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
24182007Sroberto/* Don't include ISC's version of IPv6 variables and structures */
25182007Sroberto#define ISC_IPV6_H 1
26182007Sroberto#include "isc/net.h"
27182007Sroberto#include "isc/result.h"
28182007Sroberto#include "isc/sockaddr.h"
29182007Sroberto
3054359Sroberto#ifdef HAVE_UNISTD_H
3154359Sroberto# include <unistd.h>
3254359Sroberto#endif
3354359Sroberto
3454359Sroberto#include <stdio.h>
3554359Sroberto#include <signal.h>
3654359Sroberto#include <ctype.h>
3754359Sroberto#ifdef HAVE_POLL_H
3882498Sroberto# include <poll.h>
3954359Sroberto#endif
4054359Sroberto#ifndef SYS_WINNT
41106163Sroberto# ifdef HAVE_SYS_SIGNAL_H
42106163Sroberto#  include <sys/signal.h>
43106163Sroberto# else
44106163Sroberto#  include <signal.h>
45106163Sroberto# endif
4682498Sroberto# ifdef HAVE_SYS_IOCTL_H
4782498Sroberto#  include <sys/ioctl.h>
4882498Sroberto# endif
4954359Sroberto#endif /* SYS_WINNT */
5054359Sroberto#ifdef HAVE_SYS_RESOURCE_H
5154359Sroberto# include <sys/resource.h>
5254359Sroberto#endif /* HAVE_SYS_RESOURCE_H */
5354359Sroberto
54132451Sroberto#include <arpa/inet.h>
55132451Sroberto
5654359Sroberto#ifdef SYS_VXWORKS
5754359Sroberto# include "ioLib.h"
5854359Sroberto# include "sockLib.h"
5954359Sroberto# include "timers.h"
6054359Sroberto
6154359Sroberto/* select wants a zero structure ... */
6254359Srobertostruct timeval timeout = {0,0};
63182007Sroberto#elif defined(SYS_WINNT)
64182007Sroberto/*
65182007Sroberto * Windows does not abort a select select call if SIGALRM goes off
66182007Sroberto * so a 200 ms timeout is needed
67182007Sroberto */
68182007Srobertostruct timeval timeout = {0,1000000/TIMER_HZ};
6954359Sroberto#else
7054359Srobertostruct timeval timeout = {60,0};
7154359Sroberto#endif
7254359Sroberto
73132451Sroberto#ifdef HAVE_NETINFO
74132451Sroberto#include <netinfo/ni.h>
75132451Sroberto#endif
76132451Sroberto
7754359Sroberto#include "recvbuff.h"
7854359Sroberto
7954359Sroberto#ifdef SYS_WINNT
80132451Sroberto#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
81182007Sroberto#define EAFNOSUPPORT	WSAEAFNOSUPPORT
82182007Sroberto#define EPFNOSUPPORT	WSAEPFNOSUPPORT
83132451Sroberto#define TARGET_RESOLUTION 1  /* Try for 1-millisecond accuracy
8454359Sroberto				on Windows NT timers. */
8554359Sroberto#pragma comment(lib, "winmm")
86182007Srobertoisc_boolean_t ntp_port_inuse(int af, u_short port);
87182007SrobertoUINT wTimerRes;
8854359Sroberto#endif /* SYS_WINNT */
8954359Sroberto
9054359Sroberto/*
9154359Sroberto * Scheduling priority we run at
9254359Sroberto */
9354359Sroberto#ifndef SYS_VXWORKS
9454359Sroberto# define	NTPDATE_PRIO	(-12)
9554359Sroberto#else
9654359Sroberto# define	NTPDATE_PRIO	(100)
9754359Sroberto#endif
9854359Sroberto
9954359Sroberto#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
10054359Sroberto/* POSIX TIMERS - vxWorks doesn't have itimer - casey */
10154359Srobertostatic timer_t ntpdate_timerid;
10254359Sroberto#endif
10354359Sroberto
10454359Sroberto/*
10554359Sroberto * Compatibility stuff for Version 2
10654359Sroberto */
10754359Sroberto#define NTP_MAXSKW	0x28f	/* 0.01 sec in fp format */
108182007Sroberto#define NTP_MINDIST	0x51f	/* 0.02 sec in fp format */
10954359Sroberto#define PEER_MAXDISP	(64*FP_SECOND)	/* maximum dispersion (fp 64) */
11054359Sroberto#define NTP_INFIN	15	/* max stratum, infinity a la Bellman-Ford */
11154359Sroberto#define NTP_MAXWGT	(8*FP_SECOND)	/* maximum select weight 8 seconds */
112182007Sroberto#define NTP_MAXLIST	5	/* maximum select list size */
11354359Sroberto#define PEER_SHIFT	8	/* 8 suitable for crystal time base */
11454359Sroberto
11554359Sroberto/*
116182007Sroberto * for get_systime()
117182007Sroberto */
118182007Srobertos_char	sys_precision;		/* local clock precision (log2 s) */
119182007Sroberto
120182007Sroberto/*
12154359Sroberto * Debugging flag
12254359Sroberto */
12354359Srobertovolatile int debug = 0;
12454359Sroberto
12554359Sroberto/*
12654359Sroberto * File descriptor masks etc. for call to select
12754359Sroberto */
128132451Sroberto
129132451Srobertoint ai_fam_templ;
130182007Srobertoint nbsock;             /* the number of sockets used */
131182007SrobertoSOCKET fd[MAX_AF];
132132451Srobertoint fd_family[MAX_AF];	/* to remember the socket family */
13354359Sroberto#ifdef HAVE_POLL_H
134132451Srobertostruct pollfd fdmask[MAX_AF];
13554359Sroberto#else
13654359Srobertofd_set fdmask;
137182007SrobertoSOCKET maxfd;
13854359Sroberto#endif
139132451Srobertoint polltest = 0;
14054359Sroberto
14154359Sroberto/*
14254359Sroberto * Initializing flag.  All async routines watch this and only do their
14354359Sroberto * thing when it is clear.
14454359Sroberto */
14554359Srobertoint initializing = 1;
14654359Sroberto
14754359Sroberto/*
14854359Sroberto * Alarm flag.	Set when an alarm occurs
14954359Sroberto */
15054359Srobertovolatile int alarm_flag = 0;
15154359Sroberto
15254359Sroberto/*
15354359Sroberto * Simple query flag.
15454359Sroberto */
15554359Srobertoint simple_query = 0;
15654359Sroberto
15754359Sroberto/*
158182007Sroberto * Unprivileged port flag.
15954359Sroberto */
16054359Srobertoint unpriv_port = 0;
16154359Sroberto
16254359Sroberto/*
16354359Sroberto * Program name.
16454359Sroberto */
16554359Srobertochar *progname;
16654359Sroberto
16754359Sroberto/*
16854359Sroberto * Systemwide parameters and flags
16954359Sroberto */
17054359Srobertoint sys_samples = DEFSAMPLES;	/* number of samples/server */
17154359Srobertou_long sys_timeout = DEFTIMEOUT; /* timeout time, in TIMER_HZ units */
17256746Srobertostruct server *sys_servers;	/* the server list */
17354359Srobertoint sys_numservers = 0; 	/* number of servers to poll */
17454359Srobertoint sys_authenticate = 0;	/* true when authenticating */
17554359Srobertou_int32 sys_authkey = 0;	/* set to authentication key in use */
17654359Srobertou_long sys_authdelay = 0;	/* authentication delay */
17754359Srobertoint sys_version = NTP_VERSION;	/* version to poll with */
17854359Sroberto
17954359Sroberto/*
18054359Sroberto * The current internal time
18154359Sroberto */
18254359Srobertou_long current_time = 0;
18354359Sroberto
18454359Sroberto/*
18554359Sroberto * Counter for keeping track of completed servers
18654359Sroberto */
18754359Srobertoint complete_servers = 0;
18854359Sroberto
18954359Sroberto/*
19054359Sroberto * File of encryption keys
19154359Sroberto */
19254359Sroberto
19354359Sroberto#ifndef KEYFILE
19454359Sroberto# ifndef SYS_WINNT
19554359Sroberto#define KEYFILE 	"/etc/ntp.keys"
19654359Sroberto# else
19754359Sroberto#define KEYFILE 	"%windir%\\ntp.keys"
19854359Sroberto# endif /* SYS_WINNT */
19954359Sroberto#endif /* KEYFILE */
20054359Sroberto
20154359Sroberto#ifndef SYS_WINNT
20254359Srobertoconst char *key_file = KEYFILE;
20354359Sroberto#else
20454359Srobertochar key_file_storage[MAX_PATH+1], *key_file ;
20554359Sroberto#endif	 /* SYS_WINNT */
20654359Sroberto
20754359Sroberto/*
20854359Sroberto * Miscellaneous flags
20954359Sroberto */
21054359Srobertoint verbose = 0;
21154359Srobertoint always_step = 0;
21254359Srobertoint never_step = 0;
21354359Sroberto
214182007Srobertoint ntpdatemain P((int, char **));
215132451Sroberto
21654359Srobertostatic	void	transmit	P((struct server *));
21754359Srobertostatic	void	receive 	P((struct recvbuf *));
21854359Srobertostatic	void	server_data P((struct server *, s_fp, l_fp *, u_fp));
21954359Srobertostatic	void	clock_filter	P((struct server *));
22054359Srobertostatic	struct server *clock_select P((void));
22154359Srobertostatic	int clock_adjust	P((void));
22254359Srobertostatic	void	addserver	P((char *));
223132451Srobertostatic	struct server *findserver P((struct sockaddr_storage *));
224182007Srobertovoid	timer	P((void));
22554359Srobertostatic	void	init_alarm	P((void));
22654359Sroberto#ifndef SYS_WINNT
22754359Srobertostatic	RETSIGTYPE alarming P((int));
22854359Sroberto#endif /* SYS_WINNT */
22954359Srobertostatic	void	init_io 	P((void));
230132451Srobertostatic	void	sendpkt 	P((struct sockaddr_storage *, struct pkt *, int));
23154359Srobertovoid	input_handler	P((void));
23254359Sroberto
23354359Srobertostatic	int l_adj_systime	P((l_fp *));
23454359Srobertostatic	int l_step_systime	P((l_fp *));
23554359Sroberto
23654359Srobertostatic	void	printserver P((struct server *, FILE *));
23754359Sroberto
23854359Sroberto#ifdef SYS_WINNT
23954359Srobertoint 	on = 1;
24054359SrobertoWORD	wVersionRequested;
241182007SrobertoWSADATA	wsaData;
24254359SrobertoHANDLE	TimerThreadHandle = NULL;
24354359Sroberto#endif /* SYS_WINNT */
24454359Sroberto
24554359Sroberto#ifdef NO_MAIN_ALLOWED
24654359SrobertoCALL(ntpdate,"ntpdate",ntpdatemain);
24754359Sroberto
24854359Srobertovoid clear_globals()
24954359Sroberto{
25054359Sroberto  /*
25154359Sroberto   * Debugging flag
25254359Sroberto   */
25354359Sroberto  debug = 0;
25454359Sroberto
25554359Sroberto  ntp_optind = 0;
25654359Sroberto  /*
25754359Sroberto   * Initializing flag.  All async routines watch this and only do their
25854359Sroberto   * thing when it is clear.
25954359Sroberto   */
26054359Sroberto  initializing = 1;
26154359Sroberto
26254359Sroberto  /*
26354359Sroberto   * Alarm flag.  Set when an alarm occurs
26454359Sroberto   */
26554359Sroberto  alarm_flag = 0;
26654359Sroberto
26754359Sroberto  /*
26854359Sroberto   * Simple query flag.
26954359Sroberto   */
27054359Sroberto  simple_query = 0;
27154359Sroberto
27254359Sroberto  /*
273182007Sroberto   * Unprivileged port flag.
27454359Sroberto   */
27554359Sroberto  unpriv_port = 0;
27654359Sroberto
27754359Sroberto  /*
27854359Sroberto   * Systemwide parameters and flags
27954359Sroberto   */
28054359Sroberto  sys_numservers = 0;	  /* number of servers to poll */
28154359Sroberto  sys_authenticate = 0;   /* true when authenticating */
28254359Sroberto  sys_authkey = 0;	   /* set to authentication key in use */
28354359Sroberto  sys_authdelay = 0;   /* authentication delay */
28454359Sroberto  sys_version = NTP_VERSION;  /* version to poll with */
28554359Sroberto
28654359Sroberto  /*
28754359Sroberto   * The current internal time
28854359Sroberto   */
28954359Sroberto  current_time = 0;
29054359Sroberto
29154359Sroberto  /*
29254359Sroberto   * Counter for keeping track of completed servers
29354359Sroberto   */
29454359Sroberto  complete_servers = 0;
29554359Sroberto  verbose = 0;
29654359Sroberto  always_step = 0;
29754359Sroberto  never_step = 0;
29854359Sroberto}
29954359Sroberto#endif
30054359Sroberto
30154359Sroberto#ifdef HAVE_NETINFO
30254359Srobertostatic ni_namelist *getnetinfoservers P((void));
30354359Sroberto#endif
30454359Sroberto
30554359Sroberto/*
30654359Sroberto * Main program.  Initialize us and loop waiting for I/O and/or
30754359Sroberto * timer expiries.
30854359Sroberto */
30954359Sroberto#ifndef NO_MAIN_ALLOWED
31054359Srobertoint
31154359Srobertomain(
31254359Sroberto	int argc,
31354359Sroberto	char *argv[]
31454359Sroberto	)
31554359Sroberto{
31654359Sroberto	return ntpdatemain (argc, argv);
31754359Sroberto}
31854359Sroberto#endif /* NO_MAIN_ALLOWED */
31954359Sroberto
32054359Srobertoint
32154359Srobertontpdatemain (
32254359Sroberto	int argc,
32354359Sroberto	char *argv[]
32454359Sroberto	)
32554359Sroberto{
32654359Sroberto	int was_alarmed;
327182007Sroberto	int tot_recvbufs;
32854359Sroberto	struct recvbuf *rbuf;
32954359Sroberto	l_fp tmp;
33054359Sroberto	int errflg;
33154359Sroberto	int c;
332182007Sroberto	int nfound;
333132451Sroberto
33454359Sroberto#ifdef HAVE_NETINFO
33554359Sroberto	ni_namelist *netinfoservers;
33654359Sroberto#endif
33754359Sroberto#ifdef SYS_WINNT
33854359Sroberto	HANDLE process_handle;
33954359Sroberto
34054359Sroberto	wVersionRequested = MAKEWORD(1,1);
34154359Sroberto	if (WSAStartup(wVersionRequested, &wsaData)) {
342132451Sroberto		netsyslog(LOG_ERR, "No useable winsock.dll: %m");
34354359Sroberto		exit(1);
34454359Sroberto	}
34554359Sroberto
34654359Sroberto	key_file = key_file_storage;
34754359Sroberto
34854359Sroberto	if (!ExpandEnvironmentStrings(KEYFILE, key_file, MAX_PATH))
34954359Sroberto	{
35054359Sroberto		msyslog(LOG_ERR, "ExpandEnvironmentStrings(KEYFILE) failed: %m\n");
35154359Sroberto	}
35254359Sroberto#endif /* SYS_WINNT */
35354359Sroberto
35454359Sroberto#ifdef NO_MAIN_ALLOWED
35554359Sroberto	clear_globals();
35654359Sroberto#endif
35754359Sroberto
358182007Sroberto
359182007Sroberto	/* Check to see if we have IPv6. Otherwise force the -4 flag */
360182007Sroberto	if (isc_net_probeipv6() != ISC_R_SUCCESS) {
361182007Sroberto		ai_fam_templ = AF_INET;
362182007Sroberto	}
363182007Sroberto
36454359Sroberto	errflg = 0;
36554359Sroberto	progname = argv[0];
36654359Sroberto	syslogit = 0;
36754359Sroberto
36854359Sroberto	/*
36954359Sroberto	 * Decode argument list
37054359Sroberto	 */
371182007Sroberto	while ((c = ntp_getopt(argc, argv, "46a:bBde:k:o:p:qst:uv")) != EOF)
37254359Sroberto		switch (c)
37354359Sroberto		{
374132451Sroberto		case '4':
375132451Sroberto			ai_fam_templ = AF_INET;
376132451Sroberto			break;
377132451Sroberto		case '6':
378132451Sroberto			ai_fam_templ = AF_INET6;
379132451Sroberto			break;
38054359Sroberto		case 'a':
38154359Sroberto			c = atoi(ntp_optarg);
38254359Sroberto			sys_authenticate = 1;
38354359Sroberto			sys_authkey = c;
38454359Sroberto			break;
38554359Sroberto		case 'b':
38654359Sroberto			always_step++;
38754359Sroberto			never_step = 0;
38854359Sroberto			break;
38954359Sroberto		case 'B':
39054359Sroberto			never_step++;
39154359Sroberto			always_step = 0;
39254359Sroberto			break;
39354359Sroberto		case 'd':
39454359Sroberto			++debug;
39554359Sroberto			break;
39654359Sroberto		case 'e':
39754359Sroberto			if (!atolfp(ntp_optarg, &tmp)
39854359Sroberto			|| tmp.l_ui != 0) {
39954359Sroberto				(void) fprintf(stderr,
40054359Sroberto					   "%s: encryption delay %s is unlikely\n",
40154359Sroberto					   progname, ntp_optarg);
40254359Sroberto				errflg++;
40354359Sroberto			} else {
40454359Sroberto				sys_authdelay = tmp.l_uf;
40554359Sroberto			}
40654359Sroberto			break;
40754359Sroberto		case 'k':
40854359Sroberto			key_file = ntp_optarg;
40954359Sroberto			break;
41054359Sroberto		case 'o':
41154359Sroberto			sys_version = atoi(ntp_optarg);
41254359Sroberto			break;
41354359Sroberto		case 'p':
41454359Sroberto			c = atoi(ntp_optarg);
41554359Sroberto			if (c <= 0 || c > NTP_SHIFT) {
41654359Sroberto				(void) fprintf(stderr,
41754359Sroberto					   "%s: number of samples (%d) is invalid\n",
41854359Sroberto					   progname, c);
41954359Sroberto				errflg++;
42054359Sroberto			} else {
42154359Sroberto				sys_samples = c;
42254359Sroberto			}
42354359Sroberto			break;
42454359Sroberto		case 'q':
42554359Sroberto			simple_query = 1;
42654359Sroberto			break;
42754359Sroberto		case 's':
42854359Sroberto			syslogit = 1;
42954359Sroberto			break;
43054359Sroberto		case 't':
43154359Sroberto			if (!atolfp(ntp_optarg, &tmp)) {
43254359Sroberto				(void) fprintf(stderr,
43354359Sroberto					   "%s: timeout %s is undecodeable\n",
43454359Sroberto					   progname, ntp_optarg);
43554359Sroberto				errflg++;
43654359Sroberto			} else {
43754359Sroberto				sys_timeout = ((LFPTOFP(&tmp) * TIMER_HZ)
43854359Sroberto					   + 0x8000) >> 16;
43954359Sroberto				if (sys_timeout == 0)
44054359Sroberto				sys_timeout = 1;
44154359Sroberto			}
44254359Sroberto			break;
44354359Sroberto		case 'v':
44454359Sroberto			verbose = 1;
44554359Sroberto			break;
44654359Sroberto		case 'u':
44754359Sroberto			unpriv_port = 1;
44854359Sroberto			break;
44954359Sroberto		case '?':
45054359Sroberto			++errflg;
45154359Sroberto			break;
45254359Sroberto		default:
45354359Sroberto			break;
45454359Sroberto	    }
45554359Sroberto
45654359Sroberto	if (errflg) {
45754359Sroberto		(void) fprintf(stderr,
458182007Sroberto		    "usage: %s [-46bBdqsuv] [-a key#] [-e delay] [-k file] [-p samples] [-o version#] [-t timeo] server ...\n",
459132451Sroberto		    progname);
46054359Sroberto		exit(2);
46154359Sroberto	}
46254359Sroberto
46354359Sroberto	if (debug || simple_query) {
46454359Sroberto#ifdef HAVE_SETVBUF
46554359Sroberto		static char buf[BUFSIZ];
466182007Sroberto#ifdef SYS_WINNT
467182007Sroberto		/* Win32 does not implement line buffering */
468182007Sroberto		setvbuf(stdout, NULL, _IONBF, BUFSIZ);
469182007Sroberto#else
47054359Sroberto		setvbuf(stdout, buf, _IOLBF, BUFSIZ);
471182007Sroberto#endif	/* SYS_WINNT */
47254359Sroberto#else
47354359Sroberto		setlinebuf(stdout);
47454359Sroberto#endif
47554359Sroberto	}
47654359Sroberto
47754359Sroberto	/*
47854359Sroberto	 * Logging.  Open the syslog if we have to
47954359Sroberto	 */
48054359Sroberto	if (syslogit) {
48154359Sroberto#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
48254359Sroberto# ifndef	LOG_DAEMON
48354359Sroberto		openlog("ntpdate", LOG_PID);
48454359Sroberto# else
48554359Sroberto
48654359Sroberto#  ifndef	LOG_NTP
48754359Sroberto#	define	LOG_NTP LOG_DAEMON
48854359Sroberto#  endif
48954359Sroberto		openlog("ntpdate", LOG_PID | LOG_NDELAY, LOG_NTP);
49054359Sroberto		if (debug)
49154359Sroberto			setlogmask(LOG_UPTO(LOG_DEBUG));
49254359Sroberto		else
49354359Sroberto			setlogmask(LOG_UPTO(LOG_INFO));
49454359Sroberto# endif /* LOG_DAEMON */
49554359Sroberto#endif	/* SYS_WINNT */
49654359Sroberto	}
49754359Sroberto
49854359Sroberto	if (debug || verbose)
49954359Sroberto		msyslog(LOG_NOTICE, "%s", Version);
50054359Sroberto
50154359Sroberto	/*
50254359Sroberto	 * Add servers we are going to be polling
50354359Sroberto	 */
50454359Sroberto#ifdef HAVE_NETINFO
50582498Sroberto	netinfoservers = getnetinfoservers();
50654359Sroberto#endif
50754359Sroberto
50854359Sroberto	for ( ; ntp_optind < argc; ntp_optind++)
50954359Sroberto		addserver(argv[ntp_optind]);
51054359Sroberto
51154359Sroberto#ifdef HAVE_NETINFO
51254359Sroberto	if (netinfoservers) {
51354359Sroberto		if ( netinfoservers->ni_namelist_len &&
51454359Sroberto		    *netinfoservers->ni_namelist_val ) {
51554359Sroberto			u_int servercount = 0;
51654359Sroberto			while (servercount < netinfoservers->ni_namelist_len) {
51754359Sroberto				if (debug) msyslog(LOG_DEBUG,
51854359Sroberto						   "Adding time server %s from NetInfo configuration.",
51954359Sroberto						   netinfoservers->ni_namelist_val[servercount]);
52054359Sroberto				addserver(netinfoservers->ni_namelist_val[servercount++]);
52154359Sroberto			}
52254359Sroberto		}
52354359Sroberto		ni_namelist_free(netinfoservers);
52454359Sroberto		free(netinfoservers);
52554359Sroberto	}
52654359Sroberto#endif
52754359Sroberto
52854359Sroberto	if (sys_numservers == 0) {
52954359Sroberto		msyslog(LOG_ERR, "no servers can be used, exiting");
53054359Sroberto		exit(1);
53154359Sroberto	}
53254359Sroberto
53354359Sroberto	/*
53454359Sroberto	 * Initialize the time of day routines and the I/O subsystem
53554359Sroberto	 */
53654359Sroberto	if (sys_authenticate) {
53754359Sroberto		init_auth();
53854359Sroberto		if (!authreadkeys(key_file)) {
53982498Sroberto			msyslog(LOG_ERR, "no key file <%s>, exiting", key_file);
54054359Sroberto			exit(1);
54154359Sroberto		}
54282498Sroberto		authtrust(sys_authkey, 1);
54354359Sroberto		if (!authistrusted(sys_authkey)) {
544182007Sroberto			msyslog(LOG_ERR, "authentication key %lu unknown",
545182007Sroberto				(unsigned long) sys_authkey);
54654359Sroberto			exit(1);
54754359Sroberto		}
54854359Sroberto	}
54954359Sroberto	init_io();
55054359Sroberto	init_alarm();
55154359Sroberto
55254359Sroberto	/*
55354359Sroberto	 * Set the priority.
55454359Sroberto	 */
55554359Sroberto#ifdef SYS_VXWORKS
55654359Sroberto	taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
55754359Sroberto#endif
55854359Sroberto#if defined(HAVE_ATT_NICE)
55954359Sroberto	nice (NTPDATE_PRIO);
56054359Sroberto#endif
56154359Sroberto#if defined(HAVE_BSD_NICE)
56254359Sroberto	(void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
56354359Sroberto#endif
56454359Sroberto#ifdef SYS_WINNT
56554359Sroberto	process_handle = GetCurrentProcess();
56654359Sroberto	if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
56754359Sroberto		msyslog(LOG_ERR, "SetPriorityClass failed: %m");
56854359Sroberto	}
56954359Sroberto#endif /* SYS_WINNT */
57054359Sroberto
571132451Sroberto
572132451Sroberto
57354359Sroberto	initializing = 0;
57454359Sroberto	was_alarmed = 0;
575132451Sroberto
57654359Sroberto	while (complete_servers < sys_numservers) {
57754359Sroberto#ifdef HAVE_POLL_H
578182007Sroberto		struct pollfd* rdfdes;
579182007Sroberto		rdfdes = fdmask;
58054359Sroberto#else
58154359Sroberto		fd_set rdfdes;
582182007Sroberto		rdfdes = fdmask;
58354359Sroberto#endif
58454359Sroberto
58554359Sroberto		if (alarm_flag) {		/* alarmed? */
58654359Sroberto			was_alarmed = 1;
58754359Sroberto			alarm_flag = 0;
58854359Sroberto		}
589182007Sroberto		tot_recvbufs = full_recvbuffs();	/* get received buffers */
59054359Sroberto
591182007Sroberto		if (!was_alarmed && tot_recvbufs == 0) {
59254359Sroberto			/*
59354359Sroberto			 * Nothing to do.	 Wait for something.
59454359Sroberto			 */
59554359Sroberto#ifdef HAVE_POLL_H
596182007Sroberto			nfound = poll(rdfdes, (unsigned int)nbsock, timeout.tv_sec * 1000);
597132451Sroberto
59854359Sroberto#else
599182007Sroberto			nfound = select(maxfd, &rdfdes, (fd_set *)0,
60054359Sroberto					(fd_set *)0, &timeout);
60154359Sroberto#endif
60254359Sroberto			if (nfound > 0)
60354359Sroberto				input_handler();
604182007Sroberto			else if (nfound == SOCKET_ERROR)
605182007Sroberto			{
60654359Sroberto#ifndef SYS_WINNT
607182007Sroberto				if (errno != EINTR)
60854359Sroberto#else
609182007Sroberto				if (WSAGetLastError() != WSAEINTR)
61054359Sroberto#endif
611132451Sroberto					netsyslog(LOG_ERR,
61254359Sroberto#ifdef HAVE_POLL_H
61354359Sroberto						"poll() error: %m"
61454359Sroberto#else
61554359Sroberto						"select() error: %m"
61654359Sroberto#endif
61754359Sroberto						);
618182007Sroberto			} else if (errno != 0) {
61954359Sroberto#ifndef SYS_VXWORKS
620132451Sroberto				netsyslog(LOG_DEBUG,
62154359Sroberto#ifdef HAVE_POLL_H
62254359Sroberto					"poll(): nfound = %d, error: %m",
62354359Sroberto#else
62454359Sroberto					"select(): nfound = %d, error: %m",
62554359Sroberto#endif
62654359Sroberto					nfound);
62754359Sroberto#endif
62854359Sroberto			}
62954359Sroberto			if (alarm_flag) {		/* alarmed? */
63054359Sroberto				was_alarmed = 1;
63154359Sroberto				alarm_flag = 0;
63254359Sroberto			}
633182007Sroberto			tot_recvbufs = full_recvbuffs();	/* get received buffers */
63454359Sroberto		}
63554359Sroberto
63654359Sroberto		/*
63754359Sroberto		 * Out here, signals are unblocked.  Call receive
63854359Sroberto		 * procedure for each incoming packet.
63954359Sroberto		 */
640182007Sroberto		rbuf = get_full_recv_buffer();
641182007Sroberto		while (rbuf != NULL)
642182007Sroberto		{
64354359Sroberto			receive(rbuf);
64454359Sroberto			freerecvbuf(rbuf);
645182007Sroberto			rbuf = get_full_recv_buffer();
64654359Sroberto		}
64754359Sroberto
64854359Sroberto		/*
64954359Sroberto		 * Call timer to process any timeouts
65054359Sroberto		 */
65154359Sroberto		if (was_alarmed) {
65254359Sroberto			timer();
65354359Sroberto			was_alarmed = 0;
65454359Sroberto		}
65554359Sroberto
65654359Sroberto		/*
65754359Sroberto		 * Go around again
65854359Sroberto		 */
65954359Sroberto	}
66054359Sroberto
66154359Sroberto	/*
66254359Sroberto	 * When we get here we've completed the polling of all servers.
66354359Sroberto	 * Adjust the clock, then exit.
66454359Sroberto	 */
66554359Sroberto#ifdef SYS_WINNT
66654359Sroberto	WSACleanup();
66754359Sroberto#endif
66854359Sroberto#ifdef SYS_VXWORKS
66954359Sroberto	close (fd);
67054359Sroberto	timer_delete(ntpdate_timerid);
67154359Sroberto#endif
672132451Sroberto
67354359Sroberto	return clock_adjust();
67454359Sroberto}
67554359Sroberto
67654359Sroberto
67754359Sroberto/*
67854359Sroberto * transmit - transmit a packet to the given server, or mark it completed.
679182007Sroberto *		This is called by the timeout routine and by the receive
680182007Sroberto *		procedure.
68154359Sroberto */
68254359Srobertostatic void
68354359Srobertotransmit(
68454359Sroberto	register struct server *server
68554359Sroberto	)
68654359Sroberto{
68754359Sroberto	struct pkt xpkt;
68854359Sroberto
68954359Sroberto	if (debug)
690132451Sroberto		printf("transmit(%s)\n", stoa(&(server->srcadr)));
69154359Sroberto
69254359Sroberto	if (server->filter_nextpt < server->xmtcnt) {
69354359Sroberto		l_fp ts;
69454359Sroberto		/*
69554359Sroberto		 * Last message to this server timed out.  Shift
69654359Sroberto		 * zeros into the filter.
69754359Sroberto		 */
69854359Sroberto		L_CLR(&ts);
69954359Sroberto		server_data(server, 0, &ts, 0);
70054359Sroberto	}
70154359Sroberto
70254359Sroberto	if ((int)server->filter_nextpt >= sys_samples) {
70354359Sroberto		/*
70454359Sroberto		 * Got all the data we need.  Mark this guy
70554359Sroberto		 * completed and return.
70654359Sroberto		 */
70754359Sroberto		server->event_time = 0;
70854359Sroberto		complete_servers++;
70954359Sroberto		return;
71054359Sroberto	}
71154359Sroberto
71254359Sroberto	/*
713182007Sroberto	 * If we're here, send another message to the server.  Fill in
71454359Sroberto	 * the packet and let 'er rip.
71554359Sroberto	 */
71654359Sroberto	xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
71754359Sroberto					 sys_version, MODE_CLIENT);
71854359Sroberto	xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
71954359Sroberto	xpkt.ppoll = NTP_MINPOLL;
72054359Sroberto	xpkt.precision = NTPDATE_PRECISION;
72154359Sroberto	xpkt.rootdelay = htonl(NTPDATE_DISTANCE);
72254359Sroberto	xpkt.rootdispersion = htonl(NTPDATE_DISP);
72354359Sroberto	xpkt.refid = htonl(NTPDATE_REFID);
72454359Sroberto	L_CLR(&xpkt.reftime);
72554359Sroberto	L_CLR(&xpkt.org);
72654359Sroberto	L_CLR(&xpkt.rec);
72754359Sroberto
72854359Sroberto	/*
72954359Sroberto	 * Determine whether to authenticate or not.	If so,
73054359Sroberto	 * fill in the extended part of the packet and do it.
73154359Sroberto	 * If not, just timestamp it and send it away.
73254359Sroberto	 */
73354359Sroberto	if (sys_authenticate) {
73454359Sroberto		int len;
73554359Sroberto
73682498Sroberto		xpkt.exten[0] = htonl(sys_authkey);
73754359Sroberto		get_systime(&server->xmt);
73854359Sroberto		L_ADDUF(&server->xmt, sys_authdelay);
73954359Sroberto		HTONL_FP(&server->xmt, &xpkt.xmt);
74054359Sroberto		len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC);
74154359Sroberto		sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len));
74254359Sroberto
74354359Sroberto		if (debug > 1)
74454359Sroberto			printf("transmit auth to %s\n",
745132451Sroberto			   stoa(&(server->srcadr)));
74654359Sroberto	} else {
74754359Sroberto		get_systime(&(server->xmt));
74854359Sroberto		HTONL_FP(&server->xmt, &xpkt.xmt);
74954359Sroberto		sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC);
75054359Sroberto
75154359Sroberto		if (debug > 1)
752132451Sroberto			printf("transmit to %s\n", stoa(&(server->srcadr)));
75354359Sroberto	}
75454359Sroberto
75554359Sroberto	/*
75654359Sroberto	 * Update the server timeout and transmit count
75754359Sroberto	 */
75854359Sroberto	server->event_time = current_time + sys_timeout;
75954359Sroberto	server->xmtcnt++;
76054359Sroberto}
76154359Sroberto
76254359Sroberto
76354359Sroberto/*
76454359Sroberto * receive - receive and process an incoming frame
76554359Sroberto */
76654359Srobertostatic void
76754359Srobertoreceive(
76854359Sroberto	struct recvbuf *rbufp
76954359Sroberto	)
77054359Sroberto{
77154359Sroberto	register struct pkt *rpkt;
77254359Sroberto	register struct server *server;
77354359Sroberto	register s_fp di;
774106163Sroberto	l_fp t10, t23, tmp;
77554359Sroberto	l_fp org;
77654359Sroberto	l_fp rec;
77754359Sroberto	l_fp ci;
77854359Sroberto	int has_mac;
77954359Sroberto	int is_authentic;
78054359Sroberto
78154359Sroberto	if (debug)
782182007Sroberto		printf("receive(%s)\n", stoa(&rbufp->recv_srcadr));
78354359Sroberto	/*
78454359Sroberto	 * Check to see if the packet basically looks like something
78554359Sroberto	 * intended for us.
78654359Sroberto	 */
78754359Sroberto	if (rbufp->recv_length == LEN_PKT_NOMAC)
78854359Sroberto		has_mac = 0;
78954359Sroberto	else if (rbufp->recv_length >= LEN_PKT_NOMAC)
79054359Sroberto		has_mac = 1;
79154359Sroberto	else {
79254359Sroberto		if (debug)
79354359Sroberto			printf("receive: packet length %d\n",
79454359Sroberto			   rbufp->recv_length);
79554359Sroberto		return; 		/* funny length packet */
79654359Sroberto	}
79754359Sroberto
79854359Sroberto	rpkt = &(rbufp->recv_pkt);
79954359Sroberto	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
80054359Sroberto		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
80154359Sroberto		return;
80254359Sroberto	}
80354359Sroberto
80454359Sroberto	if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
80554359Sroberto		 && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
80682498Sroberto		|| rpkt->stratum >= STRATUM_UNSPEC) {
80754359Sroberto		if (debug)
80854359Sroberto			printf("receive: mode %d stratum %d\n",
80954359Sroberto			   PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
81054359Sroberto		return;
81154359Sroberto	}
81254359Sroberto
81354359Sroberto	/*
81454359Sroberto	 * So far, so good.  See if this is from a server we know.
81554359Sroberto	 */
81654359Sroberto	server = findserver(&(rbufp->recv_srcadr));
81754359Sroberto	if (server == NULL) {
81854359Sroberto		if (debug)
81954359Sroberto			printf("receive: server not found\n");
82054359Sroberto		return;
82154359Sroberto	}
82254359Sroberto
82354359Sroberto	/*
82454359Sroberto	 * Decode the org timestamp and make sure we're getting a response
82554359Sroberto	 * to our last request.
82654359Sroberto	 */
82754359Sroberto	NTOHL_FP(&rpkt->org, &org);
82854359Sroberto	if (!L_ISEQU(&org, &server->xmt)) {
82954359Sroberto		if (debug)
83054359Sroberto			printf("receive: pkt.org and peer.xmt differ\n");
83154359Sroberto		return;
83254359Sroberto	}
83354359Sroberto
83454359Sroberto	/*
83554359Sroberto	 * Check out the authenticity if we're doing that.
83654359Sroberto	 */
83754359Sroberto	if (!sys_authenticate)
83854359Sroberto		is_authentic = 1;
83954359Sroberto	else {
84054359Sroberto		is_authentic = 0;
84154359Sroberto
84254359Sroberto		if (debug > 3)
84354359Sroberto			printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n",
84482498Sroberto			   (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey,
84554359Sroberto			   (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt,
84654359Sroberto				LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC)));
84754359Sroberto
84882498Sroberto		if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey &&
84954359Sroberto			authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC,
85054359Sroberto			(int)(rbufp->recv_length - LEN_PKT_NOMAC)))
85154359Sroberto			is_authentic = 1;
85254359Sroberto		if (debug)
85354359Sroberto			printf("receive: authentication %s\n",
85454359Sroberto			   is_authentic ? "passed" : "failed");
85554359Sroberto	}
85654359Sroberto	server->trust <<= 1;
85754359Sroberto	if (!is_authentic)
85854359Sroberto		server->trust |= 1;
85954359Sroberto
86054359Sroberto	/*
86154359Sroberto	 * Looks good.	Record info from the packet.
86254359Sroberto	 */
86354359Sroberto	server->leap = PKT_LEAP(rpkt->li_vn_mode);
86454359Sroberto	server->stratum = PKT_TO_STRATUM(rpkt->stratum);
86554359Sroberto	server->precision = rpkt->precision;
86654359Sroberto	server->rootdelay = ntohl(rpkt->rootdelay);
86754359Sroberto	server->rootdispersion = ntohl(rpkt->rootdispersion);
86854359Sroberto	server->refid = rpkt->refid;
86954359Sroberto	NTOHL_FP(&rpkt->reftime, &server->reftime);
87054359Sroberto	NTOHL_FP(&rpkt->rec, &rec);
87154359Sroberto	NTOHL_FP(&rpkt->xmt, &server->org);
87254359Sroberto
87354359Sroberto	/*
87454359Sroberto	 * Make sure the server is at least somewhat sane.	If not, try
87554359Sroberto	 * again.
87654359Sroberto	 */
87754359Sroberto	if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
87854359Sroberto		transmit(server);
87954359Sroberto		return;
88054359Sroberto	}
88154359Sroberto
88254359Sroberto	/*
88354359Sroberto	 * Calculate the round trip delay (di) and the clock offset (ci).
88454359Sroberto	 * We use the equations (reordered from those in the spec):
88554359Sroberto	 *
88654359Sroberto	 * d = (t2 - t3) - (t1 - t0)
88754359Sroberto	 * c = ((t2 - t3) + (t1 - t0)) / 2
88854359Sroberto	 */
88954359Sroberto	t10 = server->org;		/* pkt.xmt == t1 */
89054359Sroberto	L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
89154359Sroberto
89254359Sroberto	t23 = rec;			/* pkt.rec == t2 */
89354359Sroberto	L_SUB(&t23, &org);		/* pkt->org == t3 */
89454359Sroberto
89554359Sroberto	/* now have (t2 - t3) and (t0 - t1).	Calculate (ci) and (di) */
896106163Sroberto	/*
897106163Sroberto	 * Calculate (ci) = ((t1 - t0) / 2) + ((t2 - t3) / 2)
898106163Sroberto	 * For large offsets this may prevent an overflow on '+'
899106163Sroberto	 */
90054359Sroberto	ci = t10;
90154359Sroberto	L_RSHIFT(&ci);
902106163Sroberto	tmp = t23;
903106163Sroberto	L_RSHIFT(&tmp);
904106163Sroberto	L_ADD(&ci, &tmp);
90554359Sroberto
90654359Sroberto	/*
90754359Sroberto	 * Calculate di in t23 in full precision, then truncate
90854359Sroberto	 * to an s_fp.
90954359Sroberto	 */
91054359Sroberto	L_SUB(&t23, &t10);
91154359Sroberto	di = LFPTOFP(&t23);
91254359Sroberto
91354359Sroberto	if (debug > 3)
91454359Sroberto		printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5));
91554359Sroberto
91654359Sroberto	di += (FP_SECOND >> (-(int)NTPDATE_PRECISION))
91754359Sroberto		+ (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW;
91854359Sroberto
91954359Sroberto	if (di <= 0) {		/* value still too raunchy to use? */
92054359Sroberto		L_CLR(&ci);
92154359Sroberto		di = 0;
92254359Sroberto	} else {
92354359Sroberto		di = max(di, NTP_MINDIST);
92454359Sroberto	}
92554359Sroberto
92654359Sroberto	/*
92754359Sroberto	 * Shift this data in, then transmit again.
92854359Sroberto	 */
92954359Sroberto	server_data(server, (s_fp) di, &ci, 0);
93054359Sroberto	transmit(server);
93154359Sroberto}
93254359Sroberto
93354359Sroberto
93454359Sroberto/*
93554359Sroberto * server_data - add a sample to the server's filter registers
93654359Sroberto */
93754359Srobertostatic void
93854359Srobertoserver_data(
93954359Sroberto	register struct server *server,
94054359Sroberto	s_fp d,
94154359Sroberto	l_fp *c,
94254359Sroberto	u_fp e
94354359Sroberto	)
94454359Sroberto{
945132451Sroberto	u_short i;
94654359Sroberto
94754359Sroberto	i = server->filter_nextpt;
94854359Sroberto	if (i < NTP_SHIFT) {
94954359Sroberto		server->filter_delay[i] = d;
95054359Sroberto		server->filter_offset[i] = *c;
95154359Sroberto		server->filter_soffset[i] = LFPTOFP(c);
95254359Sroberto		server->filter_error[i] = e;
953132451Sroberto		server->filter_nextpt = (u_short)(i + 1);
95454359Sroberto	}
95554359Sroberto}
95654359Sroberto
95754359Sroberto
95854359Sroberto/*
95954359Sroberto * clock_filter - determine a server's delay, dispersion and offset
96054359Sroberto */
96154359Srobertostatic void
96254359Srobertoclock_filter(
96354359Sroberto	register struct server *server
96454359Sroberto	)
96554359Sroberto{
96654359Sroberto	register int i, j;
96754359Sroberto	int ord[NTP_SHIFT];
96854359Sroberto
96954359Sroberto	/*
97054359Sroberto	 * Sort indices into increasing delay order
97154359Sroberto	 */
97254359Sroberto	for (i = 0; i < sys_samples; i++)
97354359Sroberto		ord[i] = i;
97454359Sroberto
97554359Sroberto	for (i = 0; i < (sys_samples-1); i++) {
97654359Sroberto		for (j = i+1; j < sys_samples; j++) {
97754359Sroberto			if (server->filter_delay[ord[j]] == 0)
97854359Sroberto				continue;
97954359Sroberto			if (server->filter_delay[ord[i]] == 0
98054359Sroberto				|| (server->filter_delay[ord[i]]
98154359Sroberto				> server->filter_delay[ord[j]])) {
98254359Sroberto				register int tmp;
98354359Sroberto
98454359Sroberto				tmp = ord[i];
98554359Sroberto				ord[i] = ord[j];
98654359Sroberto				ord[j] = tmp;
98754359Sroberto			}
98854359Sroberto		}
98954359Sroberto	}
99054359Sroberto
99154359Sroberto	/*
99254359Sroberto	 * Now compute the dispersion, and assign values to delay and
99354359Sroberto	 * offset.	If there are no samples in the register, delay and
99454359Sroberto	 * offset go to zero and dispersion is set to the maximum.
99554359Sroberto	 */
99654359Sroberto	if (server->filter_delay[ord[0]] == 0) {
99754359Sroberto		server->delay = 0;
99854359Sroberto		L_CLR(&server->offset);
99954359Sroberto		server->soffset = 0;
100054359Sroberto		server->dispersion = PEER_MAXDISP;
100154359Sroberto	} else {
100254359Sroberto		register s_fp d;
100354359Sroberto
100454359Sroberto		server->delay = server->filter_delay[ord[0]];
100554359Sroberto		server->offset = server->filter_offset[ord[0]];
100654359Sroberto		server->soffset = LFPTOFP(&server->offset);
100754359Sroberto		server->dispersion = 0;
100854359Sroberto		for (i = 1; i < sys_samples; i++) {
100954359Sroberto			if (server->filter_delay[ord[i]] == 0)
101054359Sroberto				d = PEER_MAXDISP;
101154359Sroberto			else {
101254359Sroberto				d = server->filter_soffset[ord[i]]
101354359Sroberto					- server->filter_soffset[ord[0]];
101454359Sroberto				if (d < 0)
101554359Sroberto					d = -d;
101654359Sroberto				if (d > PEER_MAXDISP)
101754359Sroberto					d = PEER_MAXDISP;
101854359Sroberto			}
101954359Sroberto			/*
102054359Sroberto			 * XXX This *knows* PEER_FILTER is 1/2
102154359Sroberto			 */
102254359Sroberto			server->dispersion += (u_fp)(d) >> i;
102354359Sroberto		}
102454359Sroberto	}
102554359Sroberto	/*
102654359Sroberto	 * We're done
102754359Sroberto	 */
102854359Sroberto}
102954359Sroberto
103054359Sroberto
103154359Sroberto/*
103254359Sroberto * clock_select - select the pick-of-the-litter clock from the samples
103354359Sroberto *		  we've got.
103454359Sroberto */
103554359Srobertostatic struct server *
103654359Srobertoclock_select(void)
103754359Sroberto{
103854359Sroberto	register struct server *server;
103954359Sroberto	register int i;
104054359Sroberto	register int nlist;
104154359Sroberto	register s_fp d;
104254359Sroberto	register int j;
104354359Sroberto	register int n;
104454359Sroberto	s_fp local_threshold;
104554359Sroberto	struct server *server_list[NTP_MAXCLOCK];
104654359Sroberto	u_fp server_badness[NTP_MAXCLOCK];
104754359Sroberto	struct server *sys_server;
104854359Sroberto
104954359Sroberto	/*
105054359Sroberto	 * This first chunk of code is supposed to go through all
105154359Sroberto	 * servers we know about to find the NTP_MAXLIST servers which
105254359Sroberto	 * are most likely to succeed.	We run through the list
105354359Sroberto	 * doing the sanity checks and trying to insert anyone who
105454359Sroberto	 * looks okay.	We are at all times aware that we should
105554359Sroberto	 * only keep samples from the top two strata and we only need
105654359Sroberto	 * NTP_MAXLIST of them.
105754359Sroberto	 */
105854359Sroberto	nlist = 0;	/* none yet */
105956746Sroberto	for (server = sys_servers; server != NULL; server = server->next_server) {
1060106163Sroberto		if (server->delay == 0) {
1061106163Sroberto			if (debug)
1062106163Sroberto				printf("%s: Server dropped: no data\n", ntoa(&server->srcadr));
1063182007Sroberto			continue;	/* no data */
1064106163Sroberto		}
1065106163Sroberto		if (server->stratum > NTP_INFIN) {
1066106163Sroberto			if (debug)
1067106163Sroberto				printf("%s: Server dropped: strata too high\n", ntoa(&server->srcadr));
1068182007Sroberto			continue;	/* stratum no good */
1069106163Sroberto		}
107054359Sroberto		if (server->delay > NTP_MAXWGT) {
1071106163Sroberto			if (debug)
1072106163Sroberto				printf("%s: Server dropped: server too far away\n",
1073182007Sroberto					ntoa(&server->srcadr));
1074182007Sroberto			continue;	/* too far away */
107554359Sroberto		}
1076106163Sroberto		if (server->leap == LEAP_NOTINSYNC) {
1077106163Sroberto			if (debug)
1078106163Sroberto				printf("%s: Server dropped: Leap not in sync\n", ntoa(&server->srcadr));
1079182007Sroberto			continue;	/* he's in trouble */
1080106163Sroberto		}
108154359Sroberto		if (!L_ISHIS(&server->org, &server->reftime)) {
1082106163Sroberto			if (debug)
1083106163Sroberto				printf("%s: Server dropped: server is very broken\n",
1084106163Sroberto				       ntoa(&server->srcadr));
1085182007Sroberto			continue;	/* very broken host */
108654359Sroberto		}
108754359Sroberto		if ((server->org.l_ui - server->reftime.l_ui)
1088106163Sroberto		    >= NTP_MAXAGE) {
1089106163Sroberto			if (debug)
1090106163Sroberto				printf("%s: Server dropped: Server has gone too long without sync\n",
1091106163Sroberto				       ntoa(&server->srcadr));
109254359Sroberto			continue;	/* too long without sync */
109354359Sroberto		}
109454359Sroberto		if (server->trust != 0) {
1095106163Sroberto			if (debug)
1096106163Sroberto				printf("%s: Server dropped: Server is untrusted\n",
1097106163Sroberto				       ntoa(&server->srcadr));
109854359Sroberto			continue;
109954359Sroberto		}
110054359Sroberto
110154359Sroberto		/*
110254359Sroberto		 * This one seems sane.  Find where he belongs
110354359Sroberto		 * on the list.
110454359Sroberto		 */
110554359Sroberto		d = server->dispersion + server->dispersion;
110654359Sroberto		for (i = 0; i < nlist; i++)
110754359Sroberto			if (server->stratum <= server_list[i]->stratum)
110854359Sroberto			break;
110954359Sroberto		for ( ; i < nlist; i++) {
111054359Sroberto			if (server->stratum < server_list[i]->stratum)
111154359Sroberto				break;
111254359Sroberto			if (d < (s_fp) server_badness[i])
111354359Sroberto				break;
111454359Sroberto		}
111554359Sroberto
111654359Sroberto		/*
111754359Sroberto		 * If i points past the end of the list, this
111854359Sroberto		 * guy is a loser, else stick him in.
111954359Sroberto		 */
112054359Sroberto		if (i >= NTP_MAXLIST)
112154359Sroberto			continue;
112254359Sroberto		for (j = nlist; j > i; j--)
112354359Sroberto			if (j < NTP_MAXLIST) {
112454359Sroberto				server_list[j] = server_list[j-1];
112554359Sroberto				server_badness[j]
112654359Sroberto					= server_badness[j-1];
112754359Sroberto			}
112854359Sroberto
112954359Sroberto		server_list[i] = server;
113054359Sroberto		server_badness[i] = d;
113154359Sroberto		if (nlist < NTP_MAXLIST)
113254359Sroberto			nlist++;
113354359Sroberto	}
113454359Sroberto
113554359Sroberto	/*
113654359Sroberto	 * Got the five-or-less best.	 Cut the list where the number of
113754359Sroberto	 * strata exceeds two.
113854359Sroberto	 */
113954359Sroberto	j = 0;
114054359Sroberto	for (i = 1; i < nlist; i++)
114154359Sroberto		if (server_list[i]->stratum > server_list[i-1]->stratum)
114254359Sroberto		if (++j == 2) {
114354359Sroberto			nlist = i;
114454359Sroberto			break;
114554359Sroberto		}
114654359Sroberto
114754359Sroberto	/*
114854359Sroberto	 * Whew!  What we should have by now is 0 to 5 candidates for
114954359Sroberto	 * the job of syncing us.  If we have none, we're out of luck.
115054359Sroberto	 * If we have one, he's a winner.  If we have more, do falseticker
115154359Sroberto	 * detection.
115254359Sroberto	 */
115354359Sroberto
115454359Sroberto	if (nlist == 0)
115554359Sroberto		sys_server = 0;
115654359Sroberto	else if (nlist == 1) {
115754359Sroberto		sys_server = server_list[0];
115854359Sroberto	} else {
115954359Sroberto		/*
116054359Sroberto		 * Re-sort by stratum, bdelay estimate quality and
116154359Sroberto		 * server.delay.
116254359Sroberto		 */
116354359Sroberto		for (i = 0; i < nlist-1; i++)
116454359Sroberto			for (j = i+1; j < nlist; j++) {
116554359Sroberto				if (server_list[i]->stratum
116654359Sroberto				< server_list[j]->stratum)
116754359Sroberto				break;	/* already sorted by stratum */
116854359Sroberto				if (server_list[i]->delay
116954359Sroberto				< server_list[j]->delay)
117054359Sroberto				continue;
117154359Sroberto				server = server_list[i];
117254359Sroberto				server_list[i] = server_list[j];
117354359Sroberto				server_list[j] = server;
117454359Sroberto			}
117554359Sroberto
117654359Sroberto		/*
117754359Sroberto		 * Calculate the fixed part of the dispersion limit
117854359Sroberto		 */
117954359Sroberto		local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION))
118054359Sroberto			+ NTP_MAXSKW;
118154359Sroberto
118254359Sroberto		/*
118354359Sroberto		 * Now drop samples until we're down to one.
118454359Sroberto		 */
118554359Sroberto		while (nlist > 1) {
118654359Sroberto			for (n = 0; n < nlist; n++) {
118754359Sroberto				server_badness[n] = 0;
118854359Sroberto				for (j = 0; j < nlist; j++) {
118954359Sroberto					if (j == n) /* with self? */
119054359Sroberto						continue;
119154359Sroberto					d = server_list[j]->soffset
119254359Sroberto						- server_list[n]->soffset;
119354359Sroberto					if (d < 0)	/* absolute value */
119454359Sroberto						d = -d;
119554359Sroberto					/*
119654359Sroberto					 * XXX This code *knows* that
119754359Sroberto					 * NTP_SELECT is 3/4
119854359Sroberto					 */
119954359Sroberto					for (i = 0; i < j; i++)
120054359Sroberto						d = (d>>1) + (d>>2);
120154359Sroberto					server_badness[n] += d;
120254359Sroberto				}
120354359Sroberto			}
120454359Sroberto
120554359Sroberto			/*
120654359Sroberto			 * We now have an array of nlist badness
120754359Sroberto			 * coefficients.	Find the badest.  Find
120854359Sroberto			 * the minimum precision while we're at
120954359Sroberto			 * it.
121054359Sroberto			 */
121154359Sroberto			i = 0;
121254359Sroberto			n = server_list[0]->precision;;
121354359Sroberto			for (j = 1; j < nlist; j++) {
121454359Sroberto				if (server_badness[j] >= server_badness[i])
121554359Sroberto					i = j;
121654359Sroberto				if (n > server_list[j]->precision)
121754359Sroberto					n = server_list[j]->precision;
121854359Sroberto			}
121954359Sroberto
122054359Sroberto			/*
122154359Sroberto			 * i is the index of the server with the worst
122254359Sroberto			 * dispersion.	If his dispersion is less than
122354359Sroberto			 * the threshold, stop now, else delete him and
122454359Sroberto			 * continue around again.
122554359Sroberto			 */
122654359Sroberto			if ( (s_fp) server_badness[i] < (local_threshold
122754359Sroberto							 + (FP_SECOND >> (-n))))
122854359Sroberto				break;
122954359Sroberto			for (j = i + 1; j < nlist; j++)
123054359Sroberto				server_list[j-1] = server_list[j];
123154359Sroberto			nlist--;
123254359Sroberto		}
123354359Sroberto
123454359Sroberto		/*
123554359Sroberto		 * What remains is a list of less than 5 servers.  Take
123654359Sroberto		 * the best.
123754359Sroberto		 */
123854359Sroberto		sys_server = server_list[0];
123954359Sroberto	}
124054359Sroberto
124154359Sroberto	/*
1242182007Sroberto	 * That's it.  Return our server.
124354359Sroberto	 */
124454359Sroberto	return sys_server;
124554359Sroberto}
124654359Sroberto
124754359Sroberto
124854359Sroberto/*
124954359Sroberto * clock_adjust - process what we've received, and adjust the time
125054359Sroberto *		 if we got anything decent.
125154359Sroberto */
125254359Srobertostatic int
125354359Srobertoclock_adjust(void)
125454359Sroberto{
125556746Sroberto	register struct server *sp, *server;
125654359Sroberto	s_fp absoffset;
125754359Sroberto	int dostep;
125854359Sroberto
125956746Sroberto	for (sp = sys_servers; sp != NULL; sp = sp->next_server)
126056746Sroberto		clock_filter(sp);
126154359Sroberto	server = clock_select();
126254359Sroberto
126354359Sroberto	if (debug || simple_query) {
126456746Sroberto		for (sp = sys_servers; sp != NULL; sp = sp->next_server)
126556746Sroberto			printserver(sp, stdout);
126654359Sroberto	}
126754359Sroberto
126854359Sroberto	if (server == 0) {
126954359Sroberto		msyslog(LOG_ERR,
127054359Sroberto			"no server suitable for synchronization found");
127154359Sroberto		return(1);
127254359Sroberto	}
127354359Sroberto
127454359Sroberto	if (always_step) {
127554359Sroberto		dostep = 1;
127654359Sroberto	} else if (never_step) {
127754359Sroberto		dostep = 0;
127854359Sroberto	} else {
127954359Sroberto		absoffset = server->soffset;
128054359Sroberto		if (absoffset < 0)
128154359Sroberto			absoffset = -absoffset;
1282106424Sroberto		dostep = (absoffset >= NTPDATE_THRESHOLD || absoffset < 0);
128354359Sroberto	}
128454359Sroberto
128554359Sroberto	if (dostep) {
1286182007Sroberto		if (simple_query || debug || l_step_systime(&server->offset)){
128754359Sroberto			msyslog(LOG_NOTICE, "step time server %s offset %s sec",
1288132451Sroberto				stoa(&server->srcadr),
128954359Sroberto				lfptoa(&server->offset, 6));
129054359Sroberto		}
129154359Sroberto	} else {
129254359Sroberto#if !defined SYS_WINNT && !defined SYS_CYGWIN32
129354359Sroberto		if (simple_query || l_adj_systime(&server->offset)) {
129454359Sroberto			msyslog(LOG_NOTICE, "adjust time server %s offset %s sec",
1295132451Sroberto				stoa(&server->srcadr),
129654359Sroberto				lfptoa(&server->offset, 6));
129754359Sroberto		}
129854359Sroberto#else
129954359Sroberto		/* The NT SetSystemTimeAdjustment() call achieves slewing by
130054359Sroberto		 * changing the clock frequency. This means that we cannot specify
130154359Sroberto		 * it to slew the clock by a definite amount and then stop like
130254359Sroberto		 * the Unix adjtime() routine. We can technically adjust the clock
130354359Sroberto		 * frequency, have ntpdate sleep for a while, and then wake
130454359Sroberto		 * up and reset the clock frequency, but this might cause some
130554359Sroberto		 * grief if the user attempts to run ntpd immediately after
130654359Sroberto		 * ntpdate and the socket is in use.
130754359Sroberto		 */
130854359Sroberto		printf("\nThe -b option is required by ntpdate on Windows NT platforms\n");
130954359Sroberto		exit(1);
131054359Sroberto#endif /* SYS_WINNT */
131154359Sroberto	}
131254359Sroberto	return(0);
131354359Sroberto}
131454359Sroberto
131554359Sroberto
1316182007Sroberto/*
1317182007Sroberto * is_unreachable - check to see if we have a route to given destination
1318182007Sroberto *		    (non-blocking).
1319182007Sroberto */
1320182007Srobertostatic int
1321182007Srobertois_reachable (struct sockaddr_storage *dst)
1322182007Sroberto{
1323182007Sroberto	SOCKET sockfd;
1324182007Sroberto
1325182007Sroberto	sockfd = socket(dst->ss_family, SOCK_DGRAM, 0);
1326182007Sroberto	if (sockfd == -1) {
1327182007Sroberto		return 0;
1328182007Sroberto	}
1329182007Sroberto
1330182007Sroberto	if(connect(sockfd, (struct sockaddr *)dst, SOCKLEN(dst))) {
1331182007Sroberto		closesocket(sockfd);
1332182007Sroberto		return 0;
1333182007Sroberto	}
1334182007Sroberto	closesocket(sockfd);
1335182007Sroberto	return 1;
1336182007Sroberto}
1337182007Sroberto
1338182007Sroberto
1339182007Sroberto
134054359Sroberto/* XXX ELIMINATE: merge BIG slew into adj_systime in lib/systime.c */
134154359Sroberto/*
134254359Sroberto * addserver - determine a server's address and allocate a new structure
1343182007Sroberto *		for it.
134454359Sroberto */
134554359Srobertostatic void
134654359Srobertoaddserver(
134754359Sroberto	char *serv
134854359Sroberto	)
134954359Sroberto{
135054359Sroberto	register struct server *server;
1351182007Sroberto	/* Address infos structure to store result of getaddrinfo */
1352182007Sroberto	struct addrinfo *addrResult, *ptr;
1353182007Sroberto	/* Address infos structure to store hints for getaddrinfo */
1354182007Sroberto	struct addrinfo hints;
1355182007Sroberto	/* Error variable for getaddrinfo */
1356182007Sroberto	int error;
1357182007Sroberto	/* Service name */
1358182007Sroberto	char service[5];
1359132451Sroberto	strcpy(service, "ntp");
136054359Sroberto
1361182007Sroberto	/* Get host address. Looking for UDP datagram connection. */
1362182007Sroberto	memset(&hints, 0, sizeof(hints));
1363182007Sroberto	hints.ai_family = ai_fam_templ;
1364182007Sroberto	hints.ai_socktype = SOCK_DGRAM;
1365132451Sroberto
1366138451Sroberto#ifdef DEBUG
1367182007Sroberto	if (debug)
1368182007Sroberto		printf("Looking for host %s and service %s\n", serv, service);
1369138451Sroberto#endif
1370132451Sroberto
1371182007Sroberto	error = getaddrinfo(serv, service, &hints, &addrResult);
1372182007Sroberto	if (error != 0) {
1373182007Sroberto		/* Conduct more refined error analysis */
1374182007Sroberto		if (error == EAI_FAIL || error == EAI_AGAIN){
1375182007Sroberto			/* Name server is unusable. Exit after failing on the
1376182007Sroberto			   first server, in order to shorten the timeout caused
1377182007Sroberto			   by waiting for resolution of several servers */
1378182007Sroberto			fprintf(stderr, "Name server cannot be used, exiting");
1379182007Sroberto			msyslog(LOG_ERR, "name server cannot be used, reason: %s\n", gai_strerror(error));
1380182007Sroberto			exit(1);
1381182007Sroberto		}
1382182007Sroberto		fprintf(stderr, "Error : %s\n", gai_strerror(error));
138354359Sroberto		msyslog(LOG_ERR, "can't find host %s\n", serv);
138454359Sroberto		return;
138554359Sroberto	}
1386138451Sroberto#ifdef DEBUG
1387182007Sroberto	else if (debug) {
1388182007Sroberto		fprintf(stderr, "host found : %s\n", stohost((struct sockaddr_storage*)addrResult->ai_addr));
1389182007Sroberto	}
1390138451Sroberto#endif
139154359Sroberto
1392182007Sroberto	/* We must get all returned server in case the first one fails */
1393182007Sroberto	for (ptr = addrResult; ptr != NULL; ptr = ptr->ai_next) {
1394182007Sroberto		if (is_reachable ((struct sockaddr_storage *)ptr->ai_addr)) {
1395182007Sroberto			server = (struct server *)emalloc(sizeof(struct server));
1396182007Sroberto			memset((char *)server, 0, sizeof(struct server));
139754359Sroberto
1398182007Sroberto			memset(&(server->srcadr), 0, sizeof(struct sockaddr_storage));
1399182007Sroberto			memcpy(&(server->srcadr), ptr->ai_addr, ptr->ai_addrlen);
1400182007Sroberto			server->event_time = ++sys_numservers;
1401182007Sroberto			if (sys_servers == NULL)
1402182007Sroberto				sys_servers = server;
1403182007Sroberto			else {
1404182007Sroberto				struct server *sp;
140556746Sroberto
1406182007Sroberto				for (sp = sys_servers; sp->next_server != NULL;
1407182007Sroberto				     sp = sp->next_server) ;
1408182007Sroberto				sp->next_server = server;
1409182007Sroberto			}
1410182007Sroberto		}
141156746Sroberto	}
1412182007Sroberto
1413182007Sroberto	freeaddrinfo(addrResult);
141454359Sroberto}
141554359Sroberto
141654359Sroberto
141754359Sroberto/*
141854359Sroberto * findserver - find a server in the list given its address
1419132451Sroberto * ***(For now it isn't totally AF-Independant, to check later..)
142054359Sroberto */
142154359Srobertostatic struct server *
142254359Srobertofindserver(
1423132451Sroberto	struct sockaddr_storage *addr
142454359Sroberto	)
142554359Sroberto{
142656746Sroberto	struct server *server;
142756746Sroberto	struct server *mc_server;
1428182007Sroberto	isc_sockaddr_t laddr;
1429182007Sroberto	isc_sockaddr_t saddr;
143054359Sroberto
1431182007Sroberto	if(addr->ss_family == AF_INET) {
1432182007Sroberto		isc_sockaddr_fromin( &laddr, &((struct sockaddr_in*)addr)->sin_addr, 0);
1433182007Sroberto	}
1434182007Sroberto	else {
1435182007Sroberto		isc_sockaddr_fromin6(&laddr, &((struct sockaddr_in6*)addr)->sin6_addr, 0);
1436182007Sroberto	}
1437182007Sroberto
1438182007Sroberto
143956746Sroberto	mc_server = NULL;
1440132451Sroberto	if (htons(((struct sockaddr_in*)addr)->sin_port) != NTP_PORT)
144154359Sroberto		return 0;
144254359Sroberto
144356746Sroberto	for (server = sys_servers; server != NULL;
144456746Sroberto	     server = server->next_server) {
144556746Sroberto
1446182007Sroberto		if(server->srcadr.ss_family == AF_INET) {
1447182007Sroberto			isc_sockaddr_fromin(&saddr, &((struct sockaddr_in*)&server->srcadr)->sin_addr, 0);
1448182007Sroberto		}
1449182007Sroberto		else {
1450182007Sroberto			isc_sockaddr_fromin6(&saddr, &((struct sockaddr_in6*)&server->srcadr)->sin6_addr, 0);
1451182007Sroberto		}
1452182007Sroberto		if (isc_sockaddr_eqaddr(&laddr, &saddr) == ISC_TRUE)
145356746Sroberto			return server;
1454182007Sroberto
1455182007Sroberto		if(addr->ss_family == server->srcadr.ss_family) {
1456182007Sroberto			if (isc_sockaddr_ismulticast(&saddr) == ISC_TRUE)
1457182007Sroberto				mc_server = server;
1458182007Sroberto		}
145954359Sroberto	}
146056746Sroberto
146156746Sroberto	if (mc_server != NULL) {
1462132451Sroberto
146356746Sroberto		struct server *sp;
146456746Sroberto
146556746Sroberto		if (mc_server->event_time != 0) {
146656746Sroberto			mc_server->event_time = 0;
146756746Sroberto			complete_servers++;
146856746Sroberto		}
1469132451Sroberto
147056746Sroberto		server = (struct server *)emalloc(sizeof(struct server));
147156746Sroberto		memset((char *)server, 0, sizeof(struct server));
147256746Sroberto
1473182007Sroberto		memcpy(&server->srcadr, addr, sizeof(struct sockaddr_storage));
147456746Sroberto
147556746Sroberto		server->event_time = ++sys_numservers;
1476132451Sroberto
147756746Sroberto		for (sp = sys_servers; sp->next_server != NULL;
147856746Sroberto		     sp = sp->next_server) ;
147956746Sroberto		sp->next_server = server;
148056746Sroberto		transmit(server);
148156746Sroberto	}
148256746Sroberto	return NULL;
148354359Sroberto}
148454359Sroberto
148554359Sroberto
148654359Sroberto/*
148754359Sroberto * timer - process a timer interrupt
148854359Sroberto */
148954359Srobertovoid
149054359Srobertotimer(void)
149154359Sroberto{
149256746Sroberto	struct server *server;
149354359Sroberto
149454359Sroberto	/*
149554359Sroberto	 * Bump the current idea of the time
149654359Sroberto	 */
149754359Sroberto	current_time++;
149854359Sroberto
149954359Sroberto	/*
150054359Sroberto	 * Search through the server list looking for guys
150154359Sroberto	 * who's event timers have expired.  Give these to
150254359Sroberto	 * the transmit routine.
150354359Sroberto	 */
150456746Sroberto	for (server = sys_servers; server != NULL;
150556746Sroberto	     server = server->next_server) {
150656746Sroberto		if (server->event_time != 0
150756746Sroberto		    && server->event_time <= current_time)
150856746Sroberto			transmit(server);
150954359Sroberto	}
151054359Sroberto}
151154359Sroberto
151254359Sroberto
151382498Sroberto/*
151482498Sroberto * The code duplication in the following subroutine sucks, but
151582498Sroberto * we need to appease ansi2knr.
151682498Sroberto */
151782498Sroberto
151854359Sroberto#ifndef SYS_WINNT
151954359Sroberto/*
152054359Sroberto * alarming - record the occurance of an alarm interrupt
152154359Sroberto */
152254359Srobertostatic RETSIGTYPE
152354359Srobertoalarming(
152454359Sroberto	int sig
152554359Sroberto	)
152682498Sroberto{
152782498Sroberto	alarm_flag++;
152882498Sroberto}
152954359Sroberto#else
153054359Srobertovoid CALLBACK
153154359Srobertoalarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
153254359Sroberto{
153354359Sroberto	alarm_flag++;
153454359Sroberto}
153582498Sroberto#endif /* SYS_WINNT */
153654359Sroberto
153754359Sroberto
1538182007Sroberto#ifdef SYS_WINNT
1539182007Srobertostatic void
1540182007SrobertocallTimeEndPeriod(void)
1541182007Sroberto{
1542182007Sroberto	timeEndPeriod( wTimerRes );
1543182007Sroberto	wTimerRes = 0;
1544182007Sroberto}
1545182007Sroberto#endif /* SYS_WINNT */
1546182007Sroberto
1547182007Sroberto
154854359Sroberto/*
154954359Sroberto * init_alarm - set up the timer interrupt
155054359Sroberto */
155154359Srobertostatic void
155254359Srobertoinit_alarm(void)
155354359Sroberto{
155454359Sroberto#ifndef SYS_WINNT
155554359Sroberto# ifndef HAVE_TIMER_SETTIME
155654359Sroberto	struct itimerval itimer;
155754359Sroberto# else
155854359Sroberto	struct itimerspec ntpdate_itimer;
155954359Sroberto# endif
156054359Sroberto#else
156154359Sroberto	TIMECAPS tc;
1562182007Sroberto	UINT wTimerID;
156354359Sroberto# endif /* SYS_WINNT */
156454359Sroberto#if defined SYS_CYGWIN32 || defined SYS_WINNT
156554359Sroberto	HANDLE hToken;
156654359Sroberto	TOKEN_PRIVILEGES tkp;
156754359Sroberto	DWORD dwUser = 0;
156854359Sroberto#endif /* SYS_WINNT */
156954359Sroberto
157054359Sroberto	alarm_flag = 0;
157154359Sroberto
157254359Sroberto#ifndef SYS_WINNT
157354359Sroberto# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
157454359Sroberto	alarm_flag = 0;
157554359Sroberto	/* this code was put in as setitimer() is non existant this us the
157654359Sroberto	 * POSIX "equivalents" setup - casey
157754359Sroberto	 */
157854359Sroberto	/* ntpdate_timerid is global - so we can kill timer later */
157954359Sroberto	if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
158054359Sroberto#  ifdef SYS_VXWORKS
158154359Sroberto		ERROR
158254359Sroberto#  else
158354359Sroberto		-1
158454359Sroberto#  endif
158554359Sroberto		)
158654359Sroberto	{
158754359Sroberto		fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
158854359Sroberto		return;
158954359Sroberto	}
159054359Sroberto
159154359Sroberto	/*	TIMER_HZ = (5)
159254359Sroberto	 * Set up the alarm interrupt.	The first comes 1/(2*TIMER_HZ)
159354359Sroberto	 * seconds from now and they continue on every 1/TIMER_HZ seconds.
159454359Sroberto	 */
159554359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
159654359Sroberto	ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
159754359Sroberto	ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
159854359Sroberto	ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
159954359Sroberto	timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
160054359Sroberto# else
160154359Sroberto	/*
160254359Sroberto	 * Set up the alarm interrupt.	The first comes 1/(2*TIMER_HZ)
160354359Sroberto	 * seconds from now and they continue on every 1/TIMER_HZ seconds.
160454359Sroberto	 */
160554359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
160654359Sroberto	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
160754359Sroberto	itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
160854359Sroberto	itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
1609132451Sroberto
161054359Sroberto	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
161154359Sroberto# endif
161254359Sroberto#if defined SYS_CYGWIN32
161354359Sroberto	/*
1614182007Sroberto	 * Get privileges needed for fiddling with the clock
161554359Sroberto	 */
161654359Sroberto
161754359Sroberto	/* get the current process token handle */
161854359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
161954359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
162054359Sroberto		exit(1);
162154359Sroberto	}
162254359Sroberto	/* get the LUID for system-time privilege. */
162354359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
1624182007Sroberto	tkp.PrivilegeCount = 1;		/* one privilege to set */
162554359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
162654359Sroberto	/* get set-time privilege for this process. */
162754359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
162854359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
162954359Sroberto	if (GetLastError() != ERROR_SUCCESS)
163054359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
163154359Sroberto#endif
163254359Sroberto#else	/* SYS_WINNT */
163354359Sroberto	_tzset();
163454359Sroberto
163554359Sroberto	/*
1636182007Sroberto	 * Get privileges needed for fiddling with the clock
163754359Sroberto	 */
163854359Sroberto
163954359Sroberto	/* get the current process token handle */
164054359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
164154359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
164254359Sroberto		exit(1);
164354359Sroberto	}
164454359Sroberto	/* get the LUID for system-time privilege. */
164554359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
1646182007Sroberto	tkp.PrivilegeCount = 1;		/* one privilege to set */
164754359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
164854359Sroberto	/* get set-time privilege for this process. */
164954359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
165054359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
165154359Sroberto	if (GetLastError() != ERROR_SUCCESS)
165254359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
165354359Sroberto
165454359Sroberto	/*
165554359Sroberto	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
165654359Sroberto	 * Under Win/NT, expiry of timer interval leads to invocation
165754359Sroberto	 * of a callback function (on a different thread) rather than
165854359Sroberto	 * generating an alarm signal
165954359Sroberto	 */
166054359Sroberto
166154359Sroberto	/* determine max and min resolution supported */
166254359Sroberto	if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
166354359Sroberto		msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
166454359Sroberto		exit(1);
166554359Sroberto	}
166654359Sroberto	wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
166754359Sroberto	/* establish the minimum timer resolution that we'll use */
166854359Sroberto	timeBeginPeriod(wTimerRes);
1669182007Sroberto	atexit(callTimeEndPeriod);
167054359Sroberto
167154359Sroberto	/* start the timer event */
167254359Sroberto	wTimerID = timeSetEvent(
1673182007Sroberto		(UINT) (1000/TIMER_HZ),		/* Delay */
1674182007Sroberto		wTimerRes,			/* Resolution */
1675182007Sroberto		(LPTIMECALLBACK) alarming,	/* Callback function */
1676182007Sroberto		(DWORD) dwUser,			/* User data */
1677182007Sroberto		TIME_PERIODIC);			/* Event type (periodic) */
167854359Sroberto	if (wTimerID == 0) {
167954359Sroberto		msyslog(LOG_ERR, "timeSetEvent failed: %m");
168054359Sroberto		exit(1);
168154359Sroberto	}
168254359Sroberto#endif /* SYS_WINNT */
168354359Sroberto}
168454359Sroberto
168554359Sroberto
168654359Sroberto
168754359Sroberto
168854359Sroberto/*
168954359Sroberto * We do asynchronous input using the SIGIO facility.  A number of
169054359Sroberto * recvbuf buffers are preallocated for input.	In the signal
169154359Sroberto * handler we poll to see if the socket is ready and read the
169254359Sroberto * packets from it into the recvbuf's along with a time stamp and
169354359Sroberto * an indication of the source host and the interface it was received
169454359Sroberto * through.  This allows us to get as accurate receive time stamps
169554359Sroberto * as possible independent of other processing going on.
169654359Sroberto *
169754359Sroberto * We allocate a number of recvbufs equal to the number of servers
169854359Sroberto * plus 2.	This should be plenty.
169954359Sroberto */
170054359Sroberto
170154359Sroberto
170254359Sroberto/*
170354359Sroberto * init_io - initialize I/O data and open socket
170454359Sroberto */
170554359Srobertostatic void
170654359Srobertoinit_io(void)
170754359Sroberto{
1708182007Sroberto	struct addrinfo *res, *ressave;
1709182007Sroberto	struct addrinfo hints;
1710132451Sroberto	char service[5];
1711182007Sroberto	int optval = 1;
1712182007Sroberto	int check_ntp_port_in_use = !debug && !simple_query && !unpriv_port;
1713132451Sroberto
171454359Sroberto	/*
171554359Sroberto	 * Init buffer free list and stat counters
171654359Sroberto	 */
171754359Sroberto	init_recvbuff(sys_numservers + 2);
1718132451Sroberto
171954359Sroberto	/*
172054359Sroberto	 * Open the socket
172154359Sroberto	 */
172254359Sroberto
1723132451Sroberto	strcpy(service, "ntp");
1724132451Sroberto
1725182007Sroberto	/*
1726182007Sroberto	 * Init hints addrinfo structure
1727182007Sroberto	 */
1728182007Sroberto	memset(&hints, 0, sizeof(hints));
1729182007Sroberto	hints.ai_family = ai_fam_templ;
1730182007Sroberto	hints.ai_flags = AI_PASSIVE;
1731182007Sroberto	hints.ai_socktype = SOCK_DGRAM;
1732132451Sroberto
1733182007Sroberto	if(getaddrinfo(NULL, service, &hints, &res) != 0) {
1734182007Sroberto	       msyslog(LOG_ERR, "getaddrinfo() failed: %m");
1735182007Sroberto	       exit(1);
1736182007Sroberto	       /*NOTREACHED*/
1737182007Sroberto	}
1738132451Sroberto
1739182007Sroberto#ifdef SYS_WINNT
1740182007Sroberto	if (check_ntp_port_in_use && ntp_port_inuse(AF_INET, NTP_PORT)){
1741182007Sroberto		netsyslog(LOG_ERR, "the NTP socket is in use, exiting: %m");
1742182007Sroberto		exit(1);
1743182007Sroberto	}
1744182007Sroberto#endif
1745132451Sroberto
1746182007Sroberto	/* Remember the address of the addrinfo structure chain */
1747182007Sroberto	ressave = res;
1748182007Sroberto
1749182007Sroberto	/*
1750182007Sroberto	 * For each structure returned, open and bind socket
1751182007Sroberto	 */
1752182007Sroberto	for(nbsock = 0; (nbsock < MAX_AF) && res ; res = res->ai_next) {
175354359Sroberto	/* create a datagram (UDP) socket */
1754182007Sroberto		fd[nbsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1755182007Sroberto		if (fd[nbsock] == SOCKET_ERROR) {
1756182007Sroberto#ifndef SYS_WINNT
1757132451Sroberto		if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT ||
1758132451Sroberto		    errno == EPFNOSUPPORT)
1759182007Sroberto#else
1760182007Sroberto		int err = WSAGetLastError();
1761182007Sroberto		if (err == WSAEPROTONOSUPPORT || err == WSAEAFNOSUPPORT ||
1762182007Sroberto		    err == WSAEPFNOSUPPORT)
1763182007Sroberto#endif
1764132451Sroberto			continue;
1765132451Sroberto		netsyslog(LOG_ERR, "socket() failed: %m");
176654359Sroberto		exit(1);
176754359Sroberto		/*NOTREACHED*/
1768182007Sroberto		}
1769182007Sroberto		/* set socket to reuse address */
1770182007Sroberto		if (setsockopt(fd[nbsock], SOL_SOCKET, SO_REUSEADDR, (void*) &optval, sizeof(optval)) < 0) {
1771182007Sroberto				netsyslog(LOG_ERR, "setsockopt() SO_REUSEADDR failed: %m");
1772182007Sroberto				exit(1);
1773182007Sroberto				/*NOTREACHED*/
1774182007Sroberto		}
1775132451Sroberto#ifdef IPV6_V6ONLY
1776182007Sroberto		/* Restricts AF_INET6 socket to IPv6 communications (see RFC 2553bis-03) */
1777182007Sroberto		if (res->ai_family == AF_INET6)
1778182007Sroberto			if (setsockopt(fd[nbsock], IPPROTO_IPV6, IPV6_V6ONLY, (void*) &optval, sizeof(optval)) < 0) {
1779182007Sroberto				   netsyslog(LOG_ERR, "setsockopt() IPV6_V6ONLY failed: %m");
1780182007Sroberto					exit(1);
1781182007Sroberto					/*NOTREACHED*/
1782182007Sroberto		}
1783132451Sroberto#endif
178454359Sroberto
1785182007Sroberto		/* Remember the socket family in fd_family structure */
1786182007Sroberto		fd_family[nbsock] = res->ai_family;
1787132451Sroberto
1788182007Sroberto		/*
1789182007Sroberto		 * bind the socket to the NTP port
1790182007Sroberto		 */
1791182007Sroberto		if (check_ntp_port_in_use) {
1792182007Sroberto			if (bind(fd[nbsock], res->ai_addr, SOCKLEN(res->ai_addr)) < 0) {
179354359Sroberto#ifndef SYS_WINNT
1794182007Sroberto				if (errno == EADDRINUSE)
179554359Sroberto#else
179654359Sroberto				if (WSAGetLastError() == WSAEADDRINUSE)
179754359Sroberto#endif /* SYS_WINNT */
1798182007Sroberto					netsyslog(LOG_ERR, "the NTP socket is in use, exiting");
179954359Sroberto				else
1800182007Sroberto					netsyslog(LOG_ERR, "bind() fails: %m");
1801182007Sroberto				exit(1);
1802182007Sroberto			}
180354359Sroberto		}
180454359Sroberto
180554359Sroberto#ifdef HAVE_POLL_H
1806182007Sroberto		fdmask[nbsock].fd = fd[nbsock];
1807182007Sroberto		fdmask[nbsock].events = POLLIN;
180854359Sroberto#else
1809182007Sroberto		FD_SET(fd[nbsock], &fdmask);
1810182007Sroberto		if (maxfd < fd[nbsock]+1) {
1811182007Sroberto			maxfd = fd[nbsock]+1;
1812182007Sroberto		}
181354359Sroberto#endif
181454359Sroberto
1815182007Sroberto		/*
1816182007Sroberto		 * set non-blocking,
1817182007Sroberto		 */
181854359Sroberto#ifndef SYS_WINNT
181954359Sroberto# ifdef SYS_VXWORKS
1820182007Sroberto		{
1821182007Sroberto		int on = TRUE;
182254359Sroberto
1823182007Sroberto		if (ioctl(fd[nbsock],FIONBIO, &on) == ERROR) {
1824182007Sroberto		  netsyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
1825182007Sroberto			exit(1);
1826182007Sroberto		}
1827182007Sroberto		}
182854359Sroberto# else /* not SYS_VXWORKS */
182954359Sroberto#  if defined(O_NONBLOCK)
1830182007Sroberto		if (fcntl(fd[nbsock], F_SETFL, O_NONBLOCK) < 0) {
1831182007Sroberto			netsyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
1832182007Sroberto			exit(1);
1833182007Sroberto			/*NOTREACHED*/
1834182007Sroberto		}
183554359Sroberto#  else /* not O_NONBLOCK */
183654359Sroberto#	if defined(FNDELAY)
1837182007Sroberto		if (fcntl(fd[nbsock], F_SETFL, FNDELAY) < 0) {
1838182007Sroberto			netsyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
1839182007Sroberto			exit(1);
1840182007Sroberto			/*NOTREACHED*/
1841182007Sroberto		}
184254359Sroberto#	else /* FNDELAY */
184354359Sroberto#	 include "Bletch: Need non blocking I/O"
184454359Sroberto#	endif /* FNDELAY */
184554359Sroberto#  endif /* not O_NONBLOCK */
184654359Sroberto# endif /* SYS_VXWORKS */
184754359Sroberto#else /* SYS_WINNT */
1848182007Sroberto		if (ioctlsocket(fd[nbsock], FIONBIO, (u_long *) &on) == SOCKET_ERROR) {
1849182007Sroberto			netsyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
1850182007Sroberto			exit(1);
1851182007Sroberto		}
1852182007Sroberto#endif /* SYS_WINNT */
1853182007Sroberto		nbsock++;
185454359Sroberto	}
1855182007Sroberto	freeaddrinfo(ressave);
185654359Sroberto}
185754359Sroberto
185854359Sroberto/*
185954359Sroberto * sendpkt - send a packet to the specified destination
186054359Sroberto */
186154359Srobertostatic void
186254359Srobertosendpkt(
1863132451Sroberto	struct sockaddr_storage *dest,
186454359Sroberto	struct pkt *pkt,
186554359Sroberto	int len
186654359Sroberto	)
186754359Sroberto{
1868182007Sroberto	int i;
186954359Sroberto	int cc;
1870182007Sroberto	SOCKET sock = INVALID_SOCKET;
187154359Sroberto
187254359Sroberto#ifdef SYS_WINNT
187354359Sroberto	DWORD err;
187454359Sroberto#endif /* SYS_WINNT */
187554359Sroberto
1876182007Sroberto	/* Find a local family compatible socket to send ntp packet to ntp server */
1877182007Sroberto	for(i = 0; (i < MAX_AF); i++) {
1878182007Sroberto		if(dest->ss_family == fd_family[i]) {
1879182007Sroberto			sock = fd[i];
1880182007Sroberto		break;
1881182007Sroberto		}
1882182007Sroberto	}
1883132451Sroberto
1884182007Sroberto	if ( sock == INVALID_SOCKET ) {
1885182007Sroberto		netsyslog(LOG_ERR, "cannot find family compatible socket to send ntp packet");
1886182007Sroberto		exit(1);
1887182007Sroberto		/*NOTREACHED*/
1888182007Sroberto	}
1889132451Sroberto
1890132451Sroberto	cc = sendto(sock, (char *)pkt, len, 0, (struct sockaddr *)dest,
1891132451Sroberto			SOCKLEN(dest));
1892132451Sroberto
1893182007Sroberto	if (cc == SOCKET_ERROR) {
189454359Sroberto#ifndef SYS_WINNT
189554359Sroberto		if (errno != EWOULDBLOCK && errno != ENOBUFS)
189654359Sroberto#else
189754359Sroberto		err = WSAGetLastError();
189854359Sroberto		if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
189954359Sroberto#endif /* SYS_WINNT */
1900182007Sroberto			netsyslog(LOG_ERR, "sendto(%s): %m", stohost(dest));
190154359Sroberto	}
190254359Sroberto}
190354359Sroberto
190454359Sroberto
190554359Sroberto/*
190654359Sroberto * input_handler - receive packets asynchronously
190754359Sroberto */
190854359Srobertovoid
190954359Srobertoinput_handler(void)
191054359Sroberto{
191154359Sroberto	register int n;
191254359Sroberto	register struct recvbuf *rb;
191354359Sroberto	struct timeval tvzero;
191454359Sroberto	int fromlen;
191554359Sroberto	l_fp ts;
1916182007Sroberto	int i;
191754359Sroberto#ifdef HAVE_POLL_H
1918132451Sroberto	struct pollfd fds[MAX_AF];
191954359Sroberto#else
192054359Sroberto	fd_set fds;
192154359Sroberto#endif
1922182007Sroberto	int fdc = 0;
192354359Sroberto
192454359Sroberto	/*
192554359Sroberto	 * Do a poll to see if we have data
192654359Sroberto	 */
192754359Sroberto	for (;;) {
192854359Sroberto		tvzero.tv_sec = tvzero.tv_usec = 0;
192954359Sroberto#ifdef HAVE_POLL_H
1930132451Sroberto		memcpy(fds, fdmask, sizeof(fdmask));
1931182007Sroberto		n = poll(fds, (unsigned int)nbsock, tvzero.tv_sec * 1000);
1932132451Sroberto
1933182007Sroberto		/*
1934182007Sroberto		 * Determine which socket received data
1935182007Sroberto		 */
1936132451Sroberto
1937182007Sroberto		for(i=0; i < nbsock; i++) {
1938182007Sroberto			if(fds[i].revents & POLLIN) {
1939182007Sroberto				fdc = fd[i];
1940182007Sroberto				break;
1941182007Sroberto			}
1942182007Sroberto		}
1943132451Sroberto
194454359Sroberto#else
1945132451Sroberto		fds = fdmask;
1946182007Sroberto		n = select(maxfd, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
1947132451Sroberto
1948182007Sroberto		/*
1949182007Sroberto		 * Determine which socket received data
1950182007Sroberto		 */
1951132451Sroberto
1952182007Sroberto		for(i=0; i < nbsock; i++) {
1953182007Sroberto			if(FD_ISSET(fd[i], &fds)) {
1954182007Sroberto				 fdc = fd[i];
1955182007Sroberto				 break;
1956182007Sroberto			}
1957182007Sroberto		}
1958132451Sroberto
195954359Sroberto#endif
196054359Sroberto
196154359Sroberto		/*
196254359Sroberto		 * If nothing to do, just return.  If an error occurred,
196354359Sroberto		 * complain and return.  If we've got some, freeze a
196454359Sroberto		 * timestamp.
196554359Sroberto		 */
196654359Sroberto		if (n == 0)
196754359Sroberto			return;
196854359Sroberto		else if (n == -1) {
196954359Sroberto			if (errno != EINTR)
1970132451Sroberto				netsyslog(LOG_ERR,
197154359Sroberto#ifdef HAVE_POLL_H
197254359Sroberto					"poll() error: %m"
197354359Sroberto#else
197454359Sroberto					"select() error: %m"
197554359Sroberto#endif
197654359Sroberto					);
197754359Sroberto			return;
197854359Sroberto		}
197954359Sroberto		get_systime(&ts);
198054359Sroberto
198154359Sroberto		/*
198254359Sroberto		 * Get a buffer and read the frame.  If we
198354359Sroberto		 * haven't got a buffer, or this is received
198454359Sroberto		 * on the wild card socket, just dump the packet.
198554359Sroberto		 */
198654359Sroberto		if (initializing || free_recvbuffs() == 0) {
198754359Sroberto			char buf[100];
198854359Sroberto
1989132451Sroberto
199054359Sroberto#ifndef SYS_WINNT
1991132451Sroberto			(void) read(fdc, buf, sizeof buf);
199254359Sroberto#else
199354359Sroberto			/* NT's _read does not operate on nonblocking sockets
199454359Sroberto			 * either recvfrom or ReadFile() has to be used here.
199554359Sroberto			 * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
199654359Sroberto			 * just to be different use recvfrom() here
199754359Sroberto			 */
1998132451Sroberto			recvfrom(fdc, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
199954359Sroberto#endif /* SYS_WINNT */
200054359Sroberto			continue;
200154359Sroberto		}
200254359Sroberto
200354359Sroberto		rb = get_free_recv_buffer();
200454359Sroberto
2005132451Sroberto		fromlen = sizeof(struct sockaddr_storage);
2006132451Sroberto		rb->recv_length = recvfrom(fdc, (char *)&rb->recv_pkt,
200754359Sroberto		   sizeof(rb->recv_pkt), 0,
200854359Sroberto		   (struct sockaddr *)&rb->recv_srcadr, &fromlen);
200954359Sroberto		if (rb->recv_length == -1) {
201054359Sroberto			freerecvbuf(rb);
201154359Sroberto			continue;
201254359Sroberto		}
201354359Sroberto
201454359Sroberto		/*
201554359Sroberto		 * Got one.  Mark how and when it got here,
201654359Sroberto		 * put it on the full list.
201754359Sroberto		 */
201854359Sroberto		rb->recv_time = ts;
201954359Sroberto		add_full_recv_buffer(rb);
202054359Sroberto	}
202154359Sroberto}
202254359Sroberto
202354359Sroberto
202454359Sroberto#if !defined SYS_WINNT && !defined SYS_CYGWIN32
202554359Sroberto/*
202654359Sroberto * adj_systime - do a big long slew of the system time
202754359Sroberto */
202854359Srobertostatic int
202954359Srobertol_adj_systime(
203054359Sroberto	l_fp *ts
203154359Sroberto	)
203254359Sroberto{
203354359Sroberto	struct timeval adjtv, oadjtv;
203454359Sroberto	int isneg = 0;
203554359Sroberto	l_fp offset;
203654359Sroberto#ifndef STEP_SLEW
203754359Sroberto	l_fp overshoot;
203854359Sroberto#endif
203954359Sroberto
204054359Sroberto	/*
204154359Sroberto	 * Take the absolute value of the offset
204254359Sroberto	 */
204354359Sroberto	offset = *ts;
204454359Sroberto	if (L_ISNEG(&offset)) {
204554359Sroberto		isneg = 1;
204654359Sroberto		L_NEG(&offset);
204754359Sroberto	}
204854359Sroberto
204954359Sroberto#ifndef STEP_SLEW
205054359Sroberto	/*
205154359Sroberto	 * Calculate the overshoot.  XXX N.B. This code *knows*
205254359Sroberto	 * ADJ_OVERSHOOT is 1/2.
205354359Sroberto	 */
205454359Sroberto	overshoot = offset;
205554359Sroberto	L_RSHIFTU(&overshoot);
205654359Sroberto	if (overshoot.l_ui != 0 || (overshoot.l_uf > ADJ_MAXOVERSHOOT)) {
205754359Sroberto		overshoot.l_ui = 0;
205854359Sroberto		overshoot.l_uf = ADJ_MAXOVERSHOOT;
205954359Sroberto	}
206054359Sroberto	L_ADD(&offset, &overshoot);
206154359Sroberto#endif
206254359Sroberto	TSTOTV(&offset, &adjtv);
206354359Sroberto
206454359Sroberto	if (isneg) {
206554359Sroberto		adjtv.tv_sec = -adjtv.tv_sec;
206654359Sroberto		adjtv.tv_usec = -adjtv.tv_usec;
206754359Sroberto	}
206854359Sroberto
206954359Sroberto	if (adjtv.tv_usec != 0 && !debug) {
207054359Sroberto		if (adjtime(&adjtv, &oadjtv) < 0) {
207154359Sroberto			msyslog(LOG_ERR, "Can't adjust the time of day: %m");
207254359Sroberto			return 0;
207354359Sroberto		}
207454359Sroberto	}
207554359Sroberto	return 1;
207654359Sroberto}
207754359Sroberto#endif /* SYS_WINNT */
207854359Sroberto
207954359Sroberto
208054359Sroberto/*
208154359Sroberto * This fuction is not the same as lib/systime step_systime!!!
208254359Sroberto */
208354359Srobertostatic int
208454359Srobertol_step_systime(
208554359Sroberto	l_fp *ts
208654359Sroberto	)
208754359Sroberto{
208854359Sroberto	double dtemp;
208954359Sroberto
209054359Sroberto#ifdef SLEWALWAYS
209154359Sroberto#ifdef STEP_SLEW
209254359Sroberto	l_fp ftmp;
209354359Sroberto	int isneg;
209454359Sroberto	int n;
209554359Sroberto
209654359Sroberto	if (debug) return 1;
209754359Sroberto	/*
209854359Sroberto	 * Take the absolute value of the offset
209954359Sroberto	 */
210054359Sroberto	ftmp = *ts;
210154359Sroberto	if (L_ISNEG(&ftmp)) {
210254359Sroberto		L_NEG(&ftmp);
210354359Sroberto		isneg = 1;
210454359Sroberto	} else
210554359Sroberto		isneg = 0;
210654359Sroberto
210754359Sroberto	if (ftmp.l_ui >= 3) {		/* Step it and slew - we might win */
210856746Sroberto		LFPTOD(ts, dtemp);
210956746Sroberto		n = step_systime(dtemp);
211054359Sroberto		if (!n)
211154359Sroberto			return n;
211254359Sroberto		if (isneg)
211354359Sroberto			ts->l_ui = ~0;
211454359Sroberto		else
211554359Sroberto			ts->l_ui = ~0;
211654359Sroberto	}
211754359Sroberto	/*
211854359Sroberto	 * Just add adjustment into the current offset.  The update
211954359Sroberto	 * routine will take care of bringing the system clock into
212054359Sroberto	 * line.
212154359Sroberto	 */
212254359Sroberto#endif
212354359Sroberto	if (debug)
212454359Sroberto		return 1;
212554359Sroberto#ifdef FORCE_NTPDATE_STEP
212654359Sroberto	LFPTOD(ts, dtemp);
212754359Sroberto	return step_systime(dtemp);
212854359Sroberto#else
212954359Sroberto	l_adj_systime(ts);
213054359Sroberto	return 1;
213154359Sroberto#endif
2132182007Sroberto#else /* SLEWALWAYS */
213354359Sroberto	if (debug)
213454359Sroberto		return 1;
213554359Sroberto	LFPTOD(ts, dtemp);
213654359Sroberto	return step_systime(dtemp);
213754359Sroberto#endif	/* SLEWALWAYS */
213854359Sroberto}
213954359Sroberto
214054359Sroberto
214154359Sroberto/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
214254359Sroberto/*
214354359Sroberto * printserver - print detail information for a server
214454359Sroberto */
214554359Srobertostatic void
214654359Srobertoprintserver(
214754359Sroberto	register struct server *pp,
214854359Sroberto	FILE *fp
214954359Sroberto	)
215054359Sroberto{
215154359Sroberto	register int i;
215254359Sroberto	char junk[5];
215354359Sroberto	char *str;
215454359Sroberto
215554359Sroberto	if (!debug) {
215654359Sroberto		(void) fprintf(fp, "server %s, stratum %d, offset %s, delay %s\n",
2157132451Sroberto				   stoa(&pp->srcadr), pp->stratum,
215854359Sroberto				   lfptoa(&pp->offset, 6), fptoa((s_fp)pp->delay, 5));
215954359Sroberto		return;
216054359Sroberto	}
216154359Sroberto
216254359Sroberto	(void) fprintf(fp, "server %s, port %d\n",
2163132451Sroberto			   stoa(&pp->srcadr), ntohs(((struct sockaddr_in*)&(pp->srcadr))->sin_port));
216454359Sroberto
216554359Sroberto	(void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
216654359Sroberto			   pp->stratum, pp->precision,
216754359Sroberto			   pp->leap & 0x2 ? '1' : '0',
216854359Sroberto			   pp->leap & 0x1 ? '1' : '0',
216954359Sroberto			   pp->trust);
217054359Sroberto
217154359Sroberto	if (pp->stratum == 1) {
217254359Sroberto		junk[4] = 0;
217354359Sroberto		memmove(junk, (char *)&pp->refid, 4);
217454359Sroberto		str = junk;
217554359Sroberto	} else {
2176132451Sroberto		str = stoa(&pp->srcadr);
217754359Sroberto	}
217854359Sroberto	(void) fprintf(fp,
217954359Sroberto			   "refid [%s], delay %s, dispersion %s\n",
218054359Sroberto			   str, fptoa((s_fp)pp->delay, 5),
218154359Sroberto			   ufptoa(pp->dispersion, 5));
218254359Sroberto
218354359Sroberto	(void) fprintf(fp, "transmitted %d, in filter %d\n",
218454359Sroberto			   pp->xmtcnt, pp->filter_nextpt);
218554359Sroberto
218654359Sroberto	(void) fprintf(fp, "reference time:    %s\n",
218754359Sroberto			   prettydate(&pp->reftime));
218854359Sroberto	(void) fprintf(fp, "originate timestamp: %s\n",
218954359Sroberto			   prettydate(&pp->org));
219054359Sroberto	(void) fprintf(fp, "transmit timestamp:  %s\n",
219154359Sroberto			   prettydate(&pp->xmt));
219254359Sroberto
219354359Sroberto	(void) fprintf(fp, "filter delay: ");
219454359Sroberto	for (i = 0; i < NTP_SHIFT; i++) {
219554359Sroberto		(void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
219654359Sroberto		if (i == (NTP_SHIFT>>1)-1)
219754359Sroberto			(void) fprintf(fp, "\n        ");
219854359Sroberto	}
219954359Sroberto	(void) fprintf(fp, "\n");
220054359Sroberto
220154359Sroberto	(void) fprintf(fp, "filter offset:");
220254359Sroberto	for (i = 0; i < PEER_SHIFT; i++) {
220354359Sroberto		(void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
220454359Sroberto		if (i == (PEER_SHIFT>>1)-1)
220554359Sroberto			(void) fprintf(fp, "\n        ");
220654359Sroberto	}
220754359Sroberto	(void) fprintf(fp, "\n");
220854359Sroberto
220954359Sroberto	(void) fprintf(fp, "delay %s, dispersion %s\n",
221054359Sroberto			   fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
221154359Sroberto
221254359Sroberto	(void) fprintf(fp, "offset %s\n\n",
221354359Sroberto			   lfptoa(&pp->offset, 6));
221454359Sroberto}
221554359Sroberto
221654359Sroberto#if !defined(HAVE_VSPRINTF)
221754359Srobertoint
221854359Srobertovsprintf(
221954359Sroberto	char *str,
222054359Sroberto	const char *fmt,
222154359Sroberto	va_list ap
222254359Sroberto	)
222354359Sroberto{
222454359Sroberto	FILE f;
222554359Sroberto	int len;
222654359Sroberto
222754359Sroberto	f._flag = _IOWRT+_IOSTRG;
222854359Sroberto	f._ptr = str;
222954359Sroberto	f._cnt = 32767;
223054359Sroberto	len = _doprnt(fmt, ap, &f);
223154359Sroberto	*f._ptr = 0;
223254359Sroberto	return (len);
223354359Sroberto}
223454359Sroberto#endif
223554359Sroberto
223654359Sroberto#if 0
223754359Sroberto/* override function in library since SA_RESTART makes ALL syscalls restart */
223854359Sroberto#ifdef SA_RESTART
223954359Srobertovoid
224054359Srobertosignal_no_reset(
224154359Sroberto	int sig,
224254359Sroberto	void (*func)()
224354359Sroberto	)
224454359Sroberto{
224554359Sroberto	int n;
224654359Sroberto	struct sigaction vec;
224754359Sroberto
224854359Sroberto	vec.sa_handler = func;
224954359Sroberto	sigemptyset(&vec.sa_mask);
225054359Sroberto	vec.sa_flags = 0;
225154359Sroberto
225254359Sroberto	while (1)
225354359Sroberto	{
225454359Sroberto		n = sigaction(sig, &vec, NULL);
225554359Sroberto		if (n == -1 && errno == EINTR)
225654359Sroberto			continue;
225754359Sroberto		break;
225854359Sroberto	}
225954359Sroberto	if (n == -1)
226054359Sroberto	{
226154359Sroberto		perror("sigaction");
226254359Sroberto		exit(1);
226354359Sroberto	}
226454359Sroberto}
226554359Sroberto#endif
226654359Sroberto#endif
226754359Sroberto
226854359Sroberto#ifdef HAVE_NETINFO
226954359Srobertostatic ni_namelist *
227054359Srobertogetnetinfoservers(void)
227154359Sroberto{
227254359Sroberto	ni_status status;
227354359Sroberto	void *domain;
227454359Sroberto	ni_id confdir;
227554359Sroberto	ni_namelist *namelist = (ni_namelist*)malloc(sizeof(ni_namelist));
227654359Sroberto
227754359Sroberto	/* Find a time server in NetInfo */
227854359Sroberto	if ((status = ni_open(NULL, ".", &domain)) != NI_OK) return NULL;
227954359Sroberto
228054359Sroberto	while (status = ni_pathsearch(domain, &confdir, NETINFO_CONFIG_DIR) == NI_NODIR) {
228154359Sroberto		void *next_domain;
228254359Sroberto		if (ni_open(domain, "..", &next_domain) != NI_OK) break;
228354359Sroberto		ni_free(domain);
228454359Sroberto		domain = next_domain;
228554359Sroberto	}
228654359Sroberto	if (status != NI_OK) return NULL;
228754359Sroberto
228854359Sroberto	NI_INIT(namelist);
228954359Sroberto	if (ni_lookupprop(domain, &confdir, "server", namelist) != NI_OK) {
229054359Sroberto		ni_namelist_free(namelist);
229154359Sroberto		free(namelist);
229254359Sroberto		return NULL;
229354359Sroberto	}
229454359Sroberto
229554359Sroberto	return(namelist);
229654359Sroberto}
229754359Sroberto#endif
2298182007Sroberto
2299182007Sroberto#ifdef SYS_WINNT
2300182007Srobertoisc_boolean_t ntp_port_inuse(int af, u_short port)
2301182007Sroberto{
2302182007Sroberto	/*
2303182007Sroberto	 * Check if NTP socket is already in use on this system
2304182007Sroberto	 * This is only for Windows Systems, as they tend not to fail on the real bind() below
2305182007Sroberto	 */
2306182007Sroberto
2307182007Sroberto	SOCKET checksocket;
2308182007Sroberto	struct sockaddr_in checkservice;
2309182007Sroberto	checksocket = socket(af, SOCK_DGRAM, 0);
2310182007Sroberto	if (checksocket == INVALID_SOCKET) {
2311182007Sroberto		return (ISC_TRUE);
2312182007Sroberto	}
2313182007Sroberto
2314182007Sroberto	checkservice.sin_family = (short) AF_INET;
2315182007Sroberto	checkservice.sin_addr.s_addr = INADDR_LOOPBACK;
2316182007Sroberto	checkservice.sin_port = htons(port);
2317182007Sroberto
2318182007Sroberto	if (bind(checksocket, (struct sockaddr *)&checkservice,
2319182007Sroberto		sizeof(checkservice)) == SOCKET_ERROR) {
2320182007Sroberto		if ( WSAGetLastError() == WSAEADDRINUSE ){
2321182007Sroberto			closesocket(checksocket);
2322182007Sroberto			return (ISC_TRUE);
2323182007Sroberto		}
2324182007Sroberto	}
2325182007Sroberto	closesocket(checksocket);
2326182007Sroberto	return (ISC_FALSE);
2327182007Sroberto}
2328182007Sroberto#endif
2329