Net2/usr/src/contrib/isode/others/ntp/ntpd.c

Compare this file to the similar file:
Show the results in this format:

#ifndef	lint
static char *rcsid = "$Header: /f/osi/others/ntp/RCS/ntpd.c,v 7.2 91/02/22 09:33:57 mrose Interim $";
#endif	lint

/*
 * ntp daemon - based on the 3.4 version but heavily modified for OSI
 * interworking.
 *
 * $Log:	ntpd.c,v $
 * Revision 7.2  91/02/22  09:33:57  mrose
 * Interim 6.8
 * 
 * Revision 7.1  90/12/10  23:15:49  mrose
 * isode/
 * 
 * Revision 7.0  90/12/10  17:21:38  mrose
 * *** empty log message ***
 * 
 * Revision 1.4  90/08/14  10:14:00  jpo
 * new protocol version
 * 
 * Revision 1.3  90/02/13  14:24:11  jpo
 * First beta released version
 * 
 * Revision 1.2  89/12/19  08:33:00  jpo
 * Updated for ISODE 6.0ish
 * 
 * Revision 1.1  89/06/15  20:37:00  jpo
 * Initial revision
 * 
 * 
 */


#include "ntp.h"
#include "patchlevel.h"

char	*conf = NTPINITFILE;
char 	*driftcomp_file = NTPDRIFTCOMP;
char	*osiaddress = "Internet=localhost+10123";
char	*myname = "ntpd";

int	doset = 1;
int	selfds = 0;
int	trusting = 1;
int	keepallpeers = 1;
int	logstats;
#ifdef	DEBUG
int	debug = 0;
#endif
#ifdef	SETTICKADJ
int	tickadj = 0;
int	dotickadj = 0;
#endif
#ifdef	NOSWAP
int	noswap = 0;
#endif

unsigned int	servport;
unsigned long clock_watchdog;

double WayTooBig = WAYTOOBIG;


struct list	peer_list;
struct timeval 	tv;
struct ntpdata	ntpframe;
struct sysdata	sys;

fd_set globmask, globwmask;

/* STATIC data */
static int drift_fd = -1;

static LLog _pgm_log = {
	"ntp.log", NULLCP, NULLCP,
	LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE, LLOG_FATAL, -1,
	LLOGCLS | LLOGCRT, NOTOK
};
LLog *pgm_log = &_pgm_log;

static int priority = -10;
static int ticked;


static void timeout();
static void init_ntp();
static void initialize();
static void init_kern_vars();
static void hourly();
static void do_peer ();
static int finish ();

extern void make_new_peer();
extern void transmit();
extern void process_packet();
extern void clock_update();
extern void clear();
extern void clock_filter();
extern void select_clock();
extern void advise ();
extern void adios ();
extern void init_logical_clock();
extern void create_osilisten ();
extern void iso_init ();
#if	defined(DEBUG) && defined(SIGUSR1) && defined(SIGUSR2)
static	int incdebug(), decdebug();
#endif

struct ntp_peer *find_peer ();

main(argc, argv)
int argc;
char *argv[];
{
	int	cc;
	extern char *optarg;
	register int i;

	if (myname = rindex (argv[0], '/'))
		myname++;
	if (myname == NULL || *myname == NULL)
		myname = argv[0];

	isodetailor (myname, 0);
	initialize();		/* call NTP protocol initialization first,
				   then allow others to override default
				   values */

	while ((cc = getopt(argc, argv, "a:c:dD:lstnp:")) != EOF) {
		switch (cc) {
		    case 'a':
			if (strcmp(optarg, "any") == 0)
				WayTooBig = 10e15;
			else
				WayTooBig = atof(optarg);
			break;

		    case 'd':
#ifdef	DEBUG
			debug++;
#else
			adios (NULLCP, "%s: not compiled with DEBUG", myname);
#endif
			break;

		    case 'D':
#ifdef	DEBUG
			debug = atoi(optarg);
#else
			adios (NULLCP, "%s: not compiled with DEBUG", myname);
#endif
			break;

		    case 's':
			doset = 0;
			break;

		    case 't':
#ifdef	SETTICKADJ
			dotickadj++;
#else
			adios (NULLCP, "%s: not compiled to set tickadj",
			       myname);
#endif
			break;

		    case 'n':
#ifdef	NOSWAP
			noswap = 1;
#else
			adios (NULLCP, "%s: not compiled for noswap",
			       myname);
#endif
			break;

		    case 'l':
			logstats = 1;
			break;

		    case 'c':
			conf = optarg;
			break;

		    case 'p':
			servport = htons (atoi(optarg));
			break;
		    default:
			adios (NULLCP, "ntpd: -%c: unknown option", cc);
			break;
		}
	}

	if (servport == 0) {
		struct servent *sp;

		if ((sp = getservbyname ("ntp", "udp")) == NULL)
			servport = htons (NTP_PORT);
		else	servport = sp -> s_port;
	}
		


	peer_list.head = peer_list.tail = NULL;
	peer_list.members = 0;
	srandom(getpid ());

	init_ntp(conf);
	init_kern_vars();
	init_logical_clock();

	envinit ();
	create_listeners ();
	/*
	 * Attempt to open for writing the file for storing the drift comp
	 * register.  File must already exist for snapshots to be taken.
	 */
	if ((i = open(driftcomp_file, O_WRONLY|O_CREAT, 0644)) >= 0) {
		drift_fd = i;
	}
	doit ();
}

