ntpdate.c revision 132451
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
49132451Sroberto#include <arpa/inet.h>
50132451Sroberto
51132451Sroberto#ifdef __QNXNTO__
52132451Sroberto# include "adjtime.h"
53132451Sroberto#endif
54132451Sroberto
5554359Sroberto#ifdef SYS_VXWORKS
5654359Sroberto# include "ioLib.h"
5754359Sroberto# include "sockLib.h"
5854359Sroberto# include "timers.h"
5954359Sroberto
6054359Sroberto/* select wants a zero structure ... */
6154359Srobertostruct timeval timeout = {0,0};
6254359Sroberto#else
6354359Srobertostruct timeval timeout = {60,0};
6454359Sroberto#endif
6554359Sroberto
66132451Sroberto#ifdef HAVE_NETINFO
67132451Sroberto#include <netinfo/ni.h>
68132451Sroberto#endif
69132451Sroberto
7054359Sroberto#include "recvbuff.h"
7154359Sroberto
7254359Sroberto#ifdef SYS_WINNT
73132451Sroberto#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
74132451Sroberto#define EAFNOSUPPORT    WSAEAFNOSUPPORT
75132451Sroberto#define EPFNOSUPPORT    WSAEPFNOSUPPORT
76132451Sroberto#define TARGET_RESOLUTION 1  /* Try for 1-millisecond accuracy
7754359Sroberto				on Windows NT timers. */
7854359Sroberto#pragma comment(lib, "winmm")
7954359Sroberto#endif /* SYS_WINNT */
8054359Sroberto
8154359Sroberto/*
8254359Sroberto * Scheduling priority we run at
8354359Sroberto */
8454359Sroberto#ifndef SYS_VXWORKS
8554359Sroberto# define	NTPDATE_PRIO	(-12)
8654359Sroberto#else
8754359Sroberto# define	NTPDATE_PRIO	(100)
8854359Sroberto#endif
8954359Sroberto
9054359Sroberto#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
9154359Sroberto/* POSIX TIMERS - vxWorks doesn't have itimer - casey */
9254359Srobertostatic timer_t ntpdate_timerid;
9354359Sroberto#endif
9454359Sroberto
9554359Sroberto/*
9654359Sroberto * Compatibility stuff for Version 2
9754359Sroberto */
9854359Sroberto#define NTP_MAXSKW	0x28f	/* 0.01 sec in fp format */
9954359Sroberto#define NTP_MINDIST 0x51f	/* 0.02 sec in fp format */
10054359Sroberto#define PEER_MAXDISP	(64*FP_SECOND)	/* maximum dispersion (fp 64) */
10154359Sroberto#define NTP_INFIN	15	/* max stratum, infinity a la Bellman-Ford */
10254359Sroberto#define NTP_MAXWGT	(8*FP_SECOND)	/* maximum select weight 8 seconds */
10354359Sroberto#define NTP_MAXLIST 5	/* maximum select list size */
10454359Sroberto#define PEER_SHIFT	8	/* 8 suitable for crystal time base */
10554359Sroberto
10654359Sroberto/*
10754359Sroberto * Debugging flag
10854359Sroberto */
10954359Srobertovolatile int debug = 0;
11054359Sroberto
11154359Sroberto/*
11254359Sroberto * File descriptor masks etc. for call to select
11354359Sroberto */
114132451Sroberto
115132451Srobertoint ai_fam_templ;
116132451Srobertoint nbsock;
117132451SrobertoSOCKET fd[MAX_AF];	/* support up to 2 sockets */
118132451Srobertoint fd_family[MAX_AF];	/* to remember the socket family */
11954359Sroberto#ifdef HAVE_POLL_H
120132451Srobertostruct pollfd fdmask[MAX_AF];
12154359Sroberto#else
12254359Srobertofd_set fdmask;
123132451Srobertoint maxfd;
12454359Sroberto#endif
125132451Srobertoint polltest = 0;
12654359Sroberto
12754359Sroberto/*
12854359Sroberto * Initializing flag.  All async routines watch this and only do their
12954359Sroberto * thing when it is clear.
13054359Sroberto */
13154359Srobertoint initializing = 1;
13254359Sroberto
13354359Sroberto/*
13454359Sroberto * Alarm flag.	Set when an alarm occurs
13554359Sroberto */
13654359Srobertovolatile int alarm_flag = 0;
13754359Sroberto
13854359Sroberto/*
13954359Sroberto * Simple query flag.
14054359Sroberto */
14154359Srobertoint simple_query = 0;
14254359Sroberto
14354359Sroberto/*
14454359Sroberto * Unpriviledged port flag.
14554359Sroberto */
14654359Srobertoint unpriv_port = 0;
14754359Sroberto
14854359Sroberto/*
14954359Sroberto * Time to spend measuring drift rate
15054359Sroberto */
15154359Srobertoint rate = 0;
15254359Sroberto
15354359Sroberto/*
15454359Sroberto * Program name.
15554359Sroberto */
15654359Srobertochar *progname;
15754359Sroberto
15854359Sroberto/*
15954359Sroberto * Systemwide parameters and flags
16054359Sroberto */
16154359Srobertoint sys_samples = DEFSAMPLES;	/* number of samples/server */
16254359Srobertou_long sys_timeout = DEFTIMEOUT; /* timeout time, in TIMER_HZ units */
16356746Srobertostruct server *sys_servers;	/* the server list */
16454359Srobertoint sys_numservers = 0; 	/* number of servers to poll */
16554359Srobertoint sys_authenticate = 0;	/* true when authenticating */
16654359Srobertou_int32 sys_authkey = 0;	/* set to authentication key in use */
16754359Srobertou_long sys_authdelay = 0;	/* authentication delay */
16854359Srobertoint sys_version = NTP_VERSION;	/* version to poll with */
16954359Sroberto
17054359Sroberto/*
17154359Sroberto * The current internal time
17254359Sroberto */
17354359Srobertou_long current_time = 0;
17454359Sroberto
17554359Sroberto/*
17654359Sroberto * Counter for keeping track of completed servers
17754359Sroberto */
17854359Srobertoint complete_servers = 0;
17954359Sroberto
18054359Sroberto/*
18154359Sroberto * File of encryption keys
18254359Sroberto */
18354359Sroberto
18454359Sroberto#ifndef KEYFILE
18554359Sroberto# ifndef SYS_WINNT
18654359Sroberto#define KEYFILE 	"/etc/ntp.keys"
18754359Sroberto# else
18854359Sroberto#define KEYFILE 	"%windir%\\ntp.keys"
18954359Sroberto# endif /* SYS_WINNT */
19054359Sroberto#endif /* KEYFILE */
19154359Sroberto
19254359Sroberto#ifndef SYS_WINNT
19354359Srobertoconst char *key_file = KEYFILE;
19454359Sroberto#else
19554359Srobertochar key_file_storage[MAX_PATH+1], *key_file ;
19654359Sroberto#endif	 /* SYS_WINNT */
19754359Sroberto
19854359Sroberto/*
19954359Sroberto * Miscellaneous flags
20054359Sroberto */
20154359Srobertoint verbose = 0;
20254359Srobertoint always_step = 0;
20354359Srobertoint never_step = 0;
20454359Sroberto
20554359Srobertoint 	ntpdatemain P((int, char **));
206132451Sroberto
20754359Srobertostatic	void	transmit	P((struct server *));
20854359Srobertostatic	void	receive 	P((struct recvbuf *));
20954359Srobertostatic	void	server_data P((struct server *, s_fp, l_fp *, u_fp));
21054359Srobertostatic	void	clock_filter	P((struct server *));
21154359Srobertostatic	struct server *clock_select P((void));
21254359Srobertostatic	int clock_adjust	P((void));
21354359Srobertostatic	void	addserver	P((char *));
214132451Srobertostatic	struct server *findserver P((struct sockaddr_storage *));
21554359Sroberto		void	timer		P((void));
21654359Srobertostatic	void	init_alarm	P((void));
21754359Sroberto#ifndef SYS_WINNT
21854359Srobertostatic	RETSIGTYPE alarming P((int));
21954359Sroberto#endif /* SYS_WINNT */
22054359Srobertostatic	void	init_io 	P((void));
221132451Srobertostatic	void	sendpkt 	P((struct sockaddr_storage *, struct pkt *, int));
22254359Srobertovoid	input_handler	P((void));
22354359Sroberto
22454359Srobertostatic	int l_adj_systime	P((l_fp *));
22554359Srobertostatic	int l_step_systime	P((l_fp *));
22654359Sroberto
22754359Srobertostatic	void	printserver P((struct server *, FILE *));
22854359Sroberto
22954359Sroberto#ifdef SYS_WINNT
23054359Srobertoint 	on = 1;
23154359SrobertoWORD	wVersionRequested;
23254359SrobertoWSADATA wsaData;
23354359SrobertoHANDLE	TimerThreadHandle = NULL;
23454359Sroberto#endif /* SYS_WINNT */
23554359Sroberto
23654359Sroberto#ifdef NO_MAIN_ALLOWED
23754359SrobertoCALL(ntpdate,"ntpdate",ntpdatemain);
23854359Sroberto
23954359Srobertovoid clear_globals()
24054359Sroberto{
24154359Sroberto  /*
24254359Sroberto   * Debugging flag
24354359Sroberto   */
24454359Sroberto  debug = 0;
24554359Sroberto
24654359Sroberto  ntp_optind = 0;
24754359Sroberto  /*
24854359Sroberto   * Initializing flag.  All async routines watch this and only do their
24954359Sroberto   * thing when it is clear.
25054359Sroberto   */
25154359Sroberto  initializing = 1;
25254359Sroberto
25354359Sroberto  /*
25454359Sroberto   * Alarm flag.  Set when an alarm occurs
25554359Sroberto   */
25654359Sroberto  alarm_flag = 0;
25754359Sroberto
25854359Sroberto  /*
25954359Sroberto   * Simple query flag.
26054359Sroberto   */
26154359Sroberto  simple_query = 0;
26254359Sroberto
26354359Sroberto  /*
26454359Sroberto   * Unpriviledged port flag.
26554359Sroberto   */
26654359Sroberto  unpriv_port = 0;
26754359Sroberto
26854359Sroberto  /*
26954359Sroberto   * Time to spend measuring drift rate
27054359Sroberto   */
27154359Sroberto  rate = 0;
27254359Sroberto  /*
27354359Sroberto   * Systemwide parameters and flags
27454359Sroberto   */
27554359Sroberto  sys_numservers = 0;	  /* number of servers to poll */
27654359Sroberto  sys_authenticate = 0;   /* true when authenticating */
27754359Sroberto  sys_authkey = 0;	   /* set to authentication key in use */
27854359Sroberto  sys_authdelay = 0;   /* authentication delay */
27954359Sroberto  sys_version = NTP_VERSION;  /* version to poll with */
28054359Sroberto
28154359Sroberto  /*
28254359Sroberto   * The current internal time
28354359Sroberto   */
28454359Sroberto  current_time = 0;
28554359Sroberto
28654359Sroberto  /*
28754359Sroberto   * Counter for keeping track of completed servers
28854359Sroberto   */
28954359Sroberto  complete_servers = 0;
29054359Sroberto  verbose = 0;
29154359Sroberto  always_step = 0;
29254359Sroberto  never_step = 0;
29354359Sroberto}
29454359Sroberto#endif
29554359Sroberto
29654359Sroberto#ifdef HAVE_NETINFO
29754359Srobertostatic ni_namelist *getnetinfoservers P((void));
29854359Sroberto#endif
29954359Sroberto
30054359Sroberto/*
30154359Sroberto * Main program.  Initialize us and loop waiting for I/O and/or
30254359Sroberto * timer expiries.
30354359Sroberto */
30454359Sroberto#ifndef NO_MAIN_ALLOWED
30554359Srobertoint
30654359Srobertomain(
30754359Sroberto	int argc,
30854359Sroberto	char *argv[]
30954359Sroberto	)
31054359Sroberto{
31154359Sroberto	return ntpdatemain (argc, argv);
31254359Sroberto}
31354359Sroberto#endif /* NO_MAIN_ALLOWED */
31454359Sroberto
31554359Srobertoint
31654359Srobertontpdatemain (
31754359Sroberto	int argc,
31854359Sroberto	char *argv[]
31954359Sroberto	)
32054359Sroberto{
32154359Sroberto	int was_alarmed;
32254359Sroberto	struct recvbuf *rbuflist;
32354359Sroberto	struct recvbuf *rbuf;
32454359Sroberto	l_fp tmp;
32554359Sroberto	int errflg;
32654359Sroberto	int c;
327132451Sroberto        int nfound;
328132451Sroberto
32954359Sroberto#ifdef HAVE_NETINFO
33054359Sroberto	ni_namelist *netinfoservers;
33154359Sroberto#endif
33254359Sroberto#ifdef SYS_WINNT
33354359Sroberto	HANDLE process_handle;
33454359Sroberto
33554359Sroberto	wVersionRequested = MAKEWORD(1,1);
33654359Sroberto	if (WSAStartup(wVersionRequested, &wsaData)) {
337132451Sroberto		netsyslog(LOG_ERR, "No useable winsock.dll: %m");
33854359Sroberto		exit(1);
33954359Sroberto	}
34054359Sroberto
34154359Sroberto	key_file = key_file_storage;
34254359Sroberto
34354359Sroberto	if (!ExpandEnvironmentStrings(KEYFILE, key_file, MAX_PATH))
34454359Sroberto	{
34554359Sroberto		msyslog(LOG_ERR, "ExpandEnvironmentStrings(KEYFILE) failed: %m\n");
34654359Sroberto	}
34754359Sroberto#endif /* SYS_WINNT */
34854359Sroberto
34954359Sroberto#ifdef NO_MAIN_ALLOWED
35054359Sroberto	clear_globals();
35154359Sroberto#endif
35254359Sroberto
35354359Sroberto	errflg = 0;
35454359Sroberto	progname = argv[0];
35554359Sroberto	syslogit = 0;
35654359Sroberto
35754359Sroberto	/*
35854359Sroberto	 * Decode argument list
35954359Sroberto	 */
360132451Sroberto	while ((c = ntp_getopt(argc, argv, "46a:bBde:k:o:p:qr:st:uv")) != EOF)
36154359Sroberto		switch (c)
36254359Sroberto		{
363132451Sroberto		case '4':
364132451Sroberto			ai_fam_templ = AF_INET;
365132451Sroberto			break;
366132451Sroberto		case '6':
367132451Sroberto			ai_fam_templ = AF_INET6;
368132451Sroberto			break;
36954359Sroberto		case 'a':
37054359Sroberto			c = atoi(ntp_optarg);
37154359Sroberto			sys_authenticate = 1;
37254359Sroberto			sys_authkey = c;
37354359Sroberto			break;
37454359Sroberto		case 'b':
37554359Sroberto			always_step++;
37654359Sroberto			never_step = 0;
37754359Sroberto			break;
37854359Sroberto		case 'B':
37954359Sroberto			never_step++;
38054359Sroberto			always_step = 0;
38154359Sroberto			break;
38254359Sroberto		case 'd':
38354359Sroberto			++debug;
38454359Sroberto			break;
38554359Sroberto		case 'e':
38654359Sroberto			if (!atolfp(ntp_optarg, &tmp)
38754359Sroberto			|| tmp.l_ui != 0) {
38854359Sroberto				(void) fprintf(stderr,
38954359Sroberto					   "%s: encryption delay %s is unlikely\n",
39054359Sroberto					   progname, ntp_optarg);
39154359Sroberto				errflg++;
39254359Sroberto			} else {
39354359Sroberto				sys_authdelay = tmp.l_uf;
39454359Sroberto			}
39554359Sroberto			break;
39654359Sroberto		case 'k':
39754359Sroberto			key_file = ntp_optarg;
39854359Sroberto			break;
39954359Sroberto		case 'o':
40054359Sroberto			sys_version = atoi(ntp_optarg);
40154359Sroberto			break;
40254359Sroberto		case 'p':
40354359Sroberto			c = atoi(ntp_optarg);
40454359Sroberto			if (c <= 0 || c > NTP_SHIFT) {
40554359Sroberto				(void) fprintf(stderr,
40654359Sroberto					   "%s: number of samples (%d) is invalid\n",
40754359Sroberto					   progname, c);
40854359Sroberto				errflg++;
40954359Sroberto			} else {
41054359Sroberto				sys_samples = c;
41154359Sroberto			}
41254359Sroberto			break;
41354359Sroberto		case 'q':
41454359Sroberto			simple_query = 1;
41554359Sroberto			break;
41654359Sroberto		case 'r':
41754359Sroberto			c = atoi(ntp_optarg);
41854359Sroberto			if (c <= 0 || c > (60 * 60)) {
41954359Sroberto				(void) fprintf(stderr,
42054359Sroberto					   "%s: rate (%d) is invalid: 0 - %d\n",
42154359Sroberto					   progname, c, (60 * 60));
42254359Sroberto				errflg++;
42354359Sroberto			} else {
42454359Sroberto				rate = c;
42554359Sroberto			}
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,
458132451Sroberto		    "usage: %s [-46bBdqsuv] [-a key#] [-e delay] [-k file] [-p samples] [-o version#] [-r rate] [-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];
46654359Sroberto		setvbuf(stdout, buf, _IOLBF, BUFSIZ);
46754359Sroberto#else
46854359Sroberto		setlinebuf(stdout);
46954359Sroberto#endif
47054359Sroberto	}
47154359Sroberto
47254359Sroberto	/*
47354359Sroberto	 * Logging.  Open the syslog if we have to
47454359Sroberto	 */
47554359Sroberto	if (syslogit) {
47654359Sroberto#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
47754359Sroberto# ifndef	LOG_DAEMON
47854359Sroberto		openlog("ntpdate", LOG_PID);
47954359Sroberto# else
48054359Sroberto
48154359Sroberto#  ifndef	LOG_NTP
48254359Sroberto#	define	LOG_NTP LOG_DAEMON
48354359Sroberto#  endif
48454359Sroberto		openlog("ntpdate", LOG_PID | LOG_NDELAY, LOG_NTP);
48554359Sroberto		if (debug)
48654359Sroberto			setlogmask(LOG_UPTO(LOG_DEBUG));
48754359Sroberto		else
48854359Sroberto			setlogmask(LOG_UPTO(LOG_INFO));
48954359Sroberto# endif /* LOG_DAEMON */
49054359Sroberto#endif	/* SYS_WINNT */
49154359Sroberto	}
49254359Sroberto
49354359Sroberto	if (debug || verbose)
49454359Sroberto		msyslog(LOG_NOTICE, "%s", Version);
49554359Sroberto
49654359Sroberto	/*
49754359Sroberto	 * Add servers we are going to be polling
49854359Sroberto	 */
49954359Sroberto#ifdef HAVE_NETINFO
50082498Sroberto	netinfoservers = getnetinfoservers();
50154359Sroberto#endif
50254359Sroberto
50354359Sroberto	for ( ; ntp_optind < argc; ntp_optind++)
50454359Sroberto		addserver(argv[ntp_optind]);
50554359Sroberto
50654359Sroberto#ifdef HAVE_NETINFO
50754359Sroberto	if (netinfoservers) {
50854359Sroberto		if ( netinfoservers->ni_namelist_len &&
50954359Sroberto		    *netinfoservers->ni_namelist_val ) {
51054359Sroberto			u_int servercount = 0;
51154359Sroberto			while (servercount < netinfoservers->ni_namelist_len) {
51254359Sroberto				if (debug) msyslog(LOG_DEBUG,
51354359Sroberto						   "Adding time server %s from NetInfo configuration.",
51454359Sroberto						   netinfoservers->ni_namelist_val[servercount]);
51554359Sroberto				addserver(netinfoservers->ni_namelist_val[servercount++]);
51654359Sroberto			}
51754359Sroberto		}
51854359Sroberto		ni_namelist_free(netinfoservers);
51954359Sroberto		free(netinfoservers);
52054359Sroberto	}
52154359Sroberto#endif
52254359Sroberto
52354359Sroberto	if (sys_numservers == 0) {
52454359Sroberto		msyslog(LOG_ERR, "no servers can be used, exiting");
52554359Sroberto		exit(1);
52654359Sroberto	}
52754359Sroberto
52854359Sroberto	/*
52954359Sroberto	 * Initialize the time of day routines and the I/O subsystem
53054359Sroberto	 */
53154359Sroberto	if (sys_authenticate) {
53254359Sroberto		init_auth();
53354359Sroberto		if (!authreadkeys(key_file)) {
53482498Sroberto			msyslog(LOG_ERR, "no key file <%s>, exiting", key_file);
53554359Sroberto			exit(1);
53654359Sroberto		}
53782498Sroberto		authtrust(sys_authkey, 1);
53854359Sroberto		if (!authistrusted(sys_authkey)) {
53954359Sroberto			char buf[10];
54054359Sroberto
54154359Sroberto			(void) sprintf(buf, "%lu", (unsigned long)sys_authkey);
54254359Sroberto			msyslog(LOG_ERR, "authentication key %s unknown", buf);
54354359Sroberto			exit(1);
54454359Sroberto		}
54554359Sroberto	}
54654359Sroberto	init_io();
54754359Sroberto	init_alarm();
54854359Sroberto
54954359Sroberto	/*
55054359Sroberto	 * Set the priority.
55154359Sroberto	 */
55254359Sroberto#ifdef SYS_VXWORKS
55354359Sroberto	taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
55454359Sroberto#endif
55554359Sroberto#if defined(HAVE_ATT_NICE)
55654359Sroberto	nice (NTPDATE_PRIO);
55754359Sroberto#endif
55854359Sroberto#if defined(HAVE_BSD_NICE)
55954359Sroberto	(void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
56054359Sroberto#endif
56154359Sroberto#ifdef SYS_WINNT
56254359Sroberto	process_handle = GetCurrentProcess();
56354359Sroberto	if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
56454359Sroberto		msyslog(LOG_ERR, "SetPriorityClass failed: %m");
56554359Sroberto	}
56654359Sroberto#endif /* SYS_WINNT */
56754359Sroberto
568132451Sroberto
569132451Sroberto
57054359Sroberto	initializing = 0;
57154359Sroberto	was_alarmed = 0;
57254359Sroberto	rbuflist = (struct recvbuf *)0;
573132451Sroberto
57454359Sroberto	while (complete_servers < sys_numservers) {
57554359Sroberto#ifdef HAVE_POLL_H
576132451Sroberto                struct pollfd* rdfdes;
577132451Sroberto                rdfdes = fdmask;
57854359Sroberto#else
57954359Sroberto		fd_set rdfdes;
580132451Sroberto                rdfdes = fdmask;
58154359Sroberto#endif
58254359Sroberto
58354359Sroberto		if (alarm_flag) {		/* alarmed? */
58454359Sroberto			was_alarmed = 1;
58554359Sroberto			alarm_flag = 0;
58654359Sroberto		}
58754359Sroberto		rbuflist = getrecvbufs();	/* get received buffers */
58854359Sroberto
58954359Sroberto		if (!was_alarmed && rbuflist == (struct recvbuf *)0) {
59054359Sroberto			/*
59154359Sroberto			 * Nothing to do.	 Wait for something.
59254359Sroberto			 */
59354359Sroberto#ifdef HAVE_POLL_H
594132451Sroberto                        nfound = poll(rdfdes, (unsigned int)nbsock, timeout.tv_sec * 1000);
595132451Sroberto
59654359Sroberto#else
597132451Sroberto                        nfound = select(maxfd, &rdfdes, (fd_set *)0,
59854359Sroberto					(fd_set *)0, &timeout);
59954359Sroberto#endif
60054359Sroberto			if (nfound > 0)
60154359Sroberto				input_handler();
60254359Sroberto			else if (
60354359Sroberto#ifndef SYS_WINNT
60454359Sroberto				nfound == -1
60554359Sroberto#else
60654359Sroberto				nfound == SOCKET_ERROR
60754359Sroberto#endif /* SYS_WINNT */
60854359Sroberto				) {
60954359Sroberto#ifndef SYS_WINNT
61054359Sroberto				if (errno != EINTR)
61154359Sroberto#endif
612132451Sroberto					netsyslog(LOG_ERR,
61354359Sroberto#ifdef HAVE_POLL_H
61454359Sroberto						"poll() error: %m"
61554359Sroberto#else
61654359Sroberto						"select() error: %m"
61754359Sroberto#endif
61854359Sroberto						);
61954359Sroberto			} else {
62054359Sroberto#ifndef SYS_VXWORKS
621132451Sroberto				netsyslog(LOG_DEBUG,
62254359Sroberto#ifdef HAVE_POLL_H
62354359Sroberto					"poll(): nfound = %d, error: %m",
62454359Sroberto#else
62554359Sroberto					"select(): nfound = %d, error: %m",
62654359Sroberto#endif
62754359Sroberto					nfound);
62854359Sroberto#endif
62954359Sroberto			}
63054359Sroberto			if (alarm_flag) {		/* alarmed? */
63154359Sroberto				was_alarmed = 1;
63254359Sroberto				alarm_flag = 0;
63354359Sroberto			}
63454359Sroberto			rbuflist = getrecvbufs();	/* get received buffers */
63554359Sroberto		}
63654359Sroberto
63754359Sroberto		/*
63854359Sroberto		 * Out here, signals are unblocked.  Call receive
63954359Sroberto		 * procedure for each incoming packet.
64054359Sroberto		 */
64154359Sroberto		while (rbuflist != (struct recvbuf *)0) {
64254359Sroberto			rbuf = rbuflist;
64354359Sroberto			rbuflist = rbuf->next;
64454359Sroberto			receive(rbuf);
64554359Sroberto			freerecvbuf(rbuf);
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.
67954359Sroberto *		  This is called by the timeout routine and by the receive
68054359Sroberto *		  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	/*
71354359Sroberto	 * 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)
782132451Sroberto                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));
1063106163Sroberto			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));
1068106163Sroberto			continue;   /* stratum no good */
1069106163Sroberto		}
107054359Sroberto		if (server->delay > NTP_MAXWGT) {
1071106163Sroberto			if (debug)
1072106163Sroberto				printf("%s: Server dropped: server too far away\n",
1073106163Sroberto				       ntoa(&server->srcadr));
1074106163Sroberto			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));
1079106163Sroberto			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));
1085106163Sroberto			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	/*
124254359Sroberto	 * 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) {
128654359Sroberto		if (simple_query || 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
131654359Sroberto/* XXX ELIMINATE: merge BIG slew into adj_systime in lib/systime.c */
131754359Sroberto/*
131854359Sroberto * addserver - determine a server's address and allocate a new structure
131954359Sroberto *		   for it.
132054359Sroberto */
132154359Srobertostatic void
132254359Srobertoaddserver(
132354359Sroberto	char *serv
132454359Sroberto	)
132554359Sroberto{
132654359Sroberto	register struct server *server;
1327132451Sroberto        /* Address infos structure to store result of getaddrinfo */
1328132451Sroberto        struct addrinfo *addrResult;
1329132451Sroberto        /* Address infos structure to store hints for getaddrinfo */
1330132451Sroberto        struct addrinfo hints;
1331132451Sroberto        /* Error variable for getaddrinfo */
1332132451Sroberto        int error;
1333132451Sroberto        /* Service name */
1334132451Sroberto        char service[5];
1335132451Sroberto	strcpy(service, "ntp");
133654359Sroberto
1337132451Sroberto        /* Get host address. Looking for UDP datagram connection. */
1338132451Sroberto        memset(&hints, 0, sizeof(hints));
1339132451Sroberto        hints.ai_family = ai_fam_templ;
1340132451Sroberto        hints.ai_socktype = SOCK_DGRAM;
1341132451Sroberto
1342132451Sroberto        printf("Looking for host %s and service %s\n", serv, service);
1343132451Sroberto
1344132451Sroberto        error = getaddrinfo(serv, service, &hints, &addrResult);
1345132451Sroberto        if (error != 0) {
1346132451Sroberto                fprintf(stderr, "Error : %s\n", gai_strerror(error));
134754359Sroberto		msyslog(LOG_ERR, "can't find host %s\n", serv);
134854359Sroberto		return;
134954359Sroberto	}
1350132451Sroberto        else {
1351132451Sroberto                fprintf(stderr, "host found : %s\n", stohost((struct sockaddr_storage*)addrResult->ai_addr));
1352132451Sroberto        }
135354359Sroberto
135454359Sroberto	server = (struct server *)emalloc(sizeof(struct server));
135554359Sroberto	memset((char *)server, 0, sizeof(struct server));
135654359Sroberto
1357132451Sroberto        /* For now we only get the first returned server of the addrinfo list */
1358132451Sroberto        memset(&(server->srcadr), 0, sizeof(struct sockaddr_storage));
1359132451Sroberto        memcpy(&(server->srcadr), addrResult->ai_addr, addrResult->ai_addrlen);
136056746Sroberto	server->event_time = ++sys_numservers;
136156746Sroberto	if (sys_servers == NULL)
136256746Sroberto		sys_servers = server;
136356746Sroberto	else {
136456746Sroberto		struct server *sp;
136556746Sroberto
136656746Sroberto		for (sp = sys_servers; sp->next_server != NULL;
136756746Sroberto		     sp = sp->next_server) ;
136856746Sroberto		sp->next_server = server;
136956746Sroberto	}
137054359Sroberto}
137154359Sroberto
137254359Sroberto
137354359Sroberto/*
137454359Sroberto * findserver - find a server in the list given its address
1375132451Sroberto * ***(For now it isn't totally AF-Independant, to check later..)
137654359Sroberto */
137754359Srobertostatic struct server *
137854359Srobertofindserver(
1379132451Sroberto	struct sockaddr_storage *addr
138054359Sroberto	)
138154359Sroberto{
138256746Sroberto	struct server *server;
138356746Sroberto	struct server *mc_server;
138454359Sroberto
138556746Sroberto	mc_server = NULL;
1386132451Sroberto	if (htons(((struct sockaddr_in*)addr)->sin_port) != NTP_PORT)
138754359Sroberto		return 0;
138854359Sroberto
138956746Sroberto	for (server = sys_servers; server != NULL;
139056746Sroberto	     server = server->next_server) {
139156746Sroberto
1392132451Sroberto                if (memcmp(addr, &server->srcadr, SOCKLEN(addr))==0)
139356746Sroberto			return server;
1394132451Sroberto                /* Multicast compatibility to verify here... I'm not sure it's working */
1395132451Sroberto                if(addr->ss_family == AF_INET) {
1396132451Sroberto                        if (IN_MULTICAST(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)))
1397132451Sroberto                                mc_server = server;
1398132451Sroberto                }
1399132451Sroberto                else {
1400132451Sroberto#ifdef AF_INET6
1401132451Sroberto                        if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)(&server->srcadr))->sin6_addr))
140256746Sroberto			mc_server = server;
1403132451Sroberto#else
1404132451Sroberto                        return 0;
1405132451Sroberto#endif
1406132451Sroberto                }
140754359Sroberto	}
140856746Sroberto
140956746Sroberto	if (mc_server != NULL) {
1410132451Sroberto
141156746Sroberto		struct server *sp;
141256746Sroberto
141356746Sroberto		if (mc_server->event_time != 0) {
141456746Sroberto			mc_server->event_time = 0;
141556746Sroberto			complete_servers++;
141656746Sroberto		}
1417132451Sroberto
141856746Sroberto		server = (struct server *)emalloc(sizeof(struct server));
141956746Sroberto		memset((char *)server, 0, sizeof(struct server));
142056746Sroberto
1421132451Sroberto                memcpy(&server->srcadr, &addr, sizeof(struct sockaddr_storage));
142256746Sroberto
142356746Sroberto		server->event_time = ++sys_numservers;
1424132451Sroberto
142556746Sroberto		for (sp = sys_servers; sp->next_server != NULL;
142656746Sroberto		     sp = sp->next_server) ;
142756746Sroberto		sp->next_server = server;
142856746Sroberto		transmit(server);
142956746Sroberto	}
143056746Sroberto	return NULL;
143154359Sroberto}
143254359Sroberto
143354359Sroberto
143454359Sroberto/*
143554359Sroberto * timer - process a timer interrupt
143654359Sroberto */
143754359Srobertovoid
143854359Srobertotimer(void)
143954359Sroberto{
144056746Sroberto	struct server *server;
144154359Sroberto
144254359Sroberto	/*
144354359Sroberto	 * Bump the current idea of the time
144454359Sroberto	 */
144554359Sroberto	current_time++;
144654359Sroberto
144754359Sroberto	/*
144854359Sroberto	 * Search through the server list looking for guys
144954359Sroberto	 * who's event timers have expired.  Give these to
145054359Sroberto	 * the transmit routine.
145154359Sroberto	 */
145256746Sroberto	for (server = sys_servers; server != NULL;
145356746Sroberto	     server = server->next_server) {
145456746Sroberto		if (server->event_time != 0
145556746Sroberto		    && server->event_time <= current_time)
145656746Sroberto			transmit(server);
145754359Sroberto	}
145854359Sroberto}
145954359Sroberto
146054359Sroberto
146182498Sroberto/*
146282498Sroberto * The code duplication in the following subroutine sucks, but
146382498Sroberto * we need to appease ansi2knr.
146482498Sroberto */
146582498Sroberto
146654359Sroberto#ifndef SYS_WINNT
146754359Sroberto/*
146854359Sroberto * alarming - record the occurance of an alarm interrupt
146954359Sroberto */
147054359Srobertostatic RETSIGTYPE
147154359Srobertoalarming(
147254359Sroberto	int sig
147354359Sroberto	)
147482498Sroberto{
147582498Sroberto	alarm_flag++;
147682498Sroberto}
147754359Sroberto#else
147854359Srobertovoid CALLBACK
147954359Srobertoalarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
148054359Sroberto{
148154359Sroberto	alarm_flag++;
148254359Sroberto}
148382498Sroberto#endif /* SYS_WINNT */
148454359Sroberto
148554359Sroberto
148654359Sroberto/*
148754359Sroberto * init_alarm - set up the timer interrupt
148854359Sroberto */
148954359Srobertostatic void
149054359Srobertoinit_alarm(void)
149154359Sroberto{
149254359Sroberto#ifndef SYS_WINNT
149354359Sroberto# ifndef HAVE_TIMER_SETTIME
149454359Sroberto	struct itimerval itimer;
149554359Sroberto# else
149654359Sroberto	struct itimerspec ntpdate_itimer;
149754359Sroberto# endif
149854359Sroberto#else
149954359Sroberto	TIMECAPS tc;
150054359Sroberto	UINT wTimerRes, wTimerID;
150154359Sroberto# endif /* SYS_WINNT */
150254359Sroberto#if defined SYS_CYGWIN32 || defined SYS_WINNT
150354359Sroberto	HANDLE hToken;
150454359Sroberto	TOKEN_PRIVILEGES tkp;
150554359Sroberto	DWORD dwUser = 0;
150654359Sroberto#endif /* SYS_WINNT */
150754359Sroberto
150854359Sroberto	alarm_flag = 0;
150954359Sroberto
151054359Sroberto#ifndef SYS_WINNT
151154359Sroberto# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
151254359Sroberto	alarm_flag = 0;
151354359Sroberto	/* this code was put in as setitimer() is non existant this us the
151454359Sroberto	 * POSIX "equivalents" setup - casey
151554359Sroberto	 */
151654359Sroberto	/* ntpdate_timerid is global - so we can kill timer later */
151754359Sroberto	if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
151854359Sroberto#  ifdef SYS_VXWORKS
151954359Sroberto		ERROR
152054359Sroberto#  else
152154359Sroberto		-1
152254359Sroberto#  endif
152354359Sroberto		)
152454359Sroberto	{
152554359Sroberto		fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
152654359Sroberto		return;
152754359Sroberto	}
152854359Sroberto
152954359Sroberto	/*	TIMER_HZ = (5)
153054359Sroberto	 * Set up the alarm interrupt.	The first comes 1/(2*TIMER_HZ)
153154359Sroberto	 * seconds from now and they continue on every 1/TIMER_HZ seconds.
153254359Sroberto	 */
153354359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
153454359Sroberto	ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
153554359Sroberto	ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
153654359Sroberto	ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
153754359Sroberto	timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
153854359Sroberto# else
153954359Sroberto	/*
154054359Sroberto	 * Set up the alarm interrupt.	The first comes 1/(2*TIMER_HZ)
154154359Sroberto	 * seconds from now and they continue on every 1/TIMER_HZ seconds.
154254359Sroberto	 */
154354359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
154454359Sroberto	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
154554359Sroberto	itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
154654359Sroberto	itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
1547132451Sroberto
154854359Sroberto	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
154954359Sroberto# endif
155054359Sroberto#if defined SYS_CYGWIN32
155154359Sroberto	/*
155254359Sroberto	 * Get previleges needed for fiddling with the clock
155354359Sroberto	 */
155454359Sroberto
155554359Sroberto	/* get the current process token handle */
155654359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
155754359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
155854359Sroberto		exit(1);
155954359Sroberto	}
156054359Sroberto	/* get the LUID for system-time privilege. */
156154359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
156254359Sroberto	tkp.PrivilegeCount = 1;  /* one privilege to set */
156354359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
156454359Sroberto	/* get set-time privilege for this process. */
156554359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
156654359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
156754359Sroberto	if (GetLastError() != ERROR_SUCCESS)
156854359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
156954359Sroberto#endif
157054359Sroberto#else	/* SYS_WINNT */
157154359Sroberto	_tzset();
157254359Sroberto
157354359Sroberto	/*
157454359Sroberto	 * Get previleges needed for fiddling with the clock
157554359Sroberto	 */
157654359Sroberto
157754359Sroberto	/* get the current process token handle */
157854359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
157954359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
158054359Sroberto		exit(1);
158154359Sroberto	}
158254359Sroberto	/* get the LUID for system-time privilege. */
158354359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
158454359Sroberto	tkp.PrivilegeCount = 1;  /* one privilege to set */
158554359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
158654359Sroberto	/* get set-time privilege for this process. */
158754359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
158854359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
158954359Sroberto	if (GetLastError() != ERROR_SUCCESS)
159054359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
159154359Sroberto
159254359Sroberto	/*
159354359Sroberto	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
159454359Sroberto	 * Under Win/NT, expiry of timer interval leads to invocation
159554359Sroberto	 * of a callback function (on a different thread) rather than
159654359Sroberto	 * generating an alarm signal
159754359Sroberto	 */
159854359Sroberto
159954359Sroberto	/* determine max and min resolution supported */
160054359Sroberto	if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
160154359Sroberto		msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
160254359Sroberto		exit(1);
160354359Sroberto	}
160454359Sroberto	wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
160554359Sroberto	/* establish the minimum timer resolution that we'll use */
160654359Sroberto	timeBeginPeriod(wTimerRes);
160754359Sroberto
160854359Sroberto	/* start the timer event */
160954359Sroberto	wTimerID = timeSetEvent(
161054359Sroberto		(UINT) (1000/TIMER_HZ),    /* Delay */
161154359Sroberto		wTimerRes,			 /* Resolution */
161254359Sroberto		(LPTIMECALLBACK) alarming, /* Callback function */
161354359Sroberto		(DWORD) dwUser, 	 /* User data */
161454359Sroberto		TIME_PERIODIC); 	 /* Event type (periodic) */
161554359Sroberto	if (wTimerID == 0) {
161654359Sroberto		msyslog(LOG_ERR, "timeSetEvent failed: %m");
161754359Sroberto		exit(1);
161854359Sroberto	}
161954359Sroberto#endif /* SYS_WINNT */
162054359Sroberto}
162154359Sroberto
162254359Sroberto
162354359Sroberto
162454359Sroberto
162554359Sroberto/*
162654359Sroberto * We do asynchronous input using the SIGIO facility.  A number of
162754359Sroberto * recvbuf buffers are preallocated for input.	In the signal
162854359Sroberto * handler we poll to see if the socket is ready and read the
162954359Sroberto * packets from it into the recvbuf's along with a time stamp and
163054359Sroberto * an indication of the source host and the interface it was received
163154359Sroberto * through.  This allows us to get as accurate receive time stamps
163254359Sroberto * as possible independent of other processing going on.
163354359Sroberto *
163454359Sroberto * We allocate a number of recvbufs equal to the number of servers
163554359Sroberto * plus 2.	This should be plenty.
163654359Sroberto */
163754359Sroberto
163854359Sroberto
163954359Sroberto/*
164054359Sroberto * init_io - initialize I/O data and open socket
164154359Sroberto */
164254359Srobertostatic void
164354359Srobertoinit_io(void)
164454359Sroberto{
1645132451Sroberto        struct addrinfo *res, *ressave;
1646132451Sroberto        struct addrinfo hints;
1647132451Sroberto	char service[5];
1648132451Sroberto        int optval = 1;
1649132451Sroberto
165054359Sroberto	/*
165154359Sroberto	 * Init buffer free list and stat counters
165254359Sroberto	 */
165354359Sroberto	init_recvbuff(sys_numservers + 2);
1654132451Sroberto
165554359Sroberto	/*
165654359Sroberto	 * Open the socket
165754359Sroberto	 */
165854359Sroberto
1659132451Sroberto	strcpy(service, "ntp");
1660132451Sroberto
1661132451Sroberto        /*
1662132451Sroberto         * Init hints addrinfo structure
1663132451Sroberto         */
1664132451Sroberto        memset(&hints, 0, sizeof(hints));
1665132451Sroberto        hints.ai_flags = AI_PASSIVE;
1666132451Sroberto        hints.ai_socktype = SOCK_DGRAM;
1667132451Sroberto
1668132451Sroberto        if(getaddrinfo(NULL, service, &hints, &res) != 0) {
1669132451Sroberto               msyslog(LOG_ERR, "getaddrinfo() failed: %m");
1670132451Sroberto               exit(1);
1671132451Sroberto               /*NOTREACHED*/
1672132451Sroberto        }
1673132451Sroberto
1674132451Sroberto        /* Remember the address of the addrinfo structure chain */
1675132451Sroberto        ressave = res;
1676132451Sroberto
1677132451Sroberto        /*
1678132451Sroberto         * For each structure returned, open and bind socket
1679132451Sroberto         */
1680132451Sroberto        for(nbsock = 0; (nbsock < MAX_AF) && res ; res = res->ai_next) {
168154359Sroberto	/* create a datagram (UDP) socket */
1682132451Sroberto           if ((fd[nbsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
1683132451Sroberto		if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT ||
1684132451Sroberto		    errno == EPFNOSUPPORT)
1685132451Sroberto			continue;
1686132451Sroberto		netsyslog(LOG_ERR, "socket() failed: %m");
168754359Sroberto		exit(1);
168854359Sroberto		/*NOTREACHED*/
168954359Sroberto	}
1690132451Sroberto           /* set socket to reuse address */
1691132451Sroberto           if (setsockopt(fd[nbsock], SOL_SOCKET, SO_REUSEADDR, (void*) &optval, sizeof(optval)) < 0) {
1692132451Sroberto   		   netsyslog(LOG_ERR, "setsockopt() SO_REUSEADDR failed: %m");
1693132451Sroberto   		   exit(1);
1694132451Sroberto		   /*NOTREACHED*/
1695132451Sroberto    	   }
1696132451Sroberto#ifdef IPV6_V6ONLY
1697132451Sroberto           /* Restricts AF_INET6 socket to IPv6 communications (see RFC 2553bis-03) */
1698132451Sroberto           if (res->ai_family == AF_INET6)
1699132451Sroberto                if (setsockopt(fd[nbsock], IPPROTO_IPV6, IPV6_V6ONLY, (void*) &optval, sizeof(optval)) < 0) {
1700132451Sroberto   		           netsyslog(LOG_ERR, "setsockopt() IPV6_V6ONLY failed: %m");
1701132451Sroberto   		           exit(1);
1702132451Sroberto		           /*NOTREACHED*/
1703132451Sroberto    	        }
1704132451Sroberto#endif
170554359Sroberto
1706132451Sroberto           /* Remember the socket family in fd_family structure */
1707132451Sroberto           fd_family[nbsock] = res->ai_family;
1708132451Sroberto
170954359Sroberto	/*
171054359Sroberto	 * bind the socket to the NTP port
171154359Sroberto	 */
171254359Sroberto	if (!debug && !simple_query && !unpriv_port) {
1713132451Sroberto		if (bind(fd[nbsock], res->ai_addr, SOCKLEN(res->ai_addr)) < 0) {
171454359Sroberto#ifndef SYS_WINNT
171554359Sroberto			if (errno == EADDRINUSE)
171654359Sroberto#else
171754359Sroberto				if (WSAGetLastError() == WSAEADDRINUSE)
171854359Sroberto#endif /* SYS_WINNT */
1719132451Sroberto				netsyslog(LOG_ERR,
172054359Sroberto					"the NTP socket is in use, exiting");
172154359Sroberto				else
1722132451Sroberto				netsyslog(LOG_ERR, "bind() fails: %m");
172354359Sroberto			exit(1);
172454359Sroberto		}
172554359Sroberto	}
172654359Sroberto
172754359Sroberto#ifdef HAVE_POLL_H
1728132451Sroberto	    fdmask[nbsock].fd = fd[nbsock];
1729132451Sroberto	    fdmask[nbsock].events = POLLIN;
173054359Sroberto#else
1731132451Sroberto	    FD_SET(fd[nbsock], &fdmask);
1732132451Sroberto            if ((SOCKET) maxfd < fd[nbsock]+1) {
1733132451Sroberto                maxfd = fd[nbsock]+1;
1734132451Sroberto            }
173554359Sroberto#endif
173654359Sroberto
173754359Sroberto	/*
173854359Sroberto	 * set non-blocking,
173954359Sroberto	 */
174054359Sroberto#ifndef SYS_WINNT
174154359Sroberto# ifdef SYS_VXWORKS
174254359Sroberto  {
174354359Sroberto	int on = TRUE;
174454359Sroberto
1745132451Sroberto	   if (ioctl(fd[nbsock],FIONBIO, &on) == ERROR) {
1746132451Sroberto	  netsyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
174754359Sroberto	  exit(1);
174854359Sroberto	}
174954359Sroberto  }
175054359Sroberto# else /* not SYS_VXWORKS */
175154359Sroberto#  if defined(O_NONBLOCK)
1752132451Sroberto	   if (fcntl(fd[nbsock], F_SETFL, O_NONBLOCK) < 0) {
1753132451Sroberto		netsyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
175454359Sroberto		exit(1);
175554359Sroberto		/*NOTREACHED*/
175654359Sroberto	}
175754359Sroberto#  else /* not O_NONBLOCK */
175854359Sroberto#	if defined(FNDELAY)
1759132451Sroberto	   if (fcntl(fd[nbsock], F_SETFL, FNDELAY) < 0) {
1760132451Sroberto		netsyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
176154359Sroberto		exit(1);
176254359Sroberto		/*NOTREACHED*/
176354359Sroberto	}
176454359Sroberto#	else /* FNDELAY */
176554359Sroberto#	 include "Bletch: Need non blocking I/O"
176654359Sroberto#	endif /* FNDELAY */
176754359Sroberto#  endif /* not O_NONBLOCK */
176854359Sroberto# endif /* SYS_VXWORKS */
176954359Sroberto#else /* SYS_WINNT */
1770132451Sroberto	if (ioctlsocket(fd[nbsock], FIONBIO, (u_long *) &on) == SOCKET_ERROR) {
1771132451Sroberto		netsyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
177254359Sroberto		exit(1);
177354359Sroberto	}
177454359Sroberto#endif /* SYS_WINNT */
1775132451Sroberto   	nbsock++;
1776132451Sroberto    }
1777132451Sroberto    freeaddrinfo(ressave);
177854359Sroberto}
177954359Sroberto
178054359Sroberto/*
178154359Sroberto * sendpkt - send a packet to the specified destination
178254359Sroberto */
178354359Srobertostatic void
178454359Srobertosendpkt(
1785132451Sroberto	struct sockaddr_storage *dest,
178654359Sroberto	struct pkt *pkt,
178754359Sroberto	int len
178854359Sroberto	)
178954359Sroberto{
1790132451Sroberto        int i;
179154359Sroberto	int cc;
1792132451Sroberto        SOCKET sock = 0;
179354359Sroberto
179454359Sroberto#ifdef SYS_WINNT
179554359Sroberto	DWORD err;
179654359Sroberto#endif /* SYS_WINNT */
179754359Sroberto
1798132451Sroberto        /* Find a local family compatible socket to send ntp packet to ntp server */
1799132451Sroberto        for(i = 0; (i < MAX_AF); i++) {
1800132451Sroberto                if(dest->ss_family == fd_family[i]) {
1801132451Sroberto                        sock = fd[i];
1802132451Sroberto                break;
1803132451Sroberto                }
1804132451Sroberto        }
1805132451Sroberto
1806132451Sroberto        if ( sock == 0 ) {
1807132451Sroberto                netsyslog(LOG_ERR, "cannot find family compatible socket to send ntp packet");
1808132451Sroberto                exit(1);
1809132451Sroberto                /*NOTREACHED*/
1810132451Sroberto        }
1811132451Sroberto
1812132451Sroberto	cc = sendto(sock, (char *)pkt, len, 0, (struct sockaddr *)dest,
1813132451Sroberto			SOCKLEN(dest));
1814132451Sroberto
181554359Sroberto#ifndef SYS_WINNT
181654359Sroberto	if (cc == -1) {
181754359Sroberto		if (errno != EWOULDBLOCK && errno != ENOBUFS)
181854359Sroberto#else
181954359Sroberto	if (cc == SOCKET_ERROR) {
182054359Sroberto		err = WSAGetLastError();
182154359Sroberto		if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
182254359Sroberto#endif /* SYS_WINNT */
1823132451Sroberto                        netsyslog(LOG_ERR, "sendto(%s): %m", stohost(dest));
182454359Sroberto	}
182554359Sroberto}
182654359Sroberto
182754359Sroberto
182854359Sroberto/*
182954359Sroberto * input_handler - receive packets asynchronously
183054359Sroberto */
183154359Srobertovoid
183254359Srobertoinput_handler(void)
183354359Sroberto{
183454359Sroberto	register int n;
183554359Sroberto	register struct recvbuf *rb;
183654359Sroberto	struct timeval tvzero;
183754359Sroberto	int fromlen;
183854359Sroberto	l_fp ts;
1839132451Sroberto        int i;
184054359Sroberto#ifdef HAVE_POLL_H
1841132451Sroberto	struct pollfd fds[MAX_AF];
184254359Sroberto#else
184354359Sroberto	fd_set fds;
184454359Sroberto#endif
1845132451Sroberto        int fdc = 0;
184654359Sroberto
184754359Sroberto	/*
184854359Sroberto	 * Do a poll to see if we have data
184954359Sroberto	 */
185054359Sroberto	for (;;) {
185154359Sroberto		tvzero.tv_sec = tvzero.tv_usec = 0;
185254359Sroberto#ifdef HAVE_POLL_H
1853132451Sroberto		memcpy(fds, fdmask, sizeof(fdmask));
1854132451Sroberto                n = poll(fds, (unsigned int)nbsock, tvzero.tv_sec * 1000);
1855132451Sroberto
1856132451Sroberto                /*
1857132451Sroberto                 * Determine which socket received data
1858132451Sroberto                 */
1859132451Sroberto
1860132451Sroberto                 for(i=0; i < nbsock; i++) {
1861132451Sroberto                        if(fds[i].revents & POLLIN) {
1862132451Sroberto                                fdc = fd[i];
1863132451Sroberto                                break;
1864132451Sroberto                        }
1865132451Sroberto                 }
1866132451Sroberto
186754359Sroberto#else
1868132451Sroberto		fds = fdmask;
1869132451Sroberto                n = select(maxfd, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
1870132451Sroberto
1871132451Sroberto                /*
1872132451Sroberto                 * Determine which socket received data
1873132451Sroberto                 */
1874132451Sroberto
1875132451Sroberto                for(i=0; i < maxfd; i++) {
1876132451Sroberto                        if(FD_ISSET(fd[i], &fds)) {
1877132451Sroberto                                 fdc = fd[i];
1878132451Sroberto                                 break;
1879132451Sroberto                        }
1880132451Sroberto                }
1881132451Sroberto
188254359Sroberto#endif
188354359Sroberto
188454359Sroberto		/*
188554359Sroberto		 * If nothing to do, just return.  If an error occurred,
188654359Sroberto		 * complain and return.  If we've got some, freeze a
188754359Sroberto		 * timestamp.
188854359Sroberto		 */
188954359Sroberto		if (n == 0)
189054359Sroberto			return;
189154359Sroberto		else if (n == -1) {
189254359Sroberto			if (errno != EINTR)
1893132451Sroberto				netsyslog(LOG_ERR,
189454359Sroberto#ifdef HAVE_POLL_H
189554359Sroberto					"poll() error: %m"
189654359Sroberto#else
189754359Sroberto					"select() error: %m"
189854359Sroberto#endif
189954359Sroberto					);
190054359Sroberto			return;
190154359Sroberto		}
190254359Sroberto		get_systime(&ts);
190354359Sroberto
190454359Sroberto		/*
190554359Sroberto		 * Get a buffer and read the frame.  If we
190654359Sroberto		 * haven't got a buffer, or this is received
190754359Sroberto		 * on the wild card socket, just dump the packet.
190854359Sroberto		 */
190954359Sroberto		if (initializing || free_recvbuffs() == 0) {
191054359Sroberto			char buf[100];
191154359Sroberto
1912132451Sroberto
191354359Sroberto#ifndef SYS_WINNT
1914132451Sroberto			(void) read(fdc, buf, sizeof buf);
191554359Sroberto#else
191654359Sroberto			/* NT's _read does not operate on nonblocking sockets
191754359Sroberto			 * either recvfrom or ReadFile() has to be used here.
191854359Sroberto			 * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
191954359Sroberto			 * just to be different use recvfrom() here
192054359Sroberto			 */
1921132451Sroberto			recvfrom(fdc, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
192254359Sroberto#endif /* SYS_WINNT */
192354359Sroberto			continue;
192454359Sroberto		}
192554359Sroberto
192654359Sroberto		rb = get_free_recv_buffer();
192754359Sroberto
1928132451Sroberto		fromlen = sizeof(struct sockaddr_storage);
1929132451Sroberto		rb->recv_length = recvfrom(fdc, (char *)&rb->recv_pkt,
193054359Sroberto		   sizeof(rb->recv_pkt), 0,
193154359Sroberto		   (struct sockaddr *)&rb->recv_srcadr, &fromlen);
193254359Sroberto		if (rb->recv_length == -1) {
193354359Sroberto			freerecvbuf(rb);
193454359Sroberto			continue;
193554359Sroberto		}
193654359Sroberto
193754359Sroberto		/*
193854359Sroberto		 * Got one.  Mark how and when it got here,
193954359Sroberto		 * put it on the full list.
194054359Sroberto		 */
194154359Sroberto		rb->recv_time = ts;
194254359Sroberto		add_full_recv_buffer(rb);
194354359Sroberto	}
194454359Sroberto}
194554359Sroberto
194654359Sroberto
194754359Sroberto#if !defined SYS_WINNT && !defined SYS_CYGWIN32
194854359Sroberto/*
194954359Sroberto * adj_systime - do a big long slew of the system time
195054359Sroberto */
195154359Srobertostatic int
195254359Srobertol_adj_systime(
195354359Sroberto	l_fp *ts
195454359Sroberto	)
195554359Sroberto{
195654359Sroberto	struct timeval adjtv, oadjtv;
195754359Sroberto	int isneg = 0;
195854359Sroberto	l_fp offset;
195954359Sroberto#ifndef STEP_SLEW
196054359Sroberto	l_fp overshoot;
196154359Sroberto#endif
196254359Sroberto
196354359Sroberto	/*
196454359Sroberto	 * Take the absolute value of the offset
196554359Sroberto	 */
196654359Sroberto	offset = *ts;
196754359Sroberto	if (L_ISNEG(&offset)) {
196854359Sroberto		isneg = 1;
196954359Sroberto		L_NEG(&offset);
197054359Sroberto	}
197154359Sroberto
197254359Sroberto#ifndef STEP_SLEW
197354359Sroberto	/*
197454359Sroberto	 * Calculate the overshoot.  XXX N.B. This code *knows*
197554359Sroberto	 * ADJ_OVERSHOOT is 1/2.
197654359Sroberto	 */
197754359Sroberto	overshoot = offset;
197854359Sroberto	L_RSHIFTU(&overshoot);
197954359Sroberto	if (overshoot.l_ui != 0 || (overshoot.l_uf > ADJ_MAXOVERSHOOT)) {
198054359Sroberto		overshoot.l_ui = 0;
198154359Sroberto		overshoot.l_uf = ADJ_MAXOVERSHOOT;
198254359Sroberto	}
198354359Sroberto	L_ADD(&offset, &overshoot);
198454359Sroberto#endif
198554359Sroberto	TSTOTV(&offset, &adjtv);
198654359Sroberto
198754359Sroberto	if (isneg) {
198854359Sroberto		adjtv.tv_sec = -adjtv.tv_sec;
198954359Sroberto		adjtv.tv_usec = -adjtv.tv_usec;
199054359Sroberto	}
199154359Sroberto
199254359Sroberto	if (adjtv.tv_usec != 0 && !debug) {
199354359Sroberto		if (adjtime(&adjtv, &oadjtv) < 0) {
199454359Sroberto			msyslog(LOG_ERR, "Can't adjust the time of day: %m");
199554359Sroberto			return 0;
199654359Sroberto		}
199754359Sroberto	}
199854359Sroberto	return 1;
199954359Sroberto}
200054359Sroberto#endif /* SYS_WINNT */
200154359Sroberto
200254359Sroberto
200354359Sroberto/*
200454359Sroberto * This fuction is not the same as lib/systime step_systime!!!
200554359Sroberto */
200654359Srobertostatic int
200754359Srobertol_step_systime(
200854359Sroberto	l_fp *ts
200954359Sroberto	)
201054359Sroberto{
201154359Sroberto	double dtemp;
201254359Sroberto
201354359Sroberto#ifdef SLEWALWAYS
201454359Sroberto#ifdef STEP_SLEW
201554359Sroberto	l_fp ftmp;
201654359Sroberto	int isneg;
201754359Sroberto	int n;
201854359Sroberto
201954359Sroberto	if (debug) return 1;
202054359Sroberto	/*
202154359Sroberto	 * Take the absolute value of the offset
202254359Sroberto	 */
202354359Sroberto	ftmp = *ts;
202454359Sroberto	if (L_ISNEG(&ftmp)) {
202554359Sroberto		L_NEG(&ftmp);
202654359Sroberto		isneg = 1;
202754359Sroberto	} else
202854359Sroberto		isneg = 0;
202954359Sroberto
203054359Sroberto	if (ftmp.l_ui >= 3) {		/* Step it and slew - we might win */
203156746Sroberto		LFPTOD(ts, dtemp);
203256746Sroberto		n = step_systime(dtemp);
203354359Sroberto		if (!n)
203454359Sroberto			return n;
203554359Sroberto		if (isneg)
203654359Sroberto			ts->l_ui = ~0;
203754359Sroberto		else
203854359Sroberto			ts->l_ui = ~0;
203954359Sroberto	}
204054359Sroberto	/*
204154359Sroberto	 * Just add adjustment into the current offset.  The update
204254359Sroberto	 * routine will take care of bringing the system clock into
204354359Sroberto	 * line.
204454359Sroberto	 */
204554359Sroberto#endif
204654359Sroberto	if (debug)
204754359Sroberto		return 1;
204854359Sroberto#ifdef FORCE_NTPDATE_STEP
204954359Sroberto	LFPTOD(ts, dtemp);
205054359Sroberto	return step_systime(dtemp);
205154359Sroberto#else
205254359Sroberto	l_adj_systime(ts);
205354359Sroberto	return 1;
205454359Sroberto#endif
205554359Sroberto#else /* SLEWALWAYS  */
205654359Sroberto	if (debug)
205754359Sroberto		return 1;
205854359Sroberto	LFPTOD(ts, dtemp);
205954359Sroberto	return step_systime(dtemp);
206054359Sroberto#endif	/* SLEWALWAYS */
206154359Sroberto}
206254359Sroberto
206354359Sroberto
206454359Sroberto/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
206554359Sroberto/*
206654359Sroberto * printserver - print detail information for a server
206754359Sroberto */
206854359Srobertostatic void
206954359Srobertoprintserver(
207054359Sroberto	register struct server *pp,
207154359Sroberto	FILE *fp
207254359Sroberto	)
207354359Sroberto{
207454359Sroberto	register int i;
207554359Sroberto	char junk[5];
207654359Sroberto	char *str;
207754359Sroberto
207854359Sroberto	if (!debug) {
207954359Sroberto		(void) fprintf(fp, "server %s, stratum %d, offset %s, delay %s\n",
2080132451Sroberto				   stoa(&pp->srcadr), pp->stratum,
208154359Sroberto				   lfptoa(&pp->offset, 6), fptoa((s_fp)pp->delay, 5));
208254359Sroberto		return;
208354359Sroberto	}
208454359Sroberto
208554359Sroberto	(void) fprintf(fp, "server %s, port %d\n",
2086132451Sroberto			   stoa(&pp->srcadr), ntohs(((struct sockaddr_in*)&(pp->srcadr))->sin_port));
208754359Sroberto
208854359Sroberto	(void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
208954359Sroberto			   pp->stratum, pp->precision,
209054359Sroberto			   pp->leap & 0x2 ? '1' : '0',
209154359Sroberto			   pp->leap & 0x1 ? '1' : '0',
209254359Sroberto			   pp->trust);
209354359Sroberto
209454359Sroberto	if (pp->stratum == 1) {
209554359Sroberto		junk[4] = 0;
209654359Sroberto		memmove(junk, (char *)&pp->refid, 4);
209754359Sroberto		str = junk;
209854359Sroberto	} else {
2099132451Sroberto		str = stoa(&pp->srcadr);
210054359Sroberto	}
210154359Sroberto	(void) fprintf(fp,
210254359Sroberto			   "refid [%s], delay %s, dispersion %s\n",
210354359Sroberto			   str, fptoa((s_fp)pp->delay, 5),
210454359Sroberto			   ufptoa(pp->dispersion, 5));
210554359Sroberto
210654359Sroberto	(void) fprintf(fp, "transmitted %d, in filter %d\n",
210754359Sroberto			   pp->xmtcnt, pp->filter_nextpt);
210854359Sroberto
210954359Sroberto	(void) fprintf(fp, "reference time:    %s\n",
211054359Sroberto			   prettydate(&pp->reftime));
211154359Sroberto	(void) fprintf(fp, "originate timestamp: %s\n",
211254359Sroberto			   prettydate(&pp->org));
211354359Sroberto	(void) fprintf(fp, "transmit timestamp:  %s\n",
211454359Sroberto			   prettydate(&pp->xmt));
211554359Sroberto
211654359Sroberto	(void) fprintf(fp, "filter delay: ");
211754359Sroberto	for (i = 0; i < NTP_SHIFT; i++) {
211854359Sroberto		(void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
211954359Sroberto		if (i == (NTP_SHIFT>>1)-1)
212054359Sroberto			(void) fprintf(fp, "\n        ");
212154359Sroberto	}
212254359Sroberto	(void) fprintf(fp, "\n");
212354359Sroberto
212454359Sroberto	(void) fprintf(fp, "filter offset:");
212554359Sroberto	for (i = 0; i < PEER_SHIFT; i++) {
212654359Sroberto		(void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
212754359Sroberto		if (i == (PEER_SHIFT>>1)-1)
212854359Sroberto			(void) fprintf(fp, "\n        ");
212954359Sroberto	}
213054359Sroberto	(void) fprintf(fp, "\n");
213154359Sroberto
213254359Sroberto	(void) fprintf(fp, "delay %s, dispersion %s\n",
213354359Sroberto			   fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
213454359Sroberto
213554359Sroberto	(void) fprintf(fp, "offset %s\n\n",
213654359Sroberto			   lfptoa(&pp->offset, 6));
213754359Sroberto}
213854359Sroberto
213954359Sroberto#if !defined(HAVE_VSPRINTF)
214054359Srobertoint
214154359Srobertovsprintf(
214254359Sroberto	char *str,
214354359Sroberto	const char *fmt,
214454359Sroberto	va_list ap
214554359Sroberto	)
214654359Sroberto{
214754359Sroberto	FILE f;
214854359Sroberto	int len;
214954359Sroberto
215054359Sroberto	f._flag = _IOWRT+_IOSTRG;
215154359Sroberto	f._ptr = str;
215254359Sroberto	f._cnt = 32767;
215354359Sroberto	len = _doprnt(fmt, ap, &f);
215454359Sroberto	*f._ptr = 0;
215554359Sroberto	return (len);
215654359Sroberto}
215754359Sroberto#endif
215854359Sroberto
215954359Sroberto#if 0
216054359Sroberto/* override function in library since SA_RESTART makes ALL syscalls restart */
216154359Sroberto#ifdef SA_RESTART
216254359Srobertovoid
216354359Srobertosignal_no_reset(
216454359Sroberto	int sig,
216554359Sroberto	void (*func)()
216654359Sroberto	)
216754359Sroberto{
216854359Sroberto	int n;
216954359Sroberto	struct sigaction vec;
217054359Sroberto
217154359Sroberto	vec.sa_handler = func;
217254359Sroberto	sigemptyset(&vec.sa_mask);
217354359Sroberto	vec.sa_flags = 0;
217454359Sroberto
217554359Sroberto	while (1)
217654359Sroberto	{
217754359Sroberto		n = sigaction(sig, &vec, NULL);
217854359Sroberto		if (n == -1 && errno == EINTR)
217954359Sroberto			continue;
218054359Sroberto		break;
218154359Sroberto	}
218254359Sroberto	if (n == -1)
218354359Sroberto	{
218454359Sroberto		perror("sigaction");
218554359Sroberto		exit(1);
218654359Sroberto	}
218754359Sroberto}
218854359Sroberto#endif
218954359Sroberto#endif
219054359Sroberto
219154359Sroberto#ifdef HAVE_NETINFO
219254359Srobertostatic ni_namelist *
219354359Srobertogetnetinfoservers(void)
219454359Sroberto{
219554359Sroberto	ni_status status;
219654359Sroberto	void *domain;
219754359Sroberto	ni_id confdir;
219854359Sroberto	ni_namelist *namelist = (ni_namelist*)malloc(sizeof(ni_namelist));
219954359Sroberto
220054359Sroberto	/* Find a time server in NetInfo */
220154359Sroberto	if ((status = ni_open(NULL, ".", &domain)) != NI_OK) return NULL;
220254359Sroberto
220354359Sroberto	while (status = ni_pathsearch(domain, &confdir, NETINFO_CONFIG_DIR) == NI_NODIR) {
220454359Sroberto		void *next_domain;
220554359Sroberto		if (ni_open(domain, "..", &next_domain) != NI_OK) break;
220654359Sroberto		ni_free(domain);
220754359Sroberto		domain = next_domain;
220854359Sroberto	}
220954359Sroberto	if (status != NI_OK) return NULL;
221054359Sroberto
221154359Sroberto	NI_INIT(namelist);
221254359Sroberto	if (ni_lookupprop(domain, &confdir, "server", namelist) != NI_OK) {
221354359Sroberto		ni_namelist_free(namelist);
221454359Sroberto		free(namelist);
221554359Sroberto		return NULL;
221654359Sroberto	}
221754359Sroberto
221854359Sroberto	return(namelist);
221954359Sroberto}
222054359Sroberto#endif
2221