ntpdate.c revision 106163
154359Sroberto/*
254359Sroberto * ntpdate - set the time of day by polling one or more NTP servers
354359Sroberto */
454359Sroberto
554359Sroberto#ifdef HAVE_CONFIG_H
654359Sroberto# include <config.h>
754359Sroberto#endif
854359Sroberto
982498Sroberto#ifdef HAVE_NETINFO
1082498Sroberto#include <netinfo/ni.h>
1154359Sroberto#endif
1282498Sroberto
13106163Sroberto#include "ntp_machine.h"
1482498Sroberto#include "ntp_fp.h"
1582498Sroberto#include "ntp.h"
1682498Sroberto#include "ntp_io.h"
1782498Sroberto#include "ntp_unixtime.h"
1882498Sroberto#include "ntpdate.h"
1982498Sroberto#include "ntp_string.h"
2082498Sroberto#include "ntp_syslog.h"
2182498Sroberto#include "ntp_select.h"
2282498Sroberto#include "ntp_stdlib.h"
2382498Sroberto
2454359Sroberto#ifdef HAVE_UNISTD_H
2554359Sroberto# include <unistd.h>
2654359Sroberto#endif
2754359Sroberto
2854359Sroberto#include <stdio.h>
2954359Sroberto#include <signal.h>
3054359Sroberto#include <ctype.h>
3154359Sroberto#ifdef HAVE_POLL_H
3282498Sroberto# include <poll.h>
3354359Sroberto#endif
3454359Sroberto#ifndef SYS_WINNT
3554359Sroberto# include <netdb.h>
36106163Sroberto# ifdef HAVE_SYS_SIGNAL_H
37106163Sroberto#  include <sys/signal.h>
38106163Sroberto# else
39106163Sroberto#  include <signal.h>
40106163Sroberto# endif
4182498Sroberto# ifdef HAVE_SYS_IOCTL_H
4282498Sroberto#  include <sys/ioctl.h>
4382498Sroberto# endif
4454359Sroberto#endif /* SYS_WINNT */
4554359Sroberto#ifdef HAVE_SYS_RESOURCE_H
4654359Sroberto# include <sys/resource.h>
4754359Sroberto#endif /* HAVE_SYS_RESOURCE_H */
4854359Sroberto
4954359Sroberto#ifdef SYS_VXWORKS
5054359Sroberto# include "ioLib.h"
5154359Sroberto# include "sockLib.h"
5254359Sroberto# include "timers.h"
5354359Sroberto
5454359Sroberto/* select wants a zero structure ... */
5554359Srobertostruct timeval timeout = {0,0};
5654359Sroberto#else
5754359Srobertostruct timeval timeout = {60,0};
5854359Sroberto#endif
5954359Sroberto
6054359Sroberto#include "recvbuff.h"
6154359Sroberto
6254359Sroberto#ifdef SYS_WINNT
6354359Sroberto# define TARGET_RESOLUTION 1  /* Try for 1-millisecond accuracy
6454359Sroberto				on Windows NT timers. */
6554359Sroberto#pragma comment(lib, "winmm")
6654359Sroberto#endif /* SYS_WINNT */
6754359Sroberto
6854359Sroberto/*
6954359Sroberto * Scheduling priority we run at
7054359Sroberto */
7154359Sroberto#ifndef SYS_VXWORKS
7254359Sroberto# define	NTPDATE_PRIO	(-12)
7354359Sroberto#else
7454359Sroberto# define	NTPDATE_PRIO	(100)
7554359Sroberto#endif
7654359Sroberto
7754359Sroberto#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
7854359Sroberto/* POSIX TIMERS - vxWorks doesn't have itimer - casey */
7954359Srobertostatic timer_t ntpdate_timerid;
8054359Sroberto#endif
8154359Sroberto
8254359Sroberto/*
8354359Sroberto * Compatibility stuff for Version 2
8454359Sroberto */
8554359Sroberto#define NTP_MAXSKW	0x28f	/* 0.01 sec in fp format */
8654359Sroberto#define NTP_MINDIST 0x51f	/* 0.02 sec in fp format */
8754359Sroberto#define PEER_MAXDISP	(64*FP_SECOND)	/* maximum dispersion (fp 64) */
8854359Sroberto#define NTP_INFIN	15	/* max stratum, infinity a la Bellman-Ford */
8954359Sroberto#define NTP_MAXWGT	(8*FP_SECOND)	/* maximum select weight 8 seconds */
9054359Sroberto#define NTP_MAXLIST 5	/* maximum select list size */
9154359Sroberto#define PEER_SHIFT	8	/* 8 suitable for crystal time base */
9254359Sroberto
9354359Sroberto/*
9454359Sroberto * Debugging flag
9554359Sroberto */
9654359Srobertovolatile int debug = 0;
9754359Sroberto
9854359Sroberto/*
9954359Sroberto * File descriptor masks etc. for call to select
10054359Sroberto */
10154359Srobertoint fd;
10254359Sroberto#ifdef HAVE_POLL_H
10354359Srobertostruct pollfd fdmask;
10454359Sroberto#else
10554359Srobertofd_set fdmask;
10654359Sroberto#endif
10754359Sroberto
10854359Sroberto/*
10954359Sroberto * Initializing flag.  All async routines watch this and only do their
11054359Sroberto * thing when it is clear.
11154359Sroberto */
11254359Srobertoint initializing = 1;
11354359Sroberto
11454359Sroberto/*
11554359Sroberto * Alarm flag.	Set when an alarm occurs
11654359Sroberto */
11754359Srobertovolatile int alarm_flag = 0;
11854359Sroberto
11954359Sroberto/*
12054359Sroberto * Simple query flag.
12154359Sroberto */
12254359Srobertoint simple_query = 0;
12354359Sroberto
12454359Sroberto/*
12554359Sroberto * Unpriviledged port flag.
12654359Sroberto */
12754359Srobertoint unpriv_port = 0;
12854359Sroberto
12954359Sroberto/*
13054359Sroberto * Time to spend measuring drift rate
13154359Sroberto */
13254359Srobertoint rate = 0;
13354359Sroberto
13454359Sroberto/*
13554359Sroberto * Program name.
13654359Sroberto */
13754359Srobertochar *progname;
13854359Sroberto
13954359Sroberto/*
14054359Sroberto * Systemwide parameters and flags
14154359Sroberto */
14254359Srobertoint sys_samples = DEFSAMPLES;	/* number of samples/server */
14354359Srobertou_long sys_timeout = DEFTIMEOUT; /* timeout time, in TIMER_HZ units */
14456746Srobertostruct server *sys_servers;	/* the server list */
14554359Srobertoint sys_numservers = 0; 	/* number of servers to poll */
14654359Srobertoint sys_authenticate = 0;	/* true when authenticating */
14754359Srobertou_int32 sys_authkey = 0;	/* set to authentication key in use */
14854359Srobertou_long sys_authdelay = 0;	/* authentication delay */
14954359Srobertoint sys_version = NTP_VERSION;	/* version to poll with */
15054359Sroberto
15154359Sroberto/*
15254359Sroberto * The current internal time
15354359Sroberto */
15454359Srobertou_long current_time = 0;
15554359Sroberto
15654359Sroberto/*
15754359Sroberto * Counter for keeping track of completed servers
15854359Sroberto */
15954359Srobertoint complete_servers = 0;
16054359Sroberto
16154359Sroberto/*
16254359Sroberto * File of encryption keys
16354359Sroberto */
16454359Sroberto
16554359Sroberto#ifndef KEYFILE
16654359Sroberto# ifndef SYS_WINNT
16754359Sroberto#define KEYFILE 	"/etc/ntp.keys"
16854359Sroberto# else
16954359Sroberto#define KEYFILE 	"%windir%\\ntp.keys"
17054359Sroberto# endif /* SYS_WINNT */
17154359Sroberto#endif /* KEYFILE */
17254359Sroberto
17354359Sroberto#ifndef SYS_WINNT
17454359Srobertoconst char *key_file = KEYFILE;
17554359Sroberto#else
17654359Srobertochar key_file_storage[MAX_PATH+1], *key_file ;
17754359Sroberto#endif	 /* SYS_WINNT */
17854359Sroberto
17954359Sroberto/*
18054359Sroberto * Miscellaneous flags
18154359Sroberto */
18254359Srobertoint verbose = 0;
18354359Srobertoint always_step = 0;
18454359Srobertoint never_step = 0;
18554359Sroberto
18654359Srobertoint 	ntpdatemain P((int, char **));
18754359Srobertostatic	void	transmit	P((struct server *));
18854359Srobertostatic	void	receive 	P((struct recvbuf *));
18954359Srobertostatic	void	server_data P((struct server *, s_fp, l_fp *, u_fp));
19054359Srobertostatic	void	clock_filter	P((struct server *));
19154359Srobertostatic	struct server *clock_select P((void));
19254359Srobertostatic	int clock_adjust	P((void));
19354359Srobertostatic	void	addserver	P((char *));
19454359Srobertostatic	struct server *findserver P((struct sockaddr_in *));
19554359Sroberto		void	timer		P((void));
19654359Srobertostatic	void	init_alarm	P((void));
19754359Sroberto#ifndef SYS_WINNT
19854359Srobertostatic	RETSIGTYPE alarming P((int));
19954359Sroberto#endif /* SYS_WINNT */
20054359Srobertostatic	void	init_io 	P((void));
20154359Srobertostatic	void	sendpkt 	P((struct sockaddr_in *, struct pkt *, int));
20254359Srobertovoid	input_handler	P((void));
20354359Sroberto
20454359Srobertostatic	int l_adj_systime	P((l_fp *));
20554359Srobertostatic	int l_step_systime	P((l_fp *));
20654359Sroberto
20754359Srobertostatic	int getnetnum	P((const char *, u_int32 *));
20854359Srobertostatic	void	printserver P((struct server *, FILE *));
20954359Sroberto
21054359Sroberto#ifdef SYS_WINNT
21154359Srobertoint 	on = 1;
21254359SrobertoWORD	wVersionRequested;
21354359SrobertoWSADATA wsaData;
21454359SrobertoHANDLE	TimerThreadHandle = NULL;
21554359Sroberto#endif /* SYS_WINNT */
21654359Sroberto
21754359Sroberto#ifdef NO_MAIN_ALLOWED
21854359SrobertoCALL(ntpdate,"ntpdate",ntpdatemain);
21954359Sroberto
22054359Srobertovoid clear_globals()
22154359Sroberto{
22254359Sroberto  /*
22354359Sroberto   * Debugging flag
22454359Sroberto   */
22554359Sroberto  debug = 0;
22654359Sroberto
22754359Sroberto  ntp_optind = 0;
22854359Sroberto  /*
22954359Sroberto   * Initializing flag.  All async routines watch this and only do their
23054359Sroberto   * thing when it is clear.
23154359Sroberto   */
23254359Sroberto  initializing = 1;
23354359Sroberto
23454359Sroberto  /*
23554359Sroberto   * Alarm flag.  Set when an alarm occurs
23654359Sroberto   */
23754359Sroberto  alarm_flag = 0;
23854359Sroberto
23954359Sroberto  /*
24054359Sroberto   * Simple query flag.
24154359Sroberto   */
24254359Sroberto  simple_query = 0;
24354359Sroberto
24454359Sroberto  /*
24554359Sroberto   * Unpriviledged port flag.
24654359Sroberto   */
24754359Sroberto  unpriv_port = 0;
24854359Sroberto
24954359Sroberto  /*
25054359Sroberto   * Time to spend measuring drift rate
25154359Sroberto   */
25254359Sroberto  rate = 0;
25354359Sroberto  /*
25454359Sroberto   * Systemwide parameters and flags
25554359Sroberto   */
25654359Sroberto  sys_numservers = 0;	  /* number of servers to poll */
25754359Sroberto  sys_authenticate = 0;   /* true when authenticating */
25854359Sroberto  sys_authkey = 0;	   /* set to authentication key in use */
25954359Sroberto  sys_authdelay = 0;   /* authentication delay */
26054359Sroberto  sys_version = NTP_VERSION;  /* version to poll with */
26154359Sroberto
26254359Sroberto  /*
26354359Sroberto   * The current internal time
26454359Sroberto   */
26554359Sroberto  current_time = 0;
26654359Sroberto
26754359Sroberto  /*
26854359Sroberto   * Counter for keeping track of completed servers
26954359Sroberto   */
27054359Sroberto  complete_servers = 0;
27154359Sroberto  verbose = 0;
27254359Sroberto  always_step = 0;
27354359Sroberto  never_step = 0;
27454359Sroberto}
27554359Sroberto#endif
27654359Sroberto
27754359Sroberto#ifdef HAVE_NETINFO
27854359Srobertostatic ni_namelist *getnetinfoservers P((void));
27954359Sroberto#endif
28054359Sroberto
28154359Sroberto/*
28254359Sroberto * Main program.  Initialize us and loop waiting for I/O and/or
28354359Sroberto * timer expiries.
28454359Sroberto */
28554359Sroberto#ifndef NO_MAIN_ALLOWED
28654359Srobertoint
28754359Srobertomain(
28854359Sroberto	int argc,
28954359Sroberto	char *argv[]
29054359Sroberto	)
29154359Sroberto{
29254359Sroberto	return ntpdatemain (argc, argv);
29354359Sroberto}
29454359Sroberto#endif /* NO_MAIN_ALLOWED */
29554359Sroberto
29654359Srobertoint
29754359Srobertontpdatemain (
29854359Sroberto	int argc,
29954359Sroberto	char *argv[]
30054359Sroberto	)
30154359Sroberto{
30254359Sroberto	int was_alarmed;
30354359Sroberto	struct recvbuf *rbuflist;
30454359Sroberto	struct recvbuf *rbuf;
30554359Sroberto	l_fp tmp;
30654359Sroberto	int errflg;
30754359Sroberto	int c;
30854359Sroberto#ifdef HAVE_NETINFO
30954359Sroberto	ni_namelist *netinfoservers;
31054359Sroberto#endif
31154359Sroberto#ifdef SYS_WINNT
31254359Sroberto	HANDLE process_handle;
31354359Sroberto
31454359Sroberto	wVersionRequested = MAKEWORD(1,1);
31554359Sroberto	if (WSAStartup(wVersionRequested, &wsaData)) {
31654359Sroberto		msyslog(LOG_ERR, "No useable winsock.dll: %m");
31754359Sroberto		exit(1);
31854359Sroberto	}
31954359Sroberto
32054359Sroberto	key_file = key_file_storage;
32154359Sroberto
32254359Sroberto	if (!ExpandEnvironmentStrings(KEYFILE, key_file, MAX_PATH))
32354359Sroberto	{
32454359Sroberto		msyslog(LOG_ERR, "ExpandEnvironmentStrings(KEYFILE) failed: %m\n");
32554359Sroberto	}
32654359Sroberto#endif /* SYS_WINNT */
32754359Sroberto
32854359Sroberto#ifdef NO_MAIN_ALLOWED
32954359Sroberto	clear_globals();
33054359Sroberto#endif
33154359Sroberto
33254359Sroberto	errflg = 0;
33354359Sroberto	progname = argv[0];
33454359Sroberto	syslogit = 0;
33554359Sroberto
33654359Sroberto	/*
33754359Sroberto	 * Decode argument list
33854359Sroberto	 */
33954359Sroberto	while ((c = ntp_getopt(argc, argv, "a:bBde:k:o:p:qr:st:uv")) != EOF)
34054359Sroberto		switch (c)
34154359Sroberto		{
34254359Sroberto		case 'a':
34354359Sroberto			c = atoi(ntp_optarg);
34454359Sroberto			sys_authenticate = 1;
34554359Sroberto			sys_authkey = c;
34654359Sroberto			break;
34754359Sroberto		case 'b':
34854359Sroberto			always_step++;
34954359Sroberto			never_step = 0;
35054359Sroberto			break;
35154359Sroberto		case 'B':
35254359Sroberto			never_step++;
35354359Sroberto			always_step = 0;
35454359Sroberto			break;
35554359Sroberto		case 'd':
35654359Sroberto			++debug;
35754359Sroberto			break;
35854359Sroberto		case 'e':
35954359Sroberto			if (!atolfp(ntp_optarg, &tmp)
36054359Sroberto			|| tmp.l_ui != 0) {
36154359Sroberto				(void) fprintf(stderr,
36254359Sroberto					   "%s: encryption delay %s is unlikely\n",
36354359Sroberto					   progname, ntp_optarg);
36454359Sroberto				errflg++;
36554359Sroberto			} else {
36654359Sroberto				sys_authdelay = tmp.l_uf;
36754359Sroberto			}
36854359Sroberto			break;
36954359Sroberto		case 'k':
37054359Sroberto			key_file = ntp_optarg;
37154359Sroberto			break;
37254359Sroberto		case 'o':
37354359Sroberto			sys_version = atoi(ntp_optarg);
37454359Sroberto			break;
37554359Sroberto		case 'p':
37654359Sroberto			c = atoi(ntp_optarg);
37754359Sroberto			if (c <= 0 || c > NTP_SHIFT) {
37854359Sroberto				(void) fprintf(stderr,
37954359Sroberto					   "%s: number of samples (%d) is invalid\n",
38054359Sroberto					   progname, c);
38154359Sroberto				errflg++;
38254359Sroberto			} else {
38354359Sroberto				sys_samples = c;
38454359Sroberto			}
38554359Sroberto			break;
38654359Sroberto		case 'q':
38754359Sroberto			simple_query = 1;
38854359Sroberto			break;
38954359Sroberto		case 'r':
39054359Sroberto			c = atoi(ntp_optarg);
39154359Sroberto			if (c <= 0 || c > (60 * 60)) {
39254359Sroberto				(void) fprintf(stderr,
39354359Sroberto					   "%s: rate (%d) is invalid: 0 - %d\n",
39454359Sroberto					   progname, c, (60 * 60));
39554359Sroberto				errflg++;
39654359Sroberto			} else {
39754359Sroberto				rate = c;
39854359Sroberto			}
39954359Sroberto			break;
40054359Sroberto		case 's':
40154359Sroberto			syslogit = 1;
40254359Sroberto			break;
40354359Sroberto		case 't':
40454359Sroberto			if (!atolfp(ntp_optarg, &tmp)) {
40554359Sroberto				(void) fprintf(stderr,
40654359Sroberto					   "%s: timeout %s is undecodeable\n",
40754359Sroberto					   progname, ntp_optarg);
40854359Sroberto				errflg++;
40954359Sroberto			} else {
41054359Sroberto				sys_timeout = ((LFPTOFP(&tmp) * TIMER_HZ)
41154359Sroberto					   + 0x8000) >> 16;
41254359Sroberto				if (sys_timeout == 0)
41354359Sroberto				sys_timeout = 1;
41454359Sroberto			}
41554359Sroberto			break;
41654359Sroberto		case 'v':
41754359Sroberto			verbose = 1;
41854359Sroberto			break;
41954359Sroberto		case 'u':
42054359Sroberto			unpriv_port = 1;
42154359Sroberto			break;
42254359Sroberto		case '?':
42354359Sroberto			++errflg;
42454359Sroberto			break;
42554359Sroberto		default:
42654359Sroberto			break;
42754359Sroberto	    }
42854359Sroberto
42954359Sroberto	if (errflg) {
43054359Sroberto		(void) fprintf(stderr,
431106163Sroberto				   "usage: %s [-bBdqsuv] [-a key#] [-e delay] [-k file] [-p samples] [-o version#] [-r rate] [-t timeo] server ...\n",
43254359Sroberto				   progname);
43354359Sroberto		exit(2);
43454359Sroberto	}
43554359Sroberto
43654359Sroberto	if (debug || simple_query) {
43754359Sroberto#ifdef HAVE_SETVBUF
43854359Sroberto		static char buf[BUFSIZ];
43954359Sroberto		setvbuf(stdout, buf, _IOLBF, BUFSIZ);
44054359Sroberto#else
44154359Sroberto		setlinebuf(stdout);
44254359Sroberto#endif
44354359Sroberto	}
44454359Sroberto
44554359Sroberto	/*
44654359Sroberto	 * Logging.  Open the syslog if we have to
44754359Sroberto	 */
44854359Sroberto	if (syslogit) {
44954359Sroberto#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
45054359Sroberto# ifndef	LOG_DAEMON
45154359Sroberto		openlog("ntpdate", LOG_PID);
45254359Sroberto# else
45354359Sroberto
45454359Sroberto#  ifndef	LOG_NTP
45554359Sroberto#	define	LOG_NTP LOG_DAEMON
45654359Sroberto#  endif
45754359Sroberto		openlog("ntpdate", LOG_PID | LOG_NDELAY, LOG_NTP);
45854359Sroberto		if (debug)
45954359Sroberto			setlogmask(LOG_UPTO(LOG_DEBUG));
46054359Sroberto		else
46154359Sroberto			setlogmask(LOG_UPTO(LOG_INFO));
46254359Sroberto# endif /* LOG_DAEMON */
46354359Sroberto#endif	/* SYS_WINNT */
46454359Sroberto	}
46554359Sroberto
46654359Sroberto	if (debug || verbose)
46754359Sroberto		msyslog(LOG_NOTICE, "%s", Version);
46854359Sroberto
46954359Sroberto	/*
47054359Sroberto	 * Add servers we are going to be polling
47154359Sroberto	 */
47254359Sroberto#ifdef HAVE_NETINFO
47382498Sroberto	netinfoservers = getnetinfoservers();
47454359Sroberto#endif
47554359Sroberto
47654359Sroberto	for ( ; ntp_optind < argc; ntp_optind++)
47754359Sroberto		addserver(argv[ntp_optind]);
47854359Sroberto
47954359Sroberto#ifdef HAVE_NETINFO
48054359Sroberto	if (netinfoservers) {
48154359Sroberto		if ( netinfoservers->ni_namelist_len &&
48254359Sroberto		    *netinfoservers->ni_namelist_val ) {
48354359Sroberto			u_int servercount = 0;
48454359Sroberto			while (servercount < netinfoservers->ni_namelist_len) {
48554359Sroberto				if (debug) msyslog(LOG_DEBUG,
48654359Sroberto						   "Adding time server %s from NetInfo configuration.",
48754359Sroberto						   netinfoservers->ni_namelist_val[servercount]);
48854359Sroberto				addserver(netinfoservers->ni_namelist_val[servercount++]);
48954359Sroberto			}
49054359Sroberto		}
49154359Sroberto		ni_namelist_free(netinfoservers);
49254359Sroberto		free(netinfoservers);
49354359Sroberto	}
49454359Sroberto#endif
49554359Sroberto
49654359Sroberto	if (sys_numservers == 0) {
49754359Sroberto		msyslog(LOG_ERR, "no servers can be used, exiting");
49854359Sroberto		exit(1);
49954359Sroberto	}
50054359Sroberto
50154359Sroberto	/*
50254359Sroberto	 * Initialize the time of day routines and the I/O subsystem
50354359Sroberto	 */
50454359Sroberto	if (sys_authenticate) {
50554359Sroberto		init_auth();
50654359Sroberto		if (!authreadkeys(key_file)) {
50782498Sroberto			msyslog(LOG_ERR, "no key file <%s>, exiting", key_file);
50854359Sroberto			exit(1);
50954359Sroberto		}
51082498Sroberto		authtrust(sys_authkey, 1);
51154359Sroberto		if (!authistrusted(sys_authkey)) {
51254359Sroberto			char buf[10];
51354359Sroberto
51454359Sroberto			(void) sprintf(buf, "%lu", (unsigned long)sys_authkey);
51554359Sroberto			msyslog(LOG_ERR, "authentication key %s unknown", buf);
51654359Sroberto			exit(1);
51754359Sroberto		}
51854359Sroberto	}
51954359Sroberto	init_io();
52054359Sroberto	init_alarm();
52154359Sroberto
52254359Sroberto	/*
52354359Sroberto	 * Set the priority.
52454359Sroberto	 */
52554359Sroberto#ifdef SYS_VXWORKS
52654359Sroberto	taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
52754359Sroberto#endif
52854359Sroberto#if defined(HAVE_ATT_NICE)
52954359Sroberto	nice (NTPDATE_PRIO);
53054359Sroberto#endif
53154359Sroberto#if defined(HAVE_BSD_NICE)
53254359Sroberto	(void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
53354359Sroberto#endif
53454359Sroberto#ifdef SYS_WINNT
53554359Sroberto	process_handle = GetCurrentProcess();
53654359Sroberto	if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
53754359Sroberto		msyslog(LOG_ERR, "SetPriorityClass failed: %m");
53854359Sroberto	}
53954359Sroberto#endif /* SYS_WINNT */
54054359Sroberto
54154359Sroberto	initializing = 0;
54254359Sroberto
54354359Sroberto	was_alarmed = 0;
54454359Sroberto	rbuflist = (struct recvbuf *)0;
54554359Sroberto	while (complete_servers < sys_numservers) {
54654359Sroberto#ifdef HAVE_POLL_H
54754359Sroberto		struct pollfd rdfdes;
54854359Sroberto#else
54954359Sroberto		fd_set rdfdes;
55054359Sroberto#endif
55154359Sroberto		int nfound;
55254359Sroberto
55354359Sroberto		if (alarm_flag) {		/* alarmed? */
55454359Sroberto			was_alarmed = 1;
55554359Sroberto			alarm_flag = 0;
55654359Sroberto		}
55754359Sroberto		rbuflist = getrecvbufs();	/* get received buffers */
55854359Sroberto
55954359Sroberto		if (!was_alarmed && rbuflist == (struct recvbuf *)0) {
56054359Sroberto			/*
56154359Sroberto			 * Nothing to do.	 Wait for something.
56254359Sroberto			 */
56354359Sroberto			rdfdes = fdmask;
56454359Sroberto#ifdef HAVE_POLL_H
56554359Sroberto			nfound = poll(&rdfdes, 1, timeout.tv_sec * 1000);
56654359Sroberto#else
56754359Sroberto			nfound = select(fd+1, &rdfdes, (fd_set *)0,
56854359Sroberto					(fd_set *)0, &timeout);
56954359Sroberto#endif
57054359Sroberto			if (nfound > 0)
57154359Sroberto				input_handler();
57254359Sroberto			else if (
57354359Sroberto#ifndef SYS_WINNT
57454359Sroberto				nfound == -1
57554359Sroberto#else
57654359Sroberto				nfound == SOCKET_ERROR
57754359Sroberto#endif /* SYS_WINNT */
57854359Sroberto				) {
57954359Sroberto#ifndef SYS_WINNT
58054359Sroberto				if (errno != EINTR)
58154359Sroberto#endif
58254359Sroberto					msyslog(LOG_ERR,
58354359Sroberto#ifdef HAVE_POLL_H
58454359Sroberto						"poll() error: %m"
58554359Sroberto#else
58654359Sroberto						"select() error: %m"
58754359Sroberto#endif
58854359Sroberto						);
58954359Sroberto			} else {
59054359Sroberto#ifndef SYS_VXWORKS
59154359Sroberto				msyslog(LOG_DEBUG,
59254359Sroberto#ifdef HAVE_POLL_H
59354359Sroberto					"poll(): nfound = %d, error: %m",
59454359Sroberto#else
59554359Sroberto					"select(): nfound = %d, error: %m",
59654359Sroberto#endif
59754359Sroberto					nfound);
59854359Sroberto#endif
59954359Sroberto			}
60054359Sroberto			if (alarm_flag) {		/* alarmed? */
60154359Sroberto				was_alarmed = 1;
60254359Sroberto				alarm_flag = 0;
60354359Sroberto			}
60454359Sroberto			rbuflist = getrecvbufs();	/* get received buffers */
60554359Sroberto		}
60654359Sroberto
60754359Sroberto		/*
60854359Sroberto		 * Out here, signals are unblocked.  Call receive
60954359Sroberto		 * procedure for each incoming packet.
61054359Sroberto		 */
61154359Sroberto		while (rbuflist != (struct recvbuf *)0) {
61254359Sroberto			rbuf = rbuflist;
61354359Sroberto			rbuflist = rbuf->next;
61454359Sroberto			receive(rbuf);
61554359Sroberto			freerecvbuf(rbuf);
61654359Sroberto		}
61754359Sroberto
61854359Sroberto		/*
61954359Sroberto		 * Call timer to process any timeouts
62054359Sroberto		 */
62154359Sroberto		if (was_alarmed) {
62254359Sroberto			timer();
62354359Sroberto			was_alarmed = 0;
62454359Sroberto		}
62554359Sroberto
62654359Sroberto		/*
62754359Sroberto		 * Go around again
62854359Sroberto		 */
62954359Sroberto	}
63054359Sroberto
63154359Sroberto	/*
63254359Sroberto	 * When we get here we've completed the polling of all servers.
63354359Sroberto	 * Adjust the clock, then exit.
63454359Sroberto	 */
63554359Sroberto#ifdef SYS_WINNT
63654359Sroberto	WSACleanup();
63754359Sroberto#endif
63854359Sroberto#ifdef SYS_VXWORKS
63954359Sroberto	close (fd);
64054359Sroberto	timer_delete(ntpdate_timerid);
64154359Sroberto#endif
64254359Sroberto	return clock_adjust();
64354359Sroberto}
64454359Sroberto
64554359Sroberto
64654359Sroberto/*
64754359Sroberto * transmit - transmit a packet to the given server, or mark it completed.
64854359Sroberto *		  This is called by the timeout routine and by the receive
64954359Sroberto *		  procedure.
65054359Sroberto */
65154359Srobertostatic void
65254359Srobertotransmit(
65354359Sroberto	register struct server *server
65454359Sroberto	)
65554359Sroberto{
65654359Sroberto	struct pkt xpkt;
65754359Sroberto
65854359Sroberto	if (debug)
65954359Sroberto		printf("transmit(%s)\n", ntoa(&server->srcadr));
66054359Sroberto
66154359Sroberto	if (server->filter_nextpt < server->xmtcnt) {
66254359Sroberto		l_fp ts;
66354359Sroberto		/*
66454359Sroberto		 * Last message to this server timed out.  Shift
66554359Sroberto		 * zeros into the filter.
66654359Sroberto		 */
66754359Sroberto		L_CLR(&ts);
66854359Sroberto		server_data(server, 0, &ts, 0);
66954359Sroberto	}
67054359Sroberto
67154359Sroberto	if ((int)server->filter_nextpt >= sys_samples) {
67254359Sroberto		/*
67354359Sroberto		 * Got all the data we need.  Mark this guy
67454359Sroberto		 * completed and return.
67554359Sroberto		 */
67654359Sroberto		server->event_time = 0;
67754359Sroberto		complete_servers++;
67854359Sroberto		return;
67954359Sroberto	}
68054359Sroberto
68154359Sroberto	/*
68254359Sroberto	 * If we're here, send another message to the server.    Fill in
68354359Sroberto	 * the packet and let 'er rip.
68454359Sroberto	 */
68554359Sroberto	xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
68654359Sroberto					 sys_version, MODE_CLIENT);
68754359Sroberto	xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
68854359Sroberto	xpkt.ppoll = NTP_MINPOLL;
68954359Sroberto	xpkt.precision = NTPDATE_PRECISION;
69054359Sroberto	xpkt.rootdelay = htonl(NTPDATE_DISTANCE);
69154359Sroberto	xpkt.rootdispersion = htonl(NTPDATE_DISP);
69254359Sroberto	xpkt.refid = htonl(NTPDATE_REFID);
69354359Sroberto	L_CLR(&xpkt.reftime);
69454359Sroberto	L_CLR(&xpkt.org);
69554359Sroberto	L_CLR(&xpkt.rec);
69654359Sroberto
69754359Sroberto	/*
69854359Sroberto	 * Determine whether to authenticate or not.	If so,
69954359Sroberto	 * fill in the extended part of the packet and do it.
70054359Sroberto	 * If not, just timestamp it and send it away.
70154359Sroberto	 */
70254359Sroberto	if (sys_authenticate) {
70354359Sroberto		int len;
70454359Sroberto
70582498Sroberto		xpkt.exten[0] = htonl(sys_authkey);
70654359Sroberto		get_systime(&server->xmt);
70754359Sroberto		L_ADDUF(&server->xmt, sys_authdelay);
70854359Sroberto		HTONL_FP(&server->xmt, &xpkt.xmt);
70954359Sroberto		len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC);
71054359Sroberto		sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len));
71154359Sroberto
71254359Sroberto		if (debug > 1)
71354359Sroberto			printf("transmit auth to %s\n",
71454359Sroberto			   ntoa(&(server->srcadr)));
71554359Sroberto	} else {
71654359Sroberto		get_systime(&(server->xmt));
71754359Sroberto		HTONL_FP(&server->xmt, &xpkt.xmt);
71854359Sroberto		sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC);
71954359Sroberto
72054359Sroberto		if (debug > 1)
72154359Sroberto			printf("transmit to %s\n", ntoa(&(server->srcadr)));
72254359Sroberto	}
72354359Sroberto
72454359Sroberto	/*
72554359Sroberto	 * Update the server timeout and transmit count
72654359Sroberto	 */
72754359Sroberto	server->event_time = current_time + sys_timeout;
72854359Sroberto	server->xmtcnt++;
72954359Sroberto}
73054359Sroberto
73154359Sroberto
73254359Sroberto/*
73354359Sroberto * receive - receive and process an incoming frame
73454359Sroberto */
73554359Srobertostatic void
73654359Srobertoreceive(
73754359Sroberto	struct recvbuf *rbufp
73854359Sroberto	)
73954359Sroberto{
74054359Sroberto	register struct pkt *rpkt;
74154359Sroberto	register struct server *server;
74254359Sroberto	register s_fp di;
743106163Sroberto	l_fp t10, t23, tmp;
74454359Sroberto	l_fp org;
74554359Sroberto	l_fp rec;
74654359Sroberto	l_fp ci;
74754359Sroberto	int has_mac;
74854359Sroberto	int is_authentic;
74954359Sroberto
75054359Sroberto	if (debug)
75154359Sroberto		printf("receive(%s)\n", ntoa(&rbufp->recv_srcadr));
75254359Sroberto	/*
75354359Sroberto	 * Check to see if the packet basically looks like something
75454359Sroberto	 * intended for us.
75554359Sroberto	 */
75654359Sroberto	if (rbufp->recv_length == LEN_PKT_NOMAC)
75754359Sroberto		has_mac = 0;
75854359Sroberto	else if (rbufp->recv_length >= LEN_PKT_NOMAC)
75954359Sroberto		has_mac = 1;
76054359Sroberto	else {
76154359Sroberto		if (debug)
76254359Sroberto			printf("receive: packet length %d\n",
76354359Sroberto			   rbufp->recv_length);
76454359Sroberto		return; 		/* funny length packet */
76554359Sroberto	}
76654359Sroberto
76754359Sroberto	rpkt = &(rbufp->recv_pkt);
76854359Sroberto	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
76954359Sroberto		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
77054359Sroberto		return;
77154359Sroberto	}
77254359Sroberto
77354359Sroberto	if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
77454359Sroberto		 && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
77582498Sroberto		|| rpkt->stratum >= STRATUM_UNSPEC) {
77654359Sroberto		if (debug)
77754359Sroberto			printf("receive: mode %d stratum %d\n",
77854359Sroberto			   PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
77954359Sroberto		return;
78054359Sroberto	}
78154359Sroberto
78254359Sroberto	/*
78354359Sroberto	 * So far, so good.  See if this is from a server we know.
78454359Sroberto	 */
78554359Sroberto	server = findserver(&(rbufp->recv_srcadr));
78654359Sroberto	if (server == NULL) {
78754359Sroberto		if (debug)
78854359Sroberto			printf("receive: server not found\n");
78954359Sroberto		return;
79054359Sroberto	}
79154359Sroberto
79254359Sroberto	/*
79354359Sroberto	 * Decode the org timestamp and make sure we're getting a response
79454359Sroberto	 * to our last request.
79554359Sroberto	 */
79654359Sroberto	NTOHL_FP(&rpkt->org, &org);
79754359Sroberto	if (!L_ISEQU(&org, &server->xmt)) {
79854359Sroberto		if (debug)
79954359Sroberto			printf("receive: pkt.org and peer.xmt differ\n");
80054359Sroberto		return;
80154359Sroberto	}
80254359Sroberto
80354359Sroberto	/*
80454359Sroberto	 * Check out the authenticity if we're doing that.
80554359Sroberto	 */
80654359Sroberto	if (!sys_authenticate)
80754359Sroberto		is_authentic = 1;
80854359Sroberto	else {
80954359Sroberto		is_authentic = 0;
81054359Sroberto
81154359Sroberto		if (debug > 3)
81254359Sroberto			printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n",
81382498Sroberto			   (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey,
81454359Sroberto			   (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt,
81554359Sroberto				LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC)));
81654359Sroberto
81782498Sroberto		if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey &&
81854359Sroberto			authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC,
81954359Sroberto			(int)(rbufp->recv_length - LEN_PKT_NOMAC)))
82054359Sroberto			is_authentic = 1;
82154359Sroberto		if (debug)
82254359Sroberto			printf("receive: authentication %s\n",
82354359Sroberto			   is_authentic ? "passed" : "failed");
82454359Sroberto	}
82554359Sroberto	server->trust <<= 1;
82654359Sroberto	if (!is_authentic)
82754359Sroberto		server->trust |= 1;
82854359Sroberto
82954359Sroberto	/*
83054359Sroberto	 * Looks good.	Record info from the packet.
83154359Sroberto	 */
83254359Sroberto	server->leap = PKT_LEAP(rpkt->li_vn_mode);
83354359Sroberto	server->stratum = PKT_TO_STRATUM(rpkt->stratum);
83454359Sroberto	server->precision = rpkt->precision;
83554359Sroberto	server->rootdelay = ntohl(rpkt->rootdelay);
83654359Sroberto	server->rootdispersion = ntohl(rpkt->rootdispersion);
83754359Sroberto	server->refid = rpkt->refid;
83854359Sroberto	NTOHL_FP(&rpkt->reftime, &server->reftime);
83954359Sroberto	NTOHL_FP(&rpkt->rec, &rec);
84054359Sroberto	NTOHL_FP(&rpkt->xmt, &server->org);
84154359Sroberto
84254359Sroberto	/*
84354359Sroberto	 * Make sure the server is at least somewhat sane.	If not, try
84454359Sroberto	 * again.
84554359Sroberto	 */
84654359Sroberto	if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
84754359Sroberto		transmit(server);
84854359Sroberto		return;
84954359Sroberto	}
85054359Sroberto
85154359Sroberto	/*
85254359Sroberto	 * Calculate the round trip delay (di) and the clock offset (ci).
85354359Sroberto	 * We use the equations (reordered from those in the spec):
85454359Sroberto	 *
85554359Sroberto	 * d = (t2 - t3) - (t1 - t0)
85654359Sroberto	 * c = ((t2 - t3) + (t1 - t0)) / 2
85754359Sroberto	 */
85854359Sroberto	t10 = server->org;		/* pkt.xmt == t1 */
85954359Sroberto	L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
86054359Sroberto
86154359Sroberto	t23 = rec;			/* pkt.rec == t2 */
86254359Sroberto	L_SUB(&t23, &org);		/* pkt->org == t3 */
86354359Sroberto
86454359Sroberto	/* now have (t2 - t3) and (t0 - t1).	Calculate (ci) and (di) */
865106163Sroberto	/*
866106163Sroberto	 * Calculate (ci) = ((t1 - t0) / 2) + ((t2 - t3) / 2)
867106163Sroberto	 * For large offsets this may prevent an overflow on '+'
868106163Sroberto	 */
86954359Sroberto	ci = t10;
87054359Sroberto	L_RSHIFT(&ci);
871106163Sroberto	tmp = t23;
872106163Sroberto	L_RSHIFT(&tmp);
873106163Sroberto	L_ADD(&ci, &tmp);
87454359Sroberto
87554359Sroberto	/*
87654359Sroberto	 * Calculate di in t23 in full precision, then truncate
87754359Sroberto	 * to an s_fp.
87854359Sroberto	 */
87954359Sroberto	L_SUB(&t23, &t10);
88054359Sroberto	di = LFPTOFP(&t23);
88154359Sroberto
88254359Sroberto	if (debug > 3)
88354359Sroberto		printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5));
88454359Sroberto
88554359Sroberto	di += (FP_SECOND >> (-(int)NTPDATE_PRECISION))
88654359Sroberto		+ (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW;
88754359Sroberto
88854359Sroberto	if (di <= 0) {		/* value still too raunchy to use? */
88954359Sroberto		L_CLR(&ci);
89054359Sroberto		di = 0;
89154359Sroberto	} else {
89254359Sroberto		di = max(di, NTP_MINDIST);
89354359Sroberto	}
89454359Sroberto
89554359Sroberto	/*
89654359Sroberto	 * Shift this data in, then transmit again.
89754359Sroberto	 */
89854359Sroberto	server_data(server, (s_fp) di, &ci, 0);
89954359Sroberto	transmit(server);
90054359Sroberto}
90154359Sroberto
90254359Sroberto
90354359Sroberto/*
90454359Sroberto * server_data - add a sample to the server's filter registers
90554359Sroberto */
90654359Srobertostatic void
90754359Srobertoserver_data(
90854359Sroberto	register struct server *server,
90954359Sroberto	s_fp d,
91054359Sroberto	l_fp *c,
91154359Sroberto	u_fp e
91254359Sroberto	)
91354359Sroberto{
91454359Sroberto	register int i;
91554359Sroberto
91654359Sroberto	i = server->filter_nextpt;
91754359Sroberto	if (i < NTP_SHIFT) {
91854359Sroberto		server->filter_delay[i] = d;
91954359Sroberto		server->filter_offset[i] = *c;
92054359Sroberto		server->filter_soffset[i] = LFPTOFP(c);
92154359Sroberto		server->filter_error[i] = e;
92254359Sroberto		server->filter_nextpt = i + 1;
92354359Sroberto	}
92454359Sroberto}
92554359Sroberto
92654359Sroberto
92754359Sroberto/*
92854359Sroberto * clock_filter - determine a server's delay, dispersion and offset
92954359Sroberto */
93054359Srobertostatic void
93154359Srobertoclock_filter(
93254359Sroberto	register struct server *server
93354359Sroberto	)
93454359Sroberto{
93554359Sroberto	register int i, j;
93654359Sroberto	int ord[NTP_SHIFT];
93754359Sroberto
93854359Sroberto	/*
93954359Sroberto	 * Sort indices into increasing delay order
94054359Sroberto	 */
94154359Sroberto	for (i = 0; i < sys_samples; i++)
94254359Sroberto		ord[i] = i;
94354359Sroberto
94454359Sroberto	for (i = 0; i < (sys_samples-1); i++) {
94554359Sroberto		for (j = i+1; j < sys_samples; j++) {
94654359Sroberto			if (server->filter_delay[ord[j]] == 0)
94754359Sroberto				continue;
94854359Sroberto			if (server->filter_delay[ord[i]] == 0
94954359Sroberto				|| (server->filter_delay[ord[i]]
95054359Sroberto				> server->filter_delay[ord[j]])) {
95154359Sroberto				register int tmp;
95254359Sroberto
95354359Sroberto				tmp = ord[i];
95454359Sroberto				ord[i] = ord[j];
95554359Sroberto				ord[j] = tmp;
95654359Sroberto			}
95754359Sroberto		}
95854359Sroberto	}
95954359Sroberto
96054359Sroberto	/*
96154359Sroberto	 * Now compute the dispersion, and assign values to delay and
96254359Sroberto	 * offset.	If there are no samples in the register, delay and
96354359Sroberto	 * offset go to zero and dispersion is set to the maximum.
96454359Sroberto	 */
96554359Sroberto	if (server->filter_delay[ord[0]] == 0) {
96654359Sroberto		server->delay = 0;
96754359Sroberto		L_CLR(&server->offset);
96854359Sroberto		server->soffset = 0;
96954359Sroberto		server->dispersion = PEER_MAXDISP;
97054359Sroberto	} else {
97154359Sroberto		register s_fp d;
97254359Sroberto
97354359Sroberto		server->delay = server->filter_delay[ord[0]];
97454359Sroberto		server->offset = server->filter_offset[ord[0]];
97554359Sroberto		server->soffset = LFPTOFP(&server->offset);
97654359Sroberto		server->dispersion = 0;
97754359Sroberto		for (i = 1; i < sys_samples; i++) {
97854359Sroberto			if (server->filter_delay[ord[i]] == 0)
97954359Sroberto				d = PEER_MAXDISP;
98054359Sroberto			else {
98154359Sroberto				d = server->filter_soffset[ord[i]]
98254359Sroberto					- server->filter_soffset[ord[0]];
98354359Sroberto				if (d < 0)
98454359Sroberto					d = -d;
98554359Sroberto				if (d > PEER_MAXDISP)
98654359Sroberto					d = PEER_MAXDISP;
98754359Sroberto			}
98854359Sroberto			/*
98954359Sroberto			 * XXX This *knows* PEER_FILTER is 1/2
99054359Sroberto			 */
99154359Sroberto			server->dispersion += (u_fp)(d) >> i;
99254359Sroberto		}
99354359Sroberto	}
99454359Sroberto	/*
99554359Sroberto	 * We're done
99654359Sroberto	 */
99754359Sroberto}
99854359Sroberto
99954359Sroberto
100054359Sroberto/*
100154359Sroberto * clock_select - select the pick-of-the-litter clock from the samples
100254359Sroberto *		  we've got.
100354359Sroberto */
100454359Srobertostatic struct server *
100554359Srobertoclock_select(void)
100654359Sroberto{
100754359Sroberto	register struct server *server;
100854359Sroberto	register int i;
100954359Sroberto	register int nlist;
101054359Sroberto	register s_fp d;
101154359Sroberto	register int j;
101254359Sroberto	register int n;
101354359Sroberto	s_fp local_threshold;
101454359Sroberto	struct server *server_list[NTP_MAXCLOCK];
101554359Sroberto	u_fp server_badness[NTP_MAXCLOCK];
101654359Sroberto	struct server *sys_server;
101754359Sroberto
101854359Sroberto	/*
101954359Sroberto	 * This first chunk of code is supposed to go through all
102054359Sroberto	 * servers we know about to find the NTP_MAXLIST servers which
102154359Sroberto	 * are most likely to succeed.	We run through the list
102254359Sroberto	 * doing the sanity checks and trying to insert anyone who
102354359Sroberto	 * looks okay.	We are at all times aware that we should
102454359Sroberto	 * only keep samples from the top two strata and we only need
102554359Sroberto	 * NTP_MAXLIST of them.
102654359Sroberto	 */
102754359Sroberto	nlist = 0;	/* none yet */
102856746Sroberto	for (server = sys_servers; server != NULL; server = server->next_server) {
1029106163Sroberto		if (server->delay == 0) {
1030106163Sroberto			if (debug)
1031106163Sroberto				printf("%s: Server dropped: no data\n", ntoa(&server->srcadr));
1032106163Sroberto			continue;   /* no data */
1033106163Sroberto		}
1034106163Sroberto		if (server->stratum > NTP_INFIN) {
1035106163Sroberto			if (debug)
1036106163Sroberto				printf("%s: Server dropped: strata too high\n", ntoa(&server->srcadr));
1037106163Sroberto			continue;   /* stratum no good */
1038106163Sroberto		}
103954359Sroberto		if (server->delay > NTP_MAXWGT) {
1040106163Sroberto			if (debug)
1041106163Sroberto				printf("%s: Server dropped: server too far away\n",
1042106163Sroberto				       ntoa(&server->srcadr));
1043106163Sroberto			continue;   /* too far away */
104454359Sroberto		}
1045106163Sroberto		if (server->leap == LEAP_NOTINSYNC) {
1046106163Sroberto			if (debug)
1047106163Sroberto				printf("%s: Server dropped: Leap not in sync\n", ntoa(&server->srcadr));
1048106163Sroberto			continue;   /* he's in trouble */
1049106163Sroberto		}
105054359Sroberto		if (!L_ISHIS(&server->org, &server->reftime)) {
1051106163Sroberto			if (debug)
1052106163Sroberto				printf("%s: Server dropped: server is very broken\n",
1053106163Sroberto				       ntoa(&server->srcadr));
1054106163Sroberto			continue;   /* very broken host */
105554359Sroberto		}
105654359Sroberto		if ((server->org.l_ui - server->reftime.l_ui)
1057106163Sroberto		    >= NTP_MAXAGE) {
1058106163Sroberto			if (debug)
1059106163Sroberto				printf("%s: Server dropped: Server has gone too long without sync\n",
1060106163Sroberto				       ntoa(&server->srcadr));
106154359Sroberto			continue;	/* too long without sync */
106254359Sroberto		}
106354359Sroberto		if (server->trust != 0) {
1064106163Sroberto			if (debug)
1065106163Sroberto				printf("%s: Server dropped: Server is untrusted\n",
1066106163Sroberto				       ntoa(&server->srcadr));
106754359Sroberto			continue;
106854359Sroberto		}
106954359Sroberto
107054359Sroberto		/*
107154359Sroberto		 * This one seems sane.  Find where he belongs
107254359Sroberto		 * on the list.
107354359Sroberto		 */
107454359Sroberto		d = server->dispersion + server->dispersion;
107554359Sroberto		for (i = 0; i < nlist; i++)
107654359Sroberto			if (server->stratum <= server_list[i]->stratum)
107754359Sroberto			break;
107854359Sroberto		for ( ; i < nlist; i++) {
107954359Sroberto			if (server->stratum < server_list[i]->stratum)
108054359Sroberto				break;
108154359Sroberto			if (d < (s_fp) server_badness[i])
108254359Sroberto				break;
108354359Sroberto		}
108454359Sroberto
108554359Sroberto		/*
108654359Sroberto		 * If i points past the end of the list, this
108754359Sroberto		 * guy is a loser, else stick him in.
108854359Sroberto		 */
108954359Sroberto		if (i >= NTP_MAXLIST)
109054359Sroberto			continue;
109154359Sroberto		for (j = nlist; j > i; j--)
109254359Sroberto			if (j < NTP_MAXLIST) {
109354359Sroberto				server_list[j] = server_list[j-1];
109454359Sroberto				server_badness[j]
109554359Sroberto					= server_badness[j-1];
109654359Sroberto			}
109754359Sroberto
109854359Sroberto		server_list[i] = server;
109954359Sroberto		server_badness[i] = d;
110054359Sroberto		if (nlist < NTP_MAXLIST)
110154359Sroberto			nlist++;
110254359Sroberto	}
110354359Sroberto
110454359Sroberto	/*
110554359Sroberto	 * Got the five-or-less best.	 Cut the list where the number of
110654359Sroberto	 * strata exceeds two.
110754359Sroberto	 */
110854359Sroberto	j = 0;
110954359Sroberto	for (i = 1; i < nlist; i++)
111054359Sroberto		if (server_list[i]->stratum > server_list[i-1]->stratum)
111154359Sroberto		if (++j == 2) {
111254359Sroberto			nlist = i;
111354359Sroberto			break;
111454359Sroberto		}
111554359Sroberto
111654359Sroberto	/*
111754359Sroberto	 * Whew!  What we should have by now is 0 to 5 candidates for
111854359Sroberto	 * the job of syncing us.  If we have none, we're out of luck.
111954359Sroberto	 * If we have one, he's a winner.  If we have more, do falseticker
112054359Sroberto	 * detection.
112154359Sroberto	 */
112254359Sroberto
112354359Sroberto	if (nlist == 0)
112454359Sroberto		sys_server = 0;
112554359Sroberto	else if (nlist == 1) {
112654359Sroberto		sys_server = server_list[0];
112754359Sroberto	} else {
112854359Sroberto		/*
112954359Sroberto		 * Re-sort by stratum, bdelay estimate quality and
113054359Sroberto		 * server.delay.
113154359Sroberto		 */
113254359Sroberto		for (i = 0; i < nlist-1; i++)
113354359Sroberto			for (j = i+1; j < nlist; j++) {
113454359Sroberto				if (server_list[i]->stratum
113554359Sroberto				< server_list[j]->stratum)
113654359Sroberto				break;	/* already sorted by stratum */
113754359Sroberto				if (server_list[i]->delay
113854359Sroberto				< server_list[j]->delay)
113954359Sroberto				continue;
114054359Sroberto				server = server_list[i];
114154359Sroberto				server_list[i] = server_list[j];
114254359Sroberto				server_list[j] = server;
114354359Sroberto			}
114454359Sroberto
114554359Sroberto		/*
114654359Sroberto		 * Calculate the fixed part of the dispersion limit
114754359Sroberto		 */
114854359Sroberto		local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION))
114954359Sroberto			+ NTP_MAXSKW;
115054359Sroberto
115154359Sroberto		/*
115254359Sroberto		 * Now drop samples until we're down to one.
115354359Sroberto		 */
115454359Sroberto		while (nlist > 1) {
115554359Sroberto			for (n = 0; n < nlist; n++) {
115654359Sroberto				server_badness[n] = 0;
115754359Sroberto				for (j = 0; j < nlist; j++) {
115854359Sroberto					if (j == n) /* with self? */
115954359Sroberto						continue;
116054359Sroberto					d = server_list[j]->soffset
116154359Sroberto						- server_list[n]->soffset;
116254359Sroberto					if (d < 0)	/* absolute value */
116354359Sroberto						d = -d;
116454359Sroberto					/*
116554359Sroberto					 * XXX This code *knows* that
116654359Sroberto					 * NTP_SELECT is 3/4
116754359Sroberto					 */
116854359Sroberto					for (i = 0; i < j; i++)
116954359Sroberto						d = (d>>1) + (d>>2);
117054359Sroberto					server_badness[n] += d;
117154359Sroberto				}
117254359Sroberto			}
117354359Sroberto
117454359Sroberto			/*
117554359Sroberto			 * We now have an array of nlist badness
117654359Sroberto			 * coefficients.	Find the badest.  Find
117754359Sroberto			 * the minimum precision while we're at
117854359Sroberto			 * it.
117954359Sroberto			 */
118054359Sroberto			i = 0;
118154359Sroberto			n = server_list[0]->precision;;
118254359Sroberto			for (j = 1; j < nlist; j++) {
118354359Sroberto				if (server_badness[j] >= server_badness[i])
118454359Sroberto					i = j;
118554359Sroberto				if (n > server_list[j]->precision)
118654359Sroberto					n = server_list[j]->precision;
118754359Sroberto			}
118854359Sroberto
118954359Sroberto			/*
119054359Sroberto			 * i is the index of the server with the worst
119154359Sroberto			 * dispersion.	If his dispersion is less than
119254359Sroberto			 * the threshold, stop now, else delete him and
119354359Sroberto			 * continue around again.
119454359Sroberto			 */
119554359Sroberto			if ( (s_fp) server_badness[i] < (local_threshold
119654359Sroberto							 + (FP_SECOND >> (-n))))
119754359Sroberto				break;
119854359Sroberto			for (j = i + 1; j < nlist; j++)
119954359Sroberto				server_list[j-1] = server_list[j];
120054359Sroberto			nlist--;
120154359Sroberto		}
120254359Sroberto
120354359Sroberto		/*
120454359Sroberto		 * What remains is a list of less than 5 servers.  Take
120554359Sroberto		 * the best.
120654359Sroberto		 */
120754359Sroberto		sys_server = server_list[0];
120854359Sroberto	}
120954359Sroberto
121054359Sroberto	/*
121154359Sroberto	 * That's it.    Return our server.
121254359Sroberto	 */
121354359Sroberto	return sys_server;
121454359Sroberto}
121554359Sroberto
121654359Sroberto
121754359Sroberto/*
121854359Sroberto * clock_adjust - process what we've received, and adjust the time
121954359Sroberto *		 if we got anything decent.
122054359Sroberto */
122154359Srobertostatic int
122254359Srobertoclock_adjust(void)
122354359Sroberto{
122456746Sroberto	register struct server *sp, *server;
122554359Sroberto	s_fp absoffset;
122654359Sroberto	int dostep;
122754359Sroberto
122856746Sroberto	for (sp = sys_servers; sp != NULL; sp = sp->next_server)
122956746Sroberto		clock_filter(sp);
123054359Sroberto	server = clock_select();
123154359Sroberto
123254359Sroberto	if (debug || simple_query) {
123356746Sroberto		for (sp = sys_servers; sp != NULL; sp = sp->next_server)
123456746Sroberto			printserver(sp, stdout);
123554359Sroberto	}
123654359Sroberto
123754359Sroberto	if (server == 0) {
123854359Sroberto		msyslog(LOG_ERR,
123954359Sroberto			"no server suitable for synchronization found");
124054359Sroberto		return(1);
124154359Sroberto	}
124254359Sroberto
124354359Sroberto	if (always_step) {
124454359Sroberto		dostep = 1;
124554359Sroberto	} else if (never_step) {
124654359Sroberto		dostep = 0;
124754359Sroberto	} else {
124854359Sroberto		absoffset = server->soffset;
124954359Sroberto		if (absoffset < 0)
125054359Sroberto			absoffset = -absoffset;
125154359Sroberto		dostep = (absoffset >= NTPDATE_THRESHOLD);
125254359Sroberto	}
125354359Sroberto
125454359Sroberto	if (dostep) {
125554359Sroberto		if (simple_query || l_step_systime(&server->offset)) {
125654359Sroberto			msyslog(LOG_NOTICE, "step time server %s offset %s sec",
125754359Sroberto				ntoa(&server->srcadr),
125854359Sroberto				lfptoa(&server->offset, 6));
125954359Sroberto		}
126054359Sroberto	} else {
126154359Sroberto#if !defined SYS_WINNT && !defined SYS_CYGWIN32
126254359Sroberto		if (simple_query || l_adj_systime(&server->offset)) {
126354359Sroberto			msyslog(LOG_NOTICE, "adjust time server %s offset %s sec",
126454359Sroberto				ntoa(&server->srcadr),
126554359Sroberto				lfptoa(&server->offset, 6));
126654359Sroberto		}
126754359Sroberto#else
126854359Sroberto		/* The NT SetSystemTimeAdjustment() call achieves slewing by
126954359Sroberto		 * changing the clock frequency. This means that we cannot specify
127054359Sroberto		 * it to slew the clock by a definite amount and then stop like
127154359Sroberto		 * the Unix adjtime() routine. We can technically adjust the clock
127254359Sroberto		 * frequency, have ntpdate sleep for a while, and then wake
127354359Sroberto		 * up and reset the clock frequency, but this might cause some
127454359Sroberto		 * grief if the user attempts to run ntpd immediately after
127554359Sroberto		 * ntpdate and the socket is in use.
127654359Sroberto		 */
127754359Sroberto		printf("\nThe -b option is required by ntpdate on Windows NT platforms\n");
127854359Sroberto		exit(1);
127954359Sroberto#endif /* SYS_WINNT */
128054359Sroberto	}
128154359Sroberto	return(0);
128254359Sroberto}
128354359Sroberto
128454359Sroberto
128554359Sroberto/* XXX ELIMINATE: merge BIG slew into adj_systime in lib/systime.c */
128654359Sroberto/*
128754359Sroberto * addserver - determine a server's address and allocate a new structure
128854359Sroberto *		   for it.
128954359Sroberto */
129054359Srobertostatic void
129154359Srobertoaddserver(
129254359Sroberto	char *serv
129354359Sroberto	)
129454359Sroberto{
129554359Sroberto	register struct server *server;
129654359Sroberto	u_int32 netnum;
129754359Sroberto
129854359Sroberto	if (!getnetnum(serv, &netnum)) {
129954359Sroberto		msyslog(LOG_ERR, "can't find host %s\n", serv);
130054359Sroberto		return;
130154359Sroberto	}
130254359Sroberto
130354359Sroberto	server = (struct server *)emalloc(sizeof(struct server));
130454359Sroberto	memset((char *)server, 0, sizeof(struct server));
130554359Sroberto
130654359Sroberto	server->srcadr.sin_family = AF_INET;
130754359Sroberto	server->srcadr.sin_addr.s_addr = netnum;
130854359Sroberto	server->srcadr.sin_port = htons(NTP_PORT);
130954359Sroberto
131056746Sroberto	server->event_time = ++sys_numservers;
131156746Sroberto	if (sys_servers == NULL)
131256746Sroberto		sys_servers = server;
131356746Sroberto	else {
131456746Sroberto		struct server *sp;
131556746Sroberto
131656746Sroberto		for (sp = sys_servers; sp->next_server != NULL;
131756746Sroberto		     sp = sp->next_server) ;
131856746Sroberto		sp->next_server = server;
131956746Sroberto	}
132054359Sroberto}
132154359Sroberto
132254359Sroberto
132354359Sroberto/*
132454359Sroberto * findserver - find a server in the list given its address
132554359Sroberto */
132654359Srobertostatic struct server *
132754359Srobertofindserver(
132854359Sroberto	struct sockaddr_in *addr
132954359Sroberto	)
133054359Sroberto{
133154359Sroberto	register u_int32 netnum;
133256746Sroberto	struct server *server;
133356746Sroberto	struct server *mc_server;
133454359Sroberto
133556746Sroberto	mc_server = NULL;
133654359Sroberto	if (htons(addr->sin_port) != NTP_PORT)
133754359Sroberto		return 0;
133854359Sroberto	netnum = addr->sin_addr.s_addr;
133954359Sroberto
134056746Sroberto	for (server = sys_servers; server != NULL;
134156746Sroberto	     server = server->next_server) {
134256746Sroberto		register u_int32 servnum;
134356746Sroberto
134456746Sroberto		servnum = server->srcadr.sin_addr.s_addr;
134556746Sroberto		if (netnum == servnum)
134656746Sroberto			return server;
134756746Sroberto		if (IN_MULTICAST(ntohl(servnum)))
134856746Sroberto			mc_server = server;
134954359Sroberto	}
135056746Sroberto
135156746Sroberto	if (mc_server != NULL) {
135256746Sroberto		struct server *sp;
135356746Sroberto
135456746Sroberto		if (mc_server->event_time != 0) {
135556746Sroberto			mc_server->event_time = 0;
135656746Sroberto			complete_servers++;
135756746Sroberto		}
135856746Sroberto		server = (struct server *)emalloc(sizeof(struct server));
135956746Sroberto		memset((char *)server, 0, sizeof(struct server));
136056746Sroberto
136156746Sroberto		server->srcadr.sin_family = AF_INET;
136256746Sroberto		server->srcadr.sin_addr.s_addr = netnum;
136356746Sroberto		server->srcadr.sin_port = htons(NTP_PORT);
136456746Sroberto
136556746Sroberto		server->event_time = ++sys_numservers;
136656746Sroberto		for (sp = sys_servers; sp->next_server != NULL;
136756746Sroberto		     sp = sp->next_server) ;
136856746Sroberto		sp->next_server = server;
136956746Sroberto		transmit(server);
137056746Sroberto	}
137156746Sroberto	return NULL;
137254359Sroberto}
137354359Sroberto
137454359Sroberto
137554359Sroberto/*
137654359Sroberto * timer - process a timer interrupt
137754359Sroberto */
137854359Srobertovoid
137954359Srobertotimer(void)
138054359Sroberto{
138156746Sroberto	struct server *server;
138254359Sroberto
138354359Sroberto	/*
138454359Sroberto	 * Bump the current idea of the time
138554359Sroberto	 */
138654359Sroberto	current_time++;
138754359Sroberto
138854359Sroberto	/*
138954359Sroberto	 * Search through the server list looking for guys
139054359Sroberto	 * who's event timers have expired.  Give these to
139154359Sroberto	 * the transmit routine.
139254359Sroberto	 */
139356746Sroberto	for (server = sys_servers; server != NULL;
139456746Sroberto	     server = server->next_server) {
139556746Sroberto		if (server->event_time != 0
139656746Sroberto		    && server->event_time <= current_time)
139756746Sroberto			transmit(server);
139854359Sroberto	}
139954359Sroberto}
140054359Sroberto
140154359Sroberto
140282498Sroberto/*
140382498Sroberto * The code duplication in the following subroutine sucks, but
140482498Sroberto * we need to appease ansi2knr.
140582498Sroberto */
140682498Sroberto
140754359Sroberto#ifndef SYS_WINNT
140854359Sroberto/*
140954359Sroberto * alarming - record the occurance of an alarm interrupt
141054359Sroberto */
141154359Srobertostatic RETSIGTYPE
141254359Srobertoalarming(
141354359Sroberto	int sig
141454359Sroberto	)
141582498Sroberto{
141682498Sroberto	alarm_flag++;
141782498Sroberto}
141854359Sroberto#else
141954359Srobertovoid CALLBACK
142054359Srobertoalarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
142154359Sroberto{
142254359Sroberto	alarm_flag++;
142354359Sroberto}
142482498Sroberto#endif /* SYS_WINNT */
142554359Sroberto
142654359Sroberto
142754359Sroberto/*
142854359Sroberto * init_alarm - set up the timer interrupt
142954359Sroberto */
143054359Srobertostatic void
143154359Srobertoinit_alarm(void)
143254359Sroberto{
143354359Sroberto#ifndef SYS_WINNT
143454359Sroberto# ifndef HAVE_TIMER_SETTIME
143554359Sroberto	struct itimerval itimer;
143654359Sroberto# else
143754359Sroberto	struct itimerspec ntpdate_itimer;
143854359Sroberto# endif
143954359Sroberto#else
144054359Sroberto	TIMECAPS tc;
144154359Sroberto	UINT wTimerRes, wTimerID;
144254359Sroberto# endif /* SYS_WINNT */
144354359Sroberto#if defined SYS_CYGWIN32 || defined SYS_WINNT
144454359Sroberto	HANDLE hToken;
144554359Sroberto	TOKEN_PRIVILEGES tkp;
144654359Sroberto	DWORD dwUser = 0;
144754359Sroberto#endif /* SYS_WINNT */
144854359Sroberto
144954359Sroberto	alarm_flag = 0;
145054359Sroberto
145154359Sroberto#ifndef SYS_WINNT
145254359Sroberto# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
145354359Sroberto	alarm_flag = 0;
145454359Sroberto	/* this code was put in as setitimer() is non existant this us the
145554359Sroberto	 * POSIX "equivalents" setup - casey
145654359Sroberto	 */
145754359Sroberto	/* ntpdate_timerid is global - so we can kill timer later */
145854359Sroberto	if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
145954359Sroberto#  ifdef SYS_VXWORKS
146054359Sroberto		ERROR
146154359Sroberto#  else
146254359Sroberto		-1
146354359Sroberto#  endif
146454359Sroberto		)
146554359Sroberto	{
146654359Sroberto		fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
146754359Sroberto		return;
146854359Sroberto	}
146954359Sroberto
147054359Sroberto	/*	TIMER_HZ = (5)
147154359Sroberto	 * Set up the alarm interrupt.	The first comes 1/(2*TIMER_HZ)
147254359Sroberto	 * seconds from now and they continue on every 1/TIMER_HZ seconds.
147354359Sroberto	 */
147454359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
147554359Sroberto	ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
147654359Sroberto	ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
147754359Sroberto	ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
147854359Sroberto	timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
147954359Sroberto# else
148054359Sroberto	/*
148154359Sroberto	 * Set up the alarm interrupt.	The first comes 1/(2*TIMER_HZ)
148254359Sroberto	 * seconds from now and they continue on every 1/TIMER_HZ seconds.
148354359Sroberto	 */
148454359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
148554359Sroberto	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
148654359Sroberto	itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
148754359Sroberto	itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
148854359Sroberto	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
148954359Sroberto# endif
149054359Sroberto#if defined SYS_CYGWIN32
149154359Sroberto	/*
149254359Sroberto	 * Get previleges needed for fiddling with the clock
149354359Sroberto	 */
149454359Sroberto
149554359Sroberto	/* get the current process token handle */
149654359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
149754359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
149854359Sroberto		exit(1);
149954359Sroberto	}
150054359Sroberto	/* get the LUID for system-time privilege. */
150154359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
150254359Sroberto	tkp.PrivilegeCount = 1;  /* one privilege to set */
150354359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
150454359Sroberto	/* get set-time privilege for this process. */
150554359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
150654359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
150754359Sroberto	if (GetLastError() != ERROR_SUCCESS)
150854359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
150954359Sroberto#endif
151054359Sroberto#else	/* SYS_WINNT */
151154359Sroberto	_tzset();
151254359Sroberto
151354359Sroberto	/*
151454359Sroberto	 * Get previleges needed for fiddling with the clock
151554359Sroberto	 */
151654359Sroberto
151754359Sroberto	/* get the current process token handle */
151854359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
151954359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
152054359Sroberto		exit(1);
152154359Sroberto	}
152254359Sroberto	/* get the LUID for system-time privilege. */
152354359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
152454359Sroberto	tkp.PrivilegeCount = 1;  /* one privilege to set */
152554359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
152654359Sroberto	/* get set-time privilege for this process. */
152754359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
152854359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
152954359Sroberto	if (GetLastError() != ERROR_SUCCESS)
153054359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
153154359Sroberto
153254359Sroberto	/*
153354359Sroberto	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
153454359Sroberto	 * Under Win/NT, expiry of timer interval leads to invocation
153554359Sroberto	 * of a callback function (on a different thread) rather than
153654359Sroberto	 * generating an alarm signal
153754359Sroberto	 */
153854359Sroberto
153954359Sroberto	/* determine max and min resolution supported */
154054359Sroberto	if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
154154359Sroberto		msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
154254359Sroberto		exit(1);
154354359Sroberto	}
154454359Sroberto	wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
154554359Sroberto	/* establish the minimum timer resolution that we'll use */
154654359Sroberto	timeBeginPeriod(wTimerRes);
154754359Sroberto
154854359Sroberto	/* start the timer event */
154954359Sroberto	wTimerID = timeSetEvent(
155054359Sroberto		(UINT) (1000/TIMER_HZ),    /* Delay */
155154359Sroberto		wTimerRes,			 /* Resolution */
155254359Sroberto		(LPTIMECALLBACK) alarming, /* Callback function */
155354359Sroberto		(DWORD) dwUser, 	 /* User data */
155454359Sroberto		TIME_PERIODIC); 	 /* Event type (periodic) */
155554359Sroberto	if (wTimerID == 0) {
155654359Sroberto		msyslog(LOG_ERR, "timeSetEvent failed: %m");
155754359Sroberto		exit(1);
155854359Sroberto	}
155954359Sroberto#endif /* SYS_WINNT */
156054359Sroberto}
156154359Sroberto
156254359Sroberto
156354359Sroberto
156454359Sroberto
156554359Sroberto/*
156654359Sroberto * We do asynchronous input using the SIGIO facility.  A number of
156754359Sroberto * recvbuf buffers are preallocated for input.	In the signal
156854359Sroberto * handler we poll to see if the socket is ready and read the
156954359Sroberto * packets from it into the recvbuf's along with a time stamp and
157054359Sroberto * an indication of the source host and the interface it was received
157154359Sroberto * through.  This allows us to get as accurate receive time stamps
157254359Sroberto * as possible independent of other processing going on.
157354359Sroberto *
157454359Sroberto * We allocate a number of recvbufs equal to the number of servers
157554359Sroberto * plus 2.	This should be plenty.
157654359Sroberto */
157754359Sroberto
157854359Sroberto
157954359Sroberto/*
158054359Sroberto * init_io - initialize I/O data and open socket
158154359Sroberto */
158254359Srobertostatic void
158354359Srobertoinit_io(void)
158454359Sroberto{
158554359Sroberto	/*
158654359Sroberto	 * Init buffer free list and stat counters
158754359Sroberto	 */
158854359Sroberto	init_recvbuff(sys_numservers + 2);
158954359Sroberto	/*
159054359Sroberto	 * Open the socket
159154359Sroberto	 */
159254359Sroberto
159354359Sroberto	/* create a datagram (UDP) socket */
159454359Sroberto	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
159554359Sroberto		msyslog(LOG_ERR, "socket() failed: %m");
159654359Sroberto		exit(1);
159754359Sroberto		/*NOTREACHED*/
159854359Sroberto	}
159954359Sroberto
160054359Sroberto	/*
160154359Sroberto	 * bind the socket to the NTP port
160254359Sroberto	 */
160354359Sroberto	if (!debug && !simple_query && !unpriv_port) {
160454359Sroberto		struct sockaddr_in addr;
160554359Sroberto
160654359Sroberto		memset((char *)&addr, 0, sizeof addr);
160754359Sroberto		addr.sin_family = AF_INET;
160854359Sroberto		addr.sin_port = htons(NTP_PORT);
160954359Sroberto		addr.sin_addr.s_addr = htonl(INADDR_ANY);
161054359Sroberto		if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
161154359Sroberto#ifndef SYS_WINNT
161254359Sroberto			if (errno == EADDRINUSE)
161354359Sroberto#else
161454359Sroberto				if (WSAGetLastError() == WSAEADDRINUSE)
161554359Sroberto#endif /* SYS_WINNT */
161654359Sroberto				msyslog(LOG_ERR,
161754359Sroberto					"the NTP socket is in use, exiting");
161854359Sroberto				else
161954359Sroberto				msyslog(LOG_ERR, "bind() fails: %m");
162054359Sroberto			exit(1);
162154359Sroberto		}
162254359Sroberto	}
162354359Sroberto
162454359Sroberto#ifdef HAVE_POLL_H
162554359Sroberto	fdmask.fd = fd;
162654359Sroberto	fdmask.events = POLLIN;
162754359Sroberto#else
162854359Sroberto	FD_ZERO(&fdmask);
162954359Sroberto	FD_SET(fd, &fdmask);
163054359Sroberto#endif
163154359Sroberto
163254359Sroberto	/*
163354359Sroberto	 * set non-blocking,
163454359Sroberto	 */
163554359Sroberto#ifndef SYS_WINNT
163654359Sroberto# ifdef SYS_VXWORKS
163754359Sroberto  {
163854359Sroberto	int on = TRUE;
163954359Sroberto
164054359Sroberto	if (ioctl(fd,FIONBIO, &on) == ERROR) {
164154359Sroberto	  msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
164254359Sroberto	  exit(1);
164354359Sroberto	}
164454359Sroberto  }
164554359Sroberto# else /* not SYS_VXWORKS */
164654359Sroberto#  if defined(O_NONBLOCK)
164754359Sroberto	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
164854359Sroberto		msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
164954359Sroberto		exit(1);
165054359Sroberto		/*NOTREACHED*/
165154359Sroberto	}
165254359Sroberto#  else /* not O_NONBLOCK */
165354359Sroberto#	if defined(FNDELAY)
165454359Sroberto	if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
165554359Sroberto		msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
165654359Sroberto		exit(1);
165754359Sroberto		/*NOTREACHED*/
165854359Sroberto	}
165954359Sroberto#	else /* FNDELAY */
166054359Sroberto#	 include "Bletch: Need non blocking I/O"
166154359Sroberto#	endif /* FNDELAY */
166254359Sroberto#  endif /* not O_NONBLOCK */
166354359Sroberto# endif /* SYS_VXWORKS */
166454359Sroberto#else /* SYS_WINNT */
166554359Sroberto	if (ioctlsocket(fd, FIONBIO, (u_long *) &on) == SOCKET_ERROR) {
166654359Sroberto		msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
166754359Sroberto		exit(1);
166854359Sroberto	}
166954359Sroberto#endif /* SYS_WINNT */
167054359Sroberto}
167154359Sroberto
167254359Sroberto
167354359Sroberto/*
167454359Sroberto * sendpkt - send a packet to the specified destination
167554359Sroberto */
167654359Srobertostatic void
167754359Srobertosendpkt(
167854359Sroberto	struct sockaddr_in *dest,
167954359Sroberto	struct pkt *pkt,
168054359Sroberto	int len
168154359Sroberto	)
168254359Sroberto{
168354359Sroberto	int cc;
168454359Sroberto
168554359Sroberto#ifdef SYS_WINNT
168654359Sroberto	DWORD err;
168754359Sroberto#endif /* SYS_WINNT */
168854359Sroberto
168982498Sroberto	cc = sendto(fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest,
169054359Sroberto			sizeof(struct sockaddr_in));
169154359Sroberto#ifndef SYS_WINNT
169254359Sroberto	if (cc == -1) {
169354359Sroberto		if (errno != EWOULDBLOCK && errno != ENOBUFS)
169454359Sroberto#else
169554359Sroberto	if (cc == SOCKET_ERROR) {
169654359Sroberto		err = WSAGetLastError();
169754359Sroberto		if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
169854359Sroberto#endif /* SYS_WINNT */
169954359Sroberto			msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
170054359Sroberto	}
170154359Sroberto}
170254359Sroberto
170354359Sroberto
170454359Sroberto/*
170554359Sroberto * input_handler - receive packets asynchronously
170654359Sroberto */
170754359Srobertovoid
170854359Srobertoinput_handler(void)
170954359Sroberto{
171054359Sroberto	register int n;
171154359Sroberto	register struct recvbuf *rb;
171254359Sroberto	struct timeval tvzero;
171354359Sroberto	int fromlen;
171454359Sroberto	l_fp ts;
171554359Sroberto#ifdef HAVE_POLL_H
171654359Sroberto	struct pollfd fds;
171754359Sroberto#else
171854359Sroberto	fd_set fds;
171954359Sroberto#endif
172054359Sroberto
172154359Sroberto	/*
172254359Sroberto	 * Do a poll to see if we have data
172354359Sroberto	 */
172454359Sroberto	for (;;) {
172554359Sroberto		fds = fdmask;
172654359Sroberto		tvzero.tv_sec = tvzero.tv_usec = 0;
172754359Sroberto#ifdef HAVE_POLL_H
172854359Sroberto		n = poll(&fds, 1, tvzero.tv_sec * 1000);
172954359Sroberto#else
173054359Sroberto		n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
173154359Sroberto#endif
173254359Sroberto
173354359Sroberto		/*
173454359Sroberto		 * If nothing to do, just return.  If an error occurred,
173554359Sroberto		 * complain and return.  If we've got some, freeze a
173654359Sroberto		 * timestamp.
173754359Sroberto		 */
173854359Sroberto		if (n == 0)
173954359Sroberto			return;
174054359Sroberto		else if (n == -1) {
174154359Sroberto			if (errno != EINTR)
174254359Sroberto				msyslog(LOG_ERR,
174354359Sroberto#ifdef HAVE_POLL_H
174454359Sroberto					"poll() error: %m"
174554359Sroberto#else
174654359Sroberto					"select() error: %m"
174754359Sroberto#endif
174854359Sroberto					);
174954359Sroberto			return;
175054359Sroberto		}
175154359Sroberto		get_systime(&ts);
175254359Sroberto
175354359Sroberto		/*
175454359Sroberto		 * Get a buffer and read the frame.  If we
175554359Sroberto		 * haven't got a buffer, or this is received
175654359Sroberto		 * on the wild card socket, just dump the packet.
175754359Sroberto		 */
175854359Sroberto		if (initializing || free_recvbuffs() == 0) {
175954359Sroberto			char buf[100];
176054359Sroberto
176154359Sroberto#ifndef SYS_WINNT
176254359Sroberto			(void) read(fd, buf, sizeof buf);
176354359Sroberto#else
176454359Sroberto			/* NT's _read does not operate on nonblocking sockets
176554359Sroberto			 * either recvfrom or ReadFile() has to be used here.
176654359Sroberto			 * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
176754359Sroberto			 * just to be different use recvfrom() here
176854359Sroberto			 */
176954359Sroberto			recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
177054359Sroberto#endif /* SYS_WINNT */
177154359Sroberto			continue;
177254359Sroberto		}
177354359Sroberto
177454359Sroberto		rb = get_free_recv_buffer();
177554359Sroberto
177654359Sroberto		fromlen = sizeof(struct sockaddr_in);
177754359Sroberto		rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt,
177854359Sroberto		   sizeof(rb->recv_pkt), 0,
177954359Sroberto		   (struct sockaddr *)&rb->recv_srcadr, &fromlen);
178054359Sroberto		if (rb->recv_length == -1) {
178154359Sroberto			freerecvbuf(rb);
178254359Sroberto			continue;
178354359Sroberto		}
178454359Sroberto
178554359Sroberto		/*
178654359Sroberto		 * Got one.  Mark how and when it got here,
178754359Sroberto		 * put it on the full list.
178854359Sroberto		 */
178954359Sroberto		rb->recv_time = ts;
179054359Sroberto		add_full_recv_buffer(rb);
179154359Sroberto	}
179254359Sroberto}
179354359Sroberto
179454359Sroberto
179554359Sroberto#if !defined SYS_WINNT && !defined SYS_CYGWIN32
179654359Sroberto/*
179754359Sroberto * adj_systime - do a big long slew of the system time
179854359Sroberto */
179954359Srobertostatic int
180054359Srobertol_adj_systime(
180154359Sroberto	l_fp *ts
180254359Sroberto	)
180354359Sroberto{
180454359Sroberto	struct timeval adjtv, oadjtv;
180554359Sroberto	int isneg = 0;
180654359Sroberto	l_fp offset;
180754359Sroberto#ifndef STEP_SLEW
180854359Sroberto	l_fp overshoot;
180954359Sroberto#endif
181054359Sroberto
181154359Sroberto	/*
181254359Sroberto	 * Take the absolute value of the offset
181354359Sroberto	 */
181454359Sroberto	offset = *ts;
181554359Sroberto	if (L_ISNEG(&offset)) {
181654359Sroberto		isneg = 1;
181754359Sroberto		L_NEG(&offset);
181854359Sroberto	}
181954359Sroberto
182054359Sroberto#ifndef STEP_SLEW
182154359Sroberto	/*
182254359Sroberto	 * Calculate the overshoot.  XXX N.B. This code *knows*
182354359Sroberto	 * ADJ_OVERSHOOT is 1/2.
182454359Sroberto	 */
182554359Sroberto	overshoot = offset;
182654359Sroberto	L_RSHIFTU(&overshoot);
182754359Sroberto	if (overshoot.l_ui != 0 || (overshoot.l_uf > ADJ_MAXOVERSHOOT)) {
182854359Sroberto		overshoot.l_ui = 0;
182954359Sroberto		overshoot.l_uf = ADJ_MAXOVERSHOOT;
183054359Sroberto	}
183154359Sroberto	L_ADD(&offset, &overshoot);
183254359Sroberto#endif
183354359Sroberto	TSTOTV(&offset, &adjtv);
183454359Sroberto
183554359Sroberto	if (isneg) {
183654359Sroberto		adjtv.tv_sec = -adjtv.tv_sec;
183754359Sroberto		adjtv.tv_usec = -adjtv.tv_usec;
183854359Sroberto	}
183954359Sroberto
184054359Sroberto	if (adjtv.tv_usec != 0 && !debug) {
184154359Sroberto		if (adjtime(&adjtv, &oadjtv) < 0) {
184254359Sroberto			msyslog(LOG_ERR, "Can't adjust the time of day: %m");
184354359Sroberto			return 0;
184454359Sroberto		}
184554359Sroberto	}
184654359Sroberto	return 1;
184754359Sroberto}
184854359Sroberto#endif /* SYS_WINNT */
184954359Sroberto
185054359Sroberto
185154359Sroberto/*
185254359Sroberto * This fuction is not the same as lib/systime step_systime!!!
185354359Sroberto */
185454359Srobertostatic int
185554359Srobertol_step_systime(
185654359Sroberto	l_fp *ts
185754359Sroberto	)
185854359Sroberto{
185954359Sroberto	double dtemp;
186054359Sroberto
186154359Sroberto#ifdef SLEWALWAYS
186254359Sroberto#ifdef STEP_SLEW
186354359Sroberto	l_fp ftmp;
186454359Sroberto	int isneg;
186554359Sroberto	int n;
186654359Sroberto
186754359Sroberto	if (debug) return 1;
186854359Sroberto	/*
186954359Sroberto	 * Take the absolute value of the offset
187054359Sroberto	 */
187154359Sroberto	ftmp = *ts;
187254359Sroberto	if (L_ISNEG(&ftmp)) {
187354359Sroberto		L_NEG(&ftmp);
187454359Sroberto		isneg = 1;
187554359Sroberto	} else
187654359Sroberto		isneg = 0;
187754359Sroberto
187854359Sroberto	if (ftmp.l_ui >= 3) {		/* Step it and slew - we might win */
187956746Sroberto		LFPTOD(ts, dtemp);
188056746Sroberto		n = step_systime(dtemp);
188154359Sroberto		if (!n)
188254359Sroberto			return n;
188354359Sroberto		if (isneg)
188454359Sroberto			ts->l_ui = ~0;
188554359Sroberto		else
188654359Sroberto			ts->l_ui = ~0;
188754359Sroberto	}
188854359Sroberto	/*
188954359Sroberto	 * Just add adjustment into the current offset.  The update
189054359Sroberto	 * routine will take care of bringing the system clock into
189154359Sroberto	 * line.
189254359Sroberto	 */
189354359Sroberto#endif
189454359Sroberto	if (debug)
189554359Sroberto		return 1;
189654359Sroberto#ifdef FORCE_NTPDATE_STEP
189754359Sroberto	LFPTOD(ts, dtemp);
189854359Sroberto	return step_systime(dtemp);
189954359Sroberto#else
190054359Sroberto	l_adj_systime(ts);
190154359Sroberto	return 1;
190254359Sroberto#endif
190354359Sroberto#else /* SLEWALWAYS  */
190454359Sroberto	if (debug)
190554359Sroberto		return 1;
190654359Sroberto	LFPTOD(ts, dtemp);
190754359Sroberto	return step_systime(dtemp);
190854359Sroberto#endif	/* SLEWALWAYS */
190954359Sroberto}
191054359Sroberto
191154359Sroberto/*
191254359Sroberto * getnetnum - given a host name, return its net number
191354359Sroberto */
191454359Srobertostatic int
191554359Srobertogetnetnum(
191654359Sroberto	const char *host,
191754359Sroberto	u_int32 *num
191854359Sroberto	)
191954359Sroberto{
192054359Sroberto	struct hostent *hp;
192154359Sroberto
192254359Sroberto	if (decodenetnum(host, num)) {
192354359Sroberto		return 1;
192454359Sroberto	} else if ((hp = gethostbyname(host)) != 0) {
192554359Sroberto		memmove((char *)num, hp->h_addr, sizeof(u_int32));
192654359Sroberto		return (1);
192754359Sroberto	}
192854359Sroberto	return (0);
192954359Sroberto}
193054359Sroberto
193154359Sroberto/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
193254359Sroberto/*
193354359Sroberto * printserver - print detail information for a server
193454359Sroberto */
193554359Srobertostatic void
193654359Srobertoprintserver(
193754359Sroberto	register struct server *pp,
193854359Sroberto	FILE *fp
193954359Sroberto	)
194054359Sroberto{
194154359Sroberto	register int i;
194254359Sroberto	char junk[5];
194354359Sroberto	char *str;
194454359Sroberto
194554359Sroberto	if (!debug) {
194654359Sroberto		(void) fprintf(fp, "server %s, stratum %d, offset %s, delay %s\n",
194754359Sroberto				   ntoa(&pp->srcadr), pp->stratum,
194854359Sroberto				   lfptoa(&pp->offset, 6), fptoa((s_fp)pp->delay, 5));
194954359Sroberto		return;
195054359Sroberto	}
195154359Sroberto
195254359Sroberto	(void) fprintf(fp, "server %s, port %d\n",
195354359Sroberto			   ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port));
195454359Sroberto
195554359Sroberto	(void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
195654359Sroberto			   pp->stratum, pp->precision,
195754359Sroberto			   pp->leap & 0x2 ? '1' : '0',
195854359Sroberto			   pp->leap & 0x1 ? '1' : '0',
195954359Sroberto			   pp->trust);
196054359Sroberto
196154359Sroberto	if (pp->stratum == 1) {
196254359Sroberto		junk[4] = 0;
196354359Sroberto		memmove(junk, (char *)&pp->refid, 4);
196454359Sroberto		str = junk;
196554359Sroberto	} else {
196654359Sroberto		str = numtoa(pp->refid);
196754359Sroberto	}
196854359Sroberto	(void) fprintf(fp,
196954359Sroberto			   "refid [%s], delay %s, dispersion %s\n",
197054359Sroberto			   str, fptoa((s_fp)pp->delay, 5),
197154359Sroberto			   ufptoa(pp->dispersion, 5));
197254359Sroberto
197354359Sroberto	(void) fprintf(fp, "transmitted %d, in filter %d\n",
197454359Sroberto			   pp->xmtcnt, pp->filter_nextpt);
197554359Sroberto
197654359Sroberto	(void) fprintf(fp, "reference time:    %s\n",
197754359Sroberto			   prettydate(&pp->reftime));
197854359Sroberto	(void) fprintf(fp, "originate timestamp: %s\n",
197954359Sroberto			   prettydate(&pp->org));
198054359Sroberto	(void) fprintf(fp, "transmit timestamp:  %s\n",
198154359Sroberto			   prettydate(&pp->xmt));
198254359Sroberto
198354359Sroberto	(void) fprintf(fp, "filter delay: ");
198454359Sroberto	for (i = 0; i < NTP_SHIFT; i++) {
198554359Sroberto		(void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
198654359Sroberto		if (i == (NTP_SHIFT>>1)-1)
198754359Sroberto			(void) fprintf(fp, "\n        ");
198854359Sroberto	}
198954359Sroberto	(void) fprintf(fp, "\n");
199054359Sroberto
199154359Sroberto	(void) fprintf(fp, "filter offset:");
199254359Sroberto	for (i = 0; i < PEER_SHIFT; i++) {
199354359Sroberto		(void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
199454359Sroberto		if (i == (PEER_SHIFT>>1)-1)
199554359Sroberto			(void) fprintf(fp, "\n        ");
199654359Sroberto	}
199754359Sroberto	(void) fprintf(fp, "\n");
199854359Sroberto
199954359Sroberto	(void) fprintf(fp, "delay %s, dispersion %s\n",
200054359Sroberto			   fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
200154359Sroberto
200254359Sroberto	(void) fprintf(fp, "offset %s\n\n",
200354359Sroberto			   lfptoa(&pp->offset, 6));
200454359Sroberto}
200554359Sroberto
200654359Sroberto#if !defined(HAVE_VSPRINTF)
200754359Srobertoint
200854359Srobertovsprintf(
200954359Sroberto	char *str,
201054359Sroberto	const char *fmt,
201154359Sroberto	va_list ap
201254359Sroberto	)
201354359Sroberto{
201454359Sroberto	FILE f;
201554359Sroberto	int len;
201654359Sroberto
201754359Sroberto	f._flag = _IOWRT+_IOSTRG;
201854359Sroberto	f._ptr = str;
201954359Sroberto	f._cnt = 32767;
202054359Sroberto	len = _doprnt(fmt, ap, &f);
202154359Sroberto	*f._ptr = 0;
202254359Sroberto	return (len);
202354359Sroberto}
202454359Sroberto#endif
202554359Sroberto
202654359Sroberto#if 0
202754359Sroberto/* override function in library since SA_RESTART makes ALL syscalls restart */
202854359Sroberto#ifdef SA_RESTART
202954359Srobertovoid
203054359Srobertosignal_no_reset(
203154359Sroberto	int sig,
203254359Sroberto	void (*func)()
203354359Sroberto	)
203454359Sroberto{
203554359Sroberto	int n;
203654359Sroberto	struct sigaction vec;
203754359Sroberto
203854359Sroberto	vec.sa_handler = func;
203954359Sroberto	sigemptyset(&vec.sa_mask);
204054359Sroberto	vec.sa_flags = 0;
204154359Sroberto
204254359Sroberto	while (1)
204354359Sroberto	{
204454359Sroberto		n = sigaction(sig, &vec, NULL);
204554359Sroberto		if (n == -1 && errno == EINTR)
204654359Sroberto			continue;
204754359Sroberto		break;
204854359Sroberto	}
204954359Sroberto	if (n == -1)
205054359Sroberto	{
205154359Sroberto		perror("sigaction");
205254359Sroberto		exit(1);
205354359Sroberto	}
205454359Sroberto}
205554359Sroberto#endif
205654359Sroberto#endif
205754359Sroberto
205854359Sroberto#ifdef HAVE_NETINFO
205954359Srobertostatic ni_namelist *
206054359Srobertogetnetinfoservers(void)
206154359Sroberto{
206254359Sroberto	ni_status status;
206354359Sroberto	void *domain;
206454359Sroberto	ni_id confdir;
206554359Sroberto	ni_namelist *namelist = (ni_namelist*)malloc(sizeof(ni_namelist));
206654359Sroberto
206754359Sroberto	/* Find a time server in NetInfo */
206854359Sroberto	if ((status = ni_open(NULL, ".", &domain)) != NI_OK) return NULL;
206954359Sroberto
207054359Sroberto	while (status = ni_pathsearch(domain, &confdir, NETINFO_CONFIG_DIR) == NI_NODIR) {
207154359Sroberto		void *next_domain;
207254359Sroberto		if (ni_open(domain, "..", &next_domain) != NI_OK) break;
207354359Sroberto		ni_free(domain);
207454359Sroberto		domain = next_domain;
207554359Sroberto	}
207654359Sroberto	if (status != NI_OK) return NULL;
207754359Sroberto
207854359Sroberto	NI_INIT(namelist);
207954359Sroberto	if (ni_lookupprop(domain, &confdir, "server", namelist) != NI_OK) {
208054359Sroberto		ni_namelist_free(namelist);
208154359Sroberto		free(namelist);
208254359Sroberto		return NULL;
208354359Sroberto	}
208454359Sroberto
208554359Sroberto	return(namelist);
208654359Sroberto}
208754359Sroberto#endif
2088