doit ()
{
	struct timeval tvt;
	fd_set readfds, writefds;
	int	vecp;
	char *vec[4];
	struct TSAPdisconnect tds;
	struct TSAPdisconnect *td = &tds;
	register int i;
	int	newfd;

	(void) gettimeofday(&tv, (struct timezone *) 0);

	FD_ZERO(&globmask);
	FD_ZERO(&globwmask);
	for (i = 0; i < nintf; i++) {
		if ((addrs[i].flags & INTF_VALID) == 0)
			continue;
		FD_SET(addrs[i].fd, &globmask);
		if (addrs[i].if_flags & IFF_BROADCAST)
			TRACE (2, ("Addr %d: %s fd %d %s broadcast %s",
				   i, addrs[i].name, addrs[i].fd,
				   paddr (&addrs[i].addr),
				   ntoa (&addrs[i].bcast)));
		else
			TRACE (2, ("Addr %d: %s fd %d %s", i,
				   addrs[i].name, addrs[i].fd,
				   paddr (&addrs[i].addr)));
	}

	(void) signal(SIGINT, finish);
	(void) signal(SIGTERM, finish);
#if	defined(DEBUG) && defined(SIGUSR1) && defined(SIGUSR2)
	(void) signal(SIGUSR1, incdebug);
	(void) signal(SIGUSR2, decdebug);
#endif
	/*
	 * Find highest fd in use.  This might save a few microseconds in
	 * the select system call.
	 */
	for (selfds = FD_SETSIZE - 1; selfds; selfds--)
		if (FD_ISSET(selfds, &globmask))
			break;
	TRACE (2, ("Highest fd in use is %d", selfds));
	if (!selfds) abort();
	selfds++;

	/* prime the pump! */
	ticked = 1;
	(void) gettimeofday(&tv, (struct timezone *) 0);

	for (;;) {	/* go into a finite but hopefully very long loop */

		readfds = globmask;
		writefds = globwmask;
		TRACE (7, ("wait nfds %d, fds 0x%x 0x%x", selfds,
			   readfds.fds_bits[0], writefds.fds_bits[0]));

		if (ticked) {
			ticked = 0;
			tvt = tv;
		}

		(void) TNetAcceptAux (&vecp, vec, &newfd, NULLTA,
				      selfds, &readfds,
				      &writefds, NULLFD, (1<<CLOCK_ADJ), td);

		(void) gettimeofday(&tv, (struct timezone *) 0);
		if (tv.tv_sec - tvt.tv_sec >= (1 << CLOCK_ADJ))
			ticked = 1;

		if (vecp > 0)
			iso_init (vecp, vec, newfd);

		for(i = 0; i < nintf; i++) {
			if ((addrs[i].flags & INTF_SELECT) == 0)
				continue;

			if (!FD_ISSET(addrs[i].fd, &readfds) &&
			    !FD_ISSET (addrs[i].fd, &writefds))
				continue;
			TRACE (3, ("Activity on if %d fd=%d (%s)",
				   i, addrs[i].fd, addrs[i].name));
			if (addrs[i].flags & INTF_PENDING) {
				struct ntp_peer *p = find_peer (i);
				if (p)
					(void) make_osi_conn (find_peer(i),
							      osiaddress);
				continue;
			}
			if (addrs[i].flags & INTF_ACCEPTING) {
				iso_accept (&addrs[i]);
				continue;
			}
			addrs[i].uses++;
			switch (addrs[i].addr.type) {
			    case AF_INET:
				if (recv_inet (&addrs[i], &tv) == -1)
					continue;
				break;

			    case AF_OSI:
				if (recv_osi (&addrs[i], &tv) == -1)
					continue;
				break;

			    default:
				TRACE (1, ("Address family %d not supported",
						addrs[i].addr.type));
				continue;
			}
		}
		if (ticked)
			timeout((int) (tv.tv_sec - tvt.tv_sec));
	}
}

struct ntp_peer *
check_peer(dst, sock)
	struct Naddr *dst;
	int sock;
{
	register struct ntp_peer *peer = peer_list.head;

	while (peer != NULL) {
		if (addr_compare (&peer->src, dst) &&
		    ((peer->sock == sock) || (peer->sock == -1)))
			return peer;
		peer = peer->next;
	}
	return ((struct ntp_peer *) NULL);
}

#ifdef	DEBUG
void
dump_pkt(dst, pkt, peer)
	struct Naddr *dst;
	struct ntpdata *pkt;
	struct ntp_peer *peer;
{
	struct Naddr clock_host;

	printf("Packet: %s\n", paddr (dst));

	printf("Leap %d, version %d, mode %d, poll %d, precision %d stratum %d",
	       (pkt->status & LEAPMASK) >> 6, (pkt->status & VERSIONMASK) >> 3,
	       pkt->status & MODEMASK, pkt->ppoll, pkt->precision,
	       pkt->stratum);
	switch (pkt->stratum) {
	case 0:
	case 1:
		printf(" (%.4s)\n", (char *)&pkt->refid);
		break;
	default:
		clock_host.inet_ad.sin_addr.s_addr = (u_long) pkt->refid;
		clock_host.type = AF_INET;
		printf(" [%s]\n", paddr (&clock_host));
		break;
	}
	printf("Synch Dist is %04X.%04X  Synch Dispersion is %04X.%04X\n",
	       ntohs((u_short) pkt->distance.int_part),
	       ntohs((u_short) pkt->distance.fraction),
	       ntohs((u_short) pkt->dispersion.int_part),
	       ntohs((u_short) pkt->dispersion.fraction));
	printf("Reference Timestamp is %08lx.%08lx\n",
	       ntohl(pkt->reftime.int_part),
	       ntohl(pkt->reftime.fraction));
	printf("Originate Timestamp is %08lx.%08lx\n",
	       ntohl(pkt->org.int_part),
	       ntohl(pkt->org.fraction));
	printf("Receive Timestamp is   %08lx.%08lx\n",
	       ntohl(pkt->rec.int_part),
	       ntohl(pkt->rec.fraction));
	printf("Transmit Timestamp is  %08lx.%08lx\n",
	       ntohl(pkt->xmt.int_part),
	       ntohl(pkt->xmt.fraction));
	if(peer != NULL)
		printf("Input Timestamp is     %08lx.%08lx\n",
		       ntohl(peer->rec.int_part),
		       ntohl(peer->rec.fraction));
	putchar('\n');
}
#endif

