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