void
make_new_peer(peer)
	struct ntp_peer *peer;
{
	int i;
	void	double_to_s_fixed ();

	/*
	 * initialize peer data fields 
	 */
	bzero ((char *)peer, sizeof (*peer));
	peer->src.type = peer->src.inet_ad.sin_family = AF_INET;
	peer->hmode = MODE_SYM_PAS;	/* default: symmetric passive mode */
	peer->timer = 1 << NTP_MINPOLL;
	peer->hpoll = NTP_MINPOLL;
	peer->ppoll = NTP_MAXPOLL;
	peer->vers = 2;
	peer->mode = 0;
	double_to_s_fixed(&peer->dispersion, PEER_MAXDISP);
	peer->estoffset = 0.0;
	peer->estdelay = 0.0;
	for (i = 0; i < NTP_WINDOW; i++) {
		peer->filter.offset[i] = 0.0;
		peer->filter.delay[i] = 0.0;
	}
}

/*
 *  This procedure is called to delete a peer from our list of peers.
 */
demobilize(l, peer)
	struct list *l;
	struct ntp_peer *peer;
{
	extern struct ntp_peer dummy_peer;

	if (keepallpeers) {
		peer -> flags |= PEER_FL_SNOOZE;
		return 0;
	}

	if (peer == &dummy_peer)
#ifdef	DEBUG
		abort();
#else
		return 1;
#endif

#ifdef	DEBUG
	if ((peer->next == NULL && peer->prev == NULL) ||
	    l->tail == NULL || l->head == NULL)
		abort();
#endif

	/* delete only peer in list? */
	if (l->head == l->tail) {
#ifdef	DEBUG
		if (l->head != peer) abort();
#endif
		l->head = l->tail = NULL;
		goto dropit;
	}

	/* delete first peer? */
	if (l->head == peer) {
		l->head = peer->next;
		l->head->prev = NULL;
		goto dropit;
	}

	/* delete last peer? */
	if (l->tail == peer) {
		l->tail = peer->prev;
		l->tail->next = NULL;
		goto dropit;
	}

	/* drop peer in middle */
	peer->prev->next = peer->next;
	peer->next->prev = peer->prev;

 dropit:
#ifdef	DEBUG
	/* just some sanity checking */
	if ((l->members < 0) || 
	    (l->members && l->tail == NULL) ||
	    (l->members == 0 && l->tail != NULL)) {
		advise (LLOG_EXCEPTIONS, NULLCP, "List hosed (demobilize)");
		abort();
	}
	peer->next = peer->prev = NULL;
#endif
	free((char *) peer);
	l->members--;

	return 1;
}

enqueue(l, peer)
	register struct list *l;
	struct ntp_peer *peer;
{
	l->members++;
	if (l->tail == NULL) {
		/* insertion into empty list */
		l->tail = l->head = peer;
		peer->next = peer->prev = NULL;
		return;
	}

	/* insert at end of list */
	l->tail->next = peer;
	peer->next = NULL;
	peer->prev = l->tail;
	l->tail = peer;
}


static void timeout(n)
int	n;
{
	static int periodic = 0;
	register struct ntp_peer *peer;
#ifndef	XADJTIME2
	extern void adj_host_clock();

	adj_host_clock(n);
#endif
	TRACE (7, ("timeout (%d)", n));
	/*
	 * Count down sys.hold if necessary.
	 */
	if (sys.hold) {
		if (sys.hold <= n)
			sys.hold = 0;
		else
			sys.hold -= n;
	}
	/*
	 * If interval has expired blast off an NTP to that host.
	 */
	for (peer = peer_list.head; peer != NULL; peer = peer->next) {

#ifdef	DEBUG
		if (peer->next == NULL && peer != peer_list.tail) {
			advise (LLOG_EXCEPTIONS, NULLCP, "Broken peer list");
			abort();
		}
#endif
		if (peer -> flags & PEER_FL_SNOOZE)
			continue;
		if (peer -> mode == PEERMODE_QUERY)
			continue;
		if (peer->reach != 0 || peer->hmode != MODE_SERVER) {
			peer->stopwatch += n;
			if (peer->timer <= peer->stopwatch)
				do_peer (peer);
		}
	}

	periodic += n;
	if (periodic >= 60*60) {
		periodic = 0;
		hourly();
	}

	clock_watchdog += n;
	if (clock_watchdog >= NTP_MAXAGE) {
		/* woof, woof - barking dogs bite! */
		sys.leap = ALARM;
		if (clock_watchdog < NTP_MAXAGE + n) {
			advise (LLOG_EXCEPTIONS, NULLCP, 
			       "logical clock adjust timeout (%d seconds)",
			       NTP_MAXAGE);
		}
	}

#ifdef	DEBUG
	if (debug)
		(void) fflush(stdout);
#endif
}

static void do_peer (peer)
struct ntp_peer *peer;
{
	if (peer -> flags & PEER_FL_SNOOZE)
		return;
	peer->stopwatch = 0;
	if (peer->flags & PEER_FL_CONREQ) {
		switch (peer -> flags & PEER_FL_CONNSTATE) {
		    case 0:
			peer -> timer = 1 << (MAX(MIN(peer->ppoll,
						      MIN(peer->hpoll,
							  NTP_MAXPOLL)),
						  NTP_MINPOLL));
			if (peer->backoff == 0)
				peer -> backoff = BACKOFF_COUNT;
			else {
				if (peer -> backoff == 1)
					poll_update (peer, (int)peer->hpoll +1);
				peer -> backoff --;
			}

			if (make_osi_conn (peer, osiaddress) == NOTOK)
				return;
			break;
		    case PEER_FL_CONNECTED:
			break;
		    case PEER_FL_CONINP1:
		    case PEER_FL_CONINP2:
			return;
		    default:
			advise (LLOG_EXCEPTIONS, NULLCP,
				"Bad state flags %d",
				peer -> flags & PEER_FL_CONNSTATE);
			return;
		}
	}
	transmit (peer);
}



/*
 * init_ntp() reads NTP daemon configuration information from disk file.
 */
int precision;

static void init_ntp(config)
char *config;
{
	struct Naddr addr;
	char buffer[BUFSIZ];
	FILE *fp;
	double j;
	int	argc;
#define MAXARGS	10
	char	*argv[MAXARGS];

	extern double drift_comp;

	bzero((char *) &addr, sizeof(addr));
	fp = fopen(config, "r");
	if (fp == NULL)
		adios (config, "Problem opening NTP initialization file");

	while (fgets (buffer, sizeof buffer, fp)) { /* read line and parse */
		if (buffer[0] == '#' || buffer[0] == '\n')
			continue;

		if ((argc = sstr2arg (buffer, MAXARGS, argv, " \t\n")) <= 0)
			continue;

		if (config_line (argv, argc) != OK)
			TRACE (1, ("Ignoring line %s ...", argv[0]));
	}
	/*
	 *  Read saved drift compensation register value.
	 */
	if ((fp = fopen(driftcomp_file, "r")) != NULL) {
		if (fscanf(fp, "%lf", &j) == 1 && j > -1.0 && j < 1.0) {
			drift_comp = j;
			advise (LLOG_NOTICE, NULLCP,
			       "Drift compensation value initialized to %f", j);
		} else {
			advise (LLOG_EXCEPTIONS, NULLCP,
			       "init_ntp: bad drift compensation value");
		}
		(void) fclose(fp);
	}
}

#include "cmd_srch.h"

CMD_TABLE	config_tbl[] = {
#define	TBL_MAXPEERS	1
	"maxpeers",	TBL_MAXPEERS,
#define	TBL_TRUSTING	2
	"trusting",	TBL_TRUSTING,
#define	TBL_OSILISTEN	3
	"osilisten",	TBL_OSILISTEN,
#define	TBL_LOGCLOCK	4
	"logclock",	TBL_LOGCLOCK,
#define	TBL_DRIFTFILE	5
	"driftfile",	TBL_DRIFTFILE,
#define	TBL_WAYTOOBIG	6
	"waytoobig",	TBL_WAYTOOBIG,
	"setthreshold",	TBL_WAYTOOBIG,
#define	TBL_DEBUGLEVEL	7
	"debuglevel",	TBL_DEBUGLEVEL,
#define	TBL_TICKADJ	8
	"tickadj",	TBL_TICKADJ,
#define	TBL_SETTICKADJ	9
	"settickadj",	TBL_SETTICKADJ,
#define	TBL_NOSWAP	10
	"noswap",	TBL_NOSWAP,
#define	TBL_BROADCAST	11
	"broadcast",	TBL_BROADCAST,
#define	TBL_PEER	12
	"peer",		TBL_PEER,
#define	TBL_PASSIVE	13
	"passive",	TBL_PASSIVE,
#define	TBL_SERVER	14
	"server",	TBL_SERVER,
#define	TBL_REFCLOCK	15
	"refclock",	TBL_REFCLOCK,
#define TBL_STRATUM	16
	"stratum",	TBL_STRATUM,
#define TBL_PRECISION	17
	"precision",	TBL_PRECISION,
#define TBL_LOGFILE	18
	"logfile",	TBL_LOGFILE,
#define TBL_PRIORITY	19
	"priority",	TBL_PRIORITY,
#define TBL_KEEPALLPEERS 20
	"keepallpeers", TBL_KEEPALLPEERS,
	"",	-1
};

config_line (argv, argc)
char	*argv[];
int	argc;
{
	int	result;
	struct Naddr addr;
	int	i;
	struct ntp_peer *peer;

	switch (result = cmd_srch (argv[0], config_tbl)) {
	    case TBL_PRIORITY:
		if (argc > 1)
			priority = atoi (argv[1]);
		else	return NOTOK;
		break;

	    case TBL_MAXPEERS:
		if (argc > 1)
			sys.maxpeers = atoi (argv[1]);
		else	return NOTOK;
		break;

	    case TBL_TRUSTING:
		if (argc < 2)
			return NOTOK;
		trusting = ynorint (argv[1]);
		break;

	    case TBL_OSILISTEN:
		if (argc < 2)
			return NOTOK;
		osiaddress = strdup (argv[1]);
		break;

	    case TBL_LOGCLOCK:
		if (argc < 2)
			return NOTOK;
		logstats = ynorint (argv[1]);
		break;

	    case TBL_LOGFILE:
		if (argc < 2)
			return NOTOK;
		pgm_log -> ll_file = strdup (argv[1]);
		break;

	    case TBL_DRIFTFILE:
		if (argc < 2)
			return NOTOK;
		driftcomp_file = strdup (argv[1]);
		break;

	    case TBL_WAYTOOBIG:
		if (argc < 2)
			return NOTOK;
		if (lexequ (argv[1], "any") == 0)
			WayTooBig = 10e15;
		else	WayTooBig = atof (argv[1]);
		break;

	    case TBL_DEBUGLEVEL:
		if (argc < 2)
			return NOTOK;
#ifdef DEBUG
		debug += atoi (argv[1]);
#endif
		break;

	    case TBL_STRATUM:
		advise (LLOG_NOTICE, NULLCP,
			"Obsolete command 'stratum'");
		break;

	    case TBL_PRECISION:
		if (argc < 2)
			return NOTOK;
		sys.precision = atoi (argv[1]);
		break;
		
	    case TBL_TICKADJ:
		if (argc < 2)
			return NOTOK;
#ifdef	SETTICKADJ
		tickadj = atoi (argv[1]);
#endif
		break;

	    case TBL_SETTICKADJ:
		if (argc < 2)
			return NOTOK;
#ifdef SETTICKADJ
		dotickadj = ynorint (argv[1]);
#endif
		break;

	    case TBL_NOSWAP:
#ifdef NOSWAP
		noswap = 1;
#endif
		break;

	    case TBL_BROADCAST:
		if (argc < 2)
			return NOTOK;
#ifdef BROADCAST_NTP
		for (i = 0; i < nintf; i++)
			if (strcmp(addrs[i].name, argv[1]) == 0)
				break;
		if (i == nintf) {
			advise (LLOG_EXCEPTIONS, NULLCP,
				"config: %s not a known interface", argv[1]);
			return NOTOK;
		}
		if ((addrs[i].if_flags & IFF_BROADCAST) == 0) {
			advise (LLOG_EXCEPTIONS, NULLCP,
				"config: %s doesn't support broadcast",
				argv[1]);
			return NOTOK;
		}
		if (peer = check_peer(&addrs[i].bcast, -1)) {
			advise (LLOG_EXCEPTIONS, NULLCP,
				"config file: duplicate broadcast for %s",
				argv[1]);
			return NOTOK;
		}
		peer = (struct ntp_peer *) malloc(sizeof(struct ntp_peer));
		if (peer == NULL)
			adios ("malloc", "peer");
		make_new_peer(peer);
		peer->flags = PEER_FL_BCAST;
		peer->hmode = MODE_BROADCAST;
		peer->src = addrs[i].bcast;
		peer->sock = i;
#endif				/* BROADCAST_NTP */
		break;

	    case TBL_PEER:
	    case TBL_PASSIVE:
	    case TBL_SERVER:
		if (argc < 2)
			return NOTOK;

		if (GetHostName(argv[1], &addr) == NOTOK) {
			advise (LLOG_EXCEPTIONS, NULLCP,
				"%s: unknown host", argv[1]);
			return NOTOK;
		}
		for (i=0; i<nintf; i++)
			if (addr_compare (&addrs[i].addr, &addr))
				return NOTOK;

		peer = check_peer(&addr, -1);
		if (peer != NULL) {
			advise (LLOG_NOTICE, NULLCP,
				"Duplicate peer %s in in config file",
				paddr (&addr));
			return NOTOK;
		}
		peer = (struct ntp_peer *)
			malloc(sizeof(struct ntp_peer));
		if (peer == NULL)
			adios ("failed", "malloc");

		make_new_peer(peer);
		peer->flags = PEER_FL_CONFIG;
		switch (result) {
		    case TBL_PEER: /* "peer" */
			peer->hmode = MODE_SYM_ACT;
			peer->stopwatch = random () % (1 << NTP_MINPOLL);
			peer->flags |= PEER_FL_SYNC;
			break;
		    case TBL_SERVER: /* "server" */
			peer->hmode = MODE_CLIENT;
			peer->stopwatch = random () % (1 << NTP_MINPOLL);
			peer->flags |= PEER_FL_SYNC;
			break;
		    case TBL_PASSIVE: /* "passive" */
			peer->hmode = MODE_SYM_PAS;
			peer->flags |= PEER_FL_SYNC;
			break;
		    default:
			printf("can't happen\n");
			abort();
		}
		peer->src = addr;
		if (addr.type == AF_OSI)
			peer -> flags |= PEER_FL_CONREQ;
		peer->sock = -1;
		clear(peer);
		other_peer_fields (peer, argv + 2, argc - 2);
		enqueue(&peer_list, peer);
		TRACE (2, ("Peer %s mode %d",
			   paddr(&peer->src),
			   peer->hmode));
		break;

	    case TBL_REFCLOCK:
		if (argc < 6)
			return NOTOK;
#ifdef REFCLOCK
		else {
			int stratum, prec;
			char	*ref_clock;
			char *clk_type;

			ref_clock = argv[2];
			stratum = atoi (argv[3]);
			prec = atoi (argv[4]);
			clk_type = argv[5];

			if((i = init_clock(argv[1], clk_type)) < 0) {
				/* If we could not initialize clock line */
				advise (LLOG_EXCEPTIONS, NULLCP,
					"Could not init reference source %s (type %s)",
					argv[1], clk_type);
				return NOTOK;
			}
			peer = (struct ntp_peer *)
				calloc(1, sizeof(struct ntp_peer));
			if (peer == NULL) {
				(void) close(i);
				return NOTOK;
			}
			make_new_peer(peer);
			(void) strncpy(peer->refid.rid_string,
				       ref_clock, 4);
			peer->refid.rid_string[4] = 0;
			peer->refid.rid_type = RID_STRING;
			peer->flags = PEER_FL_CONFIG|PEER_FL_REFCLOCK;
			peer->hmode = MODE_SYM_ACT;
			peer->stopwatch = random () % (1 << NTP_MINPOLL);
			peer->flags |= PEER_FL_SYNC;
			peer->sock = i;
			peer->stratum = stratum;
			peer->precision = prec;
			clear(peer);
			enqueue(&peer_list, peer);
			TRACE (2, ("Refclock %s mode %d refid %.4s stratum %d precision %d",
				   argv[1], peer->hmode,
				   peer->refid.rid_string,
				   stratum, prec));
			transmit(peer);	/* head start for REFCLOCK */
		}
#endif REFCLOCK
		break;
	    case TBL_KEEPALLPEERS:
		if (argc < 2)
			return NOTOK;
		keepallpeers = ynorint (argv[1]);
		break;

	    default:
		return NOTOK;
	}
	return OK;
}


CMD_TABLE tbl_peer_flags[] = {
#define TBLPEER_VERSION	1
	"version",	TBLPEER_VERSION,
#define TBLPEER_AUTH	2
	"auth",		TBLPEER_AUTH,
	NULLCP,		-1
	};
	
other_peer_fields (peer, argv, argc)
struct ntp_peer *peer;
char	**argv;
int	argc;
{
	while (argc > 0) {
		switch (cmd_srch (argv[0], tbl_peer_flags)) {
		    case TBLPEER_VERSION:
			peer -> vers = atoi(argv[1]);
			if (peer -> vers < 1 || peer -> vers > 2)
				adios (NULLCP, "Bad version %d",
				       peer -> vers);
			break;

		    case TBLPEER_AUTH:
			advise (LLOG_NOTICE, "auth code not done yet");
			break;
		}
		argc -= 2;
		argv += 2;
	}
}

ynorint (s)
char	*s;
{
	if (*s == 'y' || *s == 'Y')
		return 1;
	if (*s == 'n' || *s == 'N')
		return 0;
	return atoi (s);
}

/*  */
int kern_tickadj;
static int kern_hz, kern_tick;
#ifdef NeXT
#define n_name n_un.n_name
#endif

static void
init_kern_vars() {
	int kmem;
	static char	*memory = "/dev/kmem";
	static struct nlist nl[4];
	static char *knames[] = { "_tickadj", "_hz", "_tick" };
	static int *kern_vars[] = {&kern_tickadj, &kern_hz, &kern_tick};
	int i;
	kmem = open(memory, O_RDONLY);
	if (kmem < 0) {
		advise (LLOG_EXCEPTIONS, memory, "Can't open");
		return;
	}

	for (i = 0; i < 3; i++) {
#ifdef SYS5		
		(void) strcpy (nl[i].n_name, knames[i]);
#else
		nl[i].n_name = knames[i];
#endif
	}
#ifdef SYS5
	(void) nlist("/unix", nl);
#else
	(void) nlist("/vmunix", nl);
#endif

	for (i = 0; i < (sizeof(kern_vars)/sizeof(kern_vars[0])); i++) {
		long where;

		if ((where = nl[i].n_value) == 0) {
			advise (LLOG_EXCEPTIONS, NULLCP,
				"Unknown kernal var %s", nl[i].n_name);
			continue;
		}
		if (lseek(kmem, where, L_SET) == -1) {
			advise (LLOG_EXCEPTIONS, "", "lseek for %s fails",
			       nl[i].n_name);
			continue;
		}
		if (read(kmem, (char *)kern_vars[i], sizeof(int)) != sizeof(int)) {
			advise (LLOG_EXCEPTIONS, "", "read for %s fails",
			       nl[i].n_name);

			*kern_vars[i] = 0;
		}
	}
#ifdef	SETTICKADJ
	/*
	 *  If desired value of tickadj is not specified in the configuration
	 *  file, compute a "reasonable" value here, based on the assumption 
	 *  that we don't have to slew more than 2ms every 4 seconds.
	 *
	 *  TODO: the 500 needs to be parameterized.
	 */
	if (tickadj == 0 && kern_hz)
		tickadj = 500/kern_hz;

	TRACE (1, ("kernel vars: tickadj = %d, hz = %d, tick = %d",
		   kern_tickadj, kern_hz, kern_tick));
	TRACE (1, ("desired tickadj = %d, dotickadj = %d", tickadj,
		   dotickadj));

	if (dotickadj && tickadj && (tickadj != kern_tickadj)) {
		(void) close(kmem);
		if ((kmem = open(memory, O_RDWR)) >= 0) {
			if (lseek(kmem, (long)nl[0].n_value, L_SET) == -1) {
				advise (LLOG_EXCEPTIONS, memory, "lseek fails");
				(void) close(kmem);
				tickadj = 0;
			}
			if (tickadj && write(kmem, (char *)&tickadj,
					     sizeof(tickadj)) !=
			    sizeof(tickadj)) {
				advise (LLOG_EXCEPTIONS, memory, "tickadj set fails");
				tickadj = 0;
			} 
			if (tickadj && tickadj != kern_tickadj)
				advise (LLOG_NOTICE, NULLCP,
				       "System tickadj SET to %d",
				       tickadj);
		} else {
			advise (LLOG_EXCEPTIONS, memory, "Can't open");
		}
	}
#endif	/* SETTICKADJ */
	(void) close(kmem);

	/*
	 *  If we have successfully discovered `hz' from the kernel, then we
	 *  can set sys.precision, if it has not already been specified.  If
	 *  no value of `hz' is available, then use default (-6)
	 */
	if (sys.precision == 0) {
		if (kern_hz <= 64)
			sys.precision = -6;
		else if (kern_hz <= 128)
			sys.precision = -7;
		else if (kern_hz <= 256)
			sys.precision = -8;
		else if (kern_hz <= 512)
			sys.precision = -9;
		else if (kern_hz <= 1024)
			sys.precision = -10;
		else sys.precision = -11;
		advise (LLOG_NOTICE, NULLCP,
			"sys.precision set to %d from sys clock of %d HZ",
		       sys.precision, kern_hz);
	}
}


/*
 * Given host or net name or internet address in dot notation assign the
 * internet address in byte format. source is ../routed/startup.c with minor
 * changes to detect syntax errors. 
 *
 * We now try to interpret the name as in address before we go off and bother
 * the domain name servers.
 *
 * Unfortunately the library routine inet_addr() does not detect mal formed
 * addresses that have characters or byte values > 255. 
 */

GetHostName(name, addr)
	char *name;
	struct Naddr *addr;
{
	long HostAddr;
	struct hostent *hp;
	char	*cp;

	if (cp = index (name, ':')) {
		*cp ++ = '\0';
		if (strcmp (name, "INET") == 0)
			addr->type = AF_INET;
		else if (strcmp (name, "OSI") == 0)
			addr->type = AF_OSI;
		else {
			advise  (LLOG_EXCEPTIONS, NULLCP, "Unknown prefix %s", name);
			return NOTOK;
		}
		name = cp;
			
	}
	else 
		addr->type = AF_INET;

	if (addr->type == AF_INET && (HostAddr = inet_addr(name)) != -1) {
		addr->inet_ad.sin_addr.s_addr = (u_long) HostAddr;
		addr->inet_ad.sin_family = AF_INET;
		addr->inet_ad.sin_port = servport;
		return OK;
	}

	if (addr->type == AF_INET && (hp = gethostbyname(name)) != NULL) {
		if (hp->h_addrtype != AF_INET)
			return NOTOK;
		bcopy((char *) hp->h_addr, (char *) &addr->inet_ad.sin_addr,
		      hp->h_length);
		addr->inet_ad.sin_family = hp->h_addrtype;
		addr->inet_ad.sin_port = servport;
		return OK;
	}
	if (addr->type == AF_OSI) {
		struct PSAPaddr *pa;
		if ((pa = str2paddr (name)) == NULLPA)
			return NOTOK;
		addr->psap_ad = *pa;
		return OK;
	}
	return (NOTOK);
}
/* every hour, dump some useful information to the log */
static void
hourly() {
	char buf[200];
	register int p = 0;
	static double drifts[5] = { 0.0, 0.0, 0.0, 0.0, 0.0 };
	static int drift_count = 0;
	extern double drift_comp, compliance;
	extern int peer_switches, peer_sw_inhibited;

	(void) sprintf(buf, "stats: dc %f comp %f peersw %d inh %d",
		       drift_comp, compliance, peer_switches,
		       peer_sw_inhibited);

	if (sys.peer == NULL) {
		(void) strcat(buf, " UNSYNC");
#ifdef	REFCLOCK
	} else if (sys.peer->flags & PEER_FL_REFCLOCK) {
		p = strlen(buf);
		(void) sprintf(buf + p, " off %f SYNC %.4s %d",
			       sys.peer->estoffset,
			       sys.peer->refid.rid_string,
			       sys.peer->stratum);
#endif
	} else {
		p = strlen(buf);
		(void) sprintf(buf + p, " off %f SYNC %s %d",
			       sys.peer->estoffset,
			       paddr (&sys.peer->src),
			       sys.peer->stratum);
	}
	advise (LLOG_NOTICE, NULLCP, buf);
	/*
	 *  If the drift compensation snapshot file is open, then write
	 *  the current value to it.  Since there's only one block in the
	 *  file, and no one else is reading it, we'll just keep the file
	 *  open and write to it.
	 */
	if (drift_fd >= 0) {
		drifts[drift_count % 5] = drift_comp;
		/* works out to be 70 bytes */
		(void) sprintf(buf,
		     "%+12.10f %+12.10f %+12.10f %+12.10f %+12.10f %4d\n",
			       drifts[drift_count % 5],
			       drifts[(drift_count+4) % 5],
			       drifts[(drift_count+3) % 5],
			       drifts[(drift_count+2) % 5],
			       drifts[(drift_count+1) % 5],
			       drift_count + 1);

		(void) lseek(drift_fd, 0L, L_SET);
		if (write(drift_fd, buf, strlen(buf)) < 0) {
			advise (LLOG_EXCEPTIONS, "write error", "drift comp file");
		}
		drift_count++;
	}
}
/* Debugging stuff */
#if	defined(DEBUG) && defined(SIGUSR1) && defined(SIGUSR2)
int
static incdebug()
{
	if (debug == 255)
		return;
	debug++;
	advise (LLOG_DEBUG, NULLCP, "DEBUG LEVEL %d", debug);
}

static int
decdebug()
{
	if (debug == 0)
		return;
	debug--;
	advise (LLOG_DEBUG, NULLCP, "DEBUG LEVEL %d", debug);
}
#endif

static int
finish(sig)
	int sig;
{
	exit(1);
}

#ifdef	REFCLOCK
struct refclock {
	int fd;
	int (*reader)();
	struct refclock *next;
} *refclocks = NULL;

int init_clock_local(), read_clock_local();
#ifdef PSTI
int init_clock_psti(), read_clock_psti();
#endif PSTI

init_clock(name, type)
char *name, *type;
{
	struct refclock *r;
	int (*reader)();
	int cfd;

	if (strcmp(type, "local") == 0) {
		reader = read_clock_local;
		cfd = init_clock_local(name);
	}
#ifdef PSTI
	else if (strcmp(type, "psti") == 0) {
		reader = read_clock_psti;
		cfd = init_clock_psti(name);
	}
#endif PSTI
	else {
		advise (LLOG_EXCEPTIONS, NULLCP,
			"Unknown reference clock type (%s)", type);
		return(-1);
	}
	if (cfd >= 0) {
		r = (struct refclock *)malloc(sizeof(struct refclock));
		r->fd = cfd;
		r->reader = reader;
		r->next = refclocks;
		refclocks = r;
	}
	return(cfd);
}

read_clock(cfd, tvpp, otvpp)
int cfd;
struct timeval **tvpp, **otvpp;
{
	struct refclock *r;

	for (r = refclocks; r; r = r->next)
		if(r->fd == cfd)
			return((r->reader)(cfd, tvpp, otvpp));
	return(1); /* Can't happen */
}
#endif

create_listeners ()
{
	(void) create_sockets(servport);

	create_osilisten (osiaddress);
}

char	*paddr (addr)
struct Naddr *addr;
{
	static char buf[128];

	switch (addr -> type) {
	    case AF_UNSPEC:
		return "None";

	    case AF_INET:
		return ntoa (&addr -> inet_ad);
		
	    case AF_OSI:
		return paddr2str (&addr -> psap_ad, NULLNA);

	    default:
		(void) sprintf (buf, "Unknown address type %d", addr -> type);
		return buf;
	}
}

envinit ()
{
	int s;

	if (!debug) {
		if (fork())
			exit(0);

		for (s = getdtablesize(); s >= 0; s--)
			(void) close(s);
		(void) open("/", 0);
		(void) dup2(0, 1);
		(void) dup2(0, 2);
		(void) setpgrp(0, getpid());
#ifdef TIOCNOTTY
		s = open("/dev/tty", O_RDWR);
		if (s >= 0) {
			(void) ioctl(s, TIOCNOTTY, (char *) 0);
			(void) close(s);
		}
#endif
		ll_hdinit (pgm_log, myname);
	}
	else	{
		pgm_log -> ll_events = LLOG_ALL;
		ll_dbinit (pgm_log, myname);
	}

	advise (LLOG_NOTICE, NULLCP,
		"%s starting: version $Revision: 7.2 $ patchlevel %d",
		myname, PATCHLEVEL);

#ifdef SYS5
	(void) nice (priority);
#else
	(void) setpriority(PRIO_PROCESS, 0, priority);
#endif

#ifdef	NOSWAP
	if (noswap)
		if (plock(PROCLOCK) != 0)
			advise (LLOG_EXCEPTIONS, "failed", "plock()");
#endif
}

#include <varargs.h>

#ifndef	lint
void	adios (va_alist)
va_dcl
{
    va_list ap;
    extern LLog *pgm_log;

    va_start (ap);
    
    _ll_log (pgm_log, LLOG_FATAL, ap);

    va_end (ap);

    _exit (1);
}
#else
/* VARARGS2 */

void	adios (what, fmt)
char   *what,
       *fmt;
{
    adios (what, fmt);
}
#endif


#ifndef	lint
void	advise (va_alist)
va_dcl
{
    int	    code;
    extern LLog    *pgm_log;
    va_list ap;

    va_start (ap);
    
    code = va_arg (ap, int);

    _ll_log (pgm_log, code, ap);

    va_end (ap);
}
#else
/* VARARGS3 */

void	advise (code, what, fmt)
char   *what,
       *fmt;
int	code;
{
    advise (code, what, fmt);
}
#endif

addr_compare (pa1, pa2)
struct Naddr *pa1, *pa2;
{
	if (pa1 -> type != pa2 -> type)
		return 0;
	switch (pa1 -> type) {
	    case AF_INET:
		if (pa1 -> inet_ad.sin_addr.s_addr !=
		    pa2 -> inet_ad.sin_addr.s_addr)
			return 0;
		if (pa1 -> inet_ad.sin_port != pa2 -> inet_ad.sin_port)
			return 0;
		return 1;
	    case AF_OSI:
		return psapaddr_cmp (&pa1 -> psap_ad, &pa2 -> psap_ad);
	    default:
		return 0;
	}
}

psapaddr_cmp (pa1, pa2)
struct PSAPaddr *pa1, *pa2;
{
	char	*ps1, *ps2;

	if ((ps1 = _paddr2str (pa1, NULLNA, -1)) == NULLCP)
		return 0;
	if ((ps2 = _paddr2str (pa2, NULLNA, -1)) == NULLCP)
		return 0;
	if (strcmp (ps1, ps2) == 0)
		return 1;
	return 0;
}

struct ntp_peer *find_peer (n)
{
	struct ntp_peer *peer;

	for (peer = peer_list.head; peer; peer = peer->next)
		if (peer -> sock == n)
			return peer;
	TRACE (1, ("Can't find peer with sock %d", n));
	return NULL;
}

struct intf *getintf (n)
int	*n;
{
	int acount;
	struct intf *ap;

	for (acount = 0, ap = addrs; acount < nintf; ap++, acount++)
		if (ap -> flags == 0) {
			*n = acount;
			return ap;
		}
	if (nintf == 0)
		addrs = (struct intf *) malloc (sizeof *ap);
	else
		addrs = (struct intf *)realloc ((char *)addrs,
						(unsigned)(nintf+1) * sizeof *ap);
	if (addrs == NULL)
		adios ("memory", "out of");
	ap = &addrs[nintf];
	bzero ((char *)ap, sizeof *ap);

	*n = nintf++;
	return ap;
}