154359Sroberto/*
254359Sroberto * ntptimeset - get/set the time via ntp
354359Sroberto *
454359Sroberto * GOAL:
554359Sroberto * The goal of ntptime is to set the current time on system startup
654359Sroberto * to the best possible time using the network very wisely. It is assumed
754359Sroberto * that after a resonable time has been sett then ntp daemon will
854359Sroberto * maintain it.
954359Sroberto *
1054359Sroberto * PROBLEM DOMAIN:
1154359Sroberto * We have three sets of issues related to acheiving the goal. The first
1254359Sroberto * issue is using the network when normal traffic is happening or when
1354359Sroberto * the entire network world is recovering from a campus wide power failure
1454359Sroberto * and is restarting. The second issue is the class of machine whether it
1554359Sroberto * is a user's office workstation being handled by an uneducated user or
1654359Sroberto * a server computer being handled by a trained operations staff. The third
1754359Sroberto * issue is whether the ratio of people to computers and whether the
1854359Sroberto * environment is stable and viable or not.
1954359Sroberto *
2054359Sroberto * NETWORK USAGE:
2154359Sroberto * The first issue of using the network wisely is a question of whether
2254359Sroberto * the network load and time server load and state are normal. If things
2354359Sroberto * are normal ntptime can do what ntpdate does of sending out 4 packets
2454359Sroberto * quickly to each server (new transmit done with each ack). However
2554359Sroberto * if network or time load is high then this scheme will simply contribute
2654359Sroberto * to problems. Given we have minimal state, we simply weight lost packets
2754359Sroberto * significantly and make sure we throttle output as much as possible
2854359Sroberto * without performance lost for quick startups.
2954359Sroberto *
3054359Sroberto * TRAINING AND KNOWLEDGE:
3154359Sroberto * The second issue of uneducated user of a office workstation versus a
3254359Sroberto * trained operation staff of a server machine translates into simply an
3354359Sroberto * issue of untrained and trained users.
3454359Sroberto *
3554359Sroberto * The training issue implies that for the sake of the users involved in the
3654359Sroberto * handling of their office workstation, problems and options should be
3754359Sroberto * communicated simply and effectively and not in terse expert related
3854359Sroberto * descriptions without possible options to be taken. The operator's training
3954359Sroberto * and education enables them to deal with either type of communication and
4054359Sroberto * control.
4154359Sroberto *
4254359Sroberto * AUTOMATION AND MANUAL CONTROL:
4354359Sroberto * The last issue boils down to a design problem. If the design tends to go
4454359Sroberto * into a manual mode when the environment is non-viable then one person
4554359Sroberto * handling many computers all at the same time will be heavily impacted. On
4654359Sroberto * the other hand, if the design tends to be automatic and does not indicate
4754359Sroberto * a way for the user to take over control then the computer will be
4854359Sroberto * unavailable for the user until the proble is resolved by someone else or
4954359Sroberto * the user.
5054359Sroberto *
5154359Sroberto * NOTE: Please do not have this program print out every minute some line,
5254359Sroberto *       of output. If this happens and the environment is in trouble then
5354359Sroberto *       many pages of paper on many different machines will be filled up.
5454359Sroberto *       Save some tress in your lifetime.
5554359Sroberto *
5654359Sroberto * CONCLUSION:
5754359Sroberto * The behavior of the program derived from these three issues should be
5854359Sroberto * that during normal situations it quickly sets the time and allow the
5954359Sroberto * system to startup.
6054359Sroberto *
6154359Sroberto * However during abnormal conditions as detected by unresponsive servers,
6254359Sroberto * out-of-sync or bad responses and other detections, it should print out
6354359Sroberto * a simple but clear message and continue in a mellow way to get the best
6454359Sroberto * possible time. It may never get the time and if so should also indicate
6554359Sroberto * this.
6654359Sroberto *
6754359Sroberto * Rudy Nedved
6854359Sroberto * 18-May-1993
6954359Sroberto *
7054359Sroberto ****************************************************************
7154359Sroberto *
7254359Sroberto * Much of the above is confusing or no longer relevant.  For example,
7354359Sroberto * it is rare these days for a machine's console to be a printing terminal,
7454359Sroberto * so the comment about saving trees doesn't mean much.  Nonetheless,
7554359Sroberto * the basic principles still stand:
7654359Sroberto *
7754359Sroberto * - Work automatically, without human control or intervention.  To
7854359Sroberto *   this end, we use the same configuration file as ntpd itself, so
7954359Sroberto *   you don't have to specify servers or other information on the
8054359Sroberto *   command line.  We also recognize that sometimes we won't be able
8154359Sroberto *   to contact any servers, and give up in that event instead of
8254359Sroberto *   hanging forever.
8354359Sroberto *
8454359Sroberto * - Behave in a sane way, both internally and externally, even in the
8554359Sroberto *   face of insane conditions.  That means we back off quickly when
8654359Sroberto *   we don't hear a response, to avoid network congestion.  Like
8754359Sroberto *   ntpd, we verify responses from several servers before accepting
8854359Sroberto *   the new time data.
8954359Sroberto *
9054359Sroberto *   However, we don't assume that the local clock is right, or even
9154359Sroberto *   close, because it might not be at boot time, and we want to catch
9254359Sroberto *   and correct that situation.  This behaviour has saved us in several
9354359Sroberto *   instances.  On HP-UX 9.0x, there used to be a bug in adjtimed which
9454359Sroberto *   would cause the time to be set to some wild value, making the machine
9554359Sroberto *   essentially unusable (we use Kerberos authentication pervasively,
9654359Sroberto *   and it requires workstations and servers to have a time within five
9754359Sroberto *   minutes of the Kerberos server).  We also have problems on PC's
9854359Sroberto *   running both Linux and some Microsoft OS -- they tend to disagree
9954359Sroberto *   on what the BIOS clock should say, and who should update it, and
10054359Sroberto *   when.  On those systems, we not only run ntptimeset at boot, we
10154359Sroberto *   also reset the BIOS clock based on the result, so the correct
10254359Sroberto *   time will be retained across reboots.
10354359Sroberto *
10454359Sroberto * For these reasons, and others, we have continued to use this tool
10554359Sroberto * rather than ntpdate.  It is run automatically at boot time on every
10654359Sroberto * workstation and server in our facility.
10754359Sroberto *
10854359Sroberto * In the past, we called this program 'ntptime'.  Unfortunately, the
10954359Sroberto * ntp v4 distribution also includes a program with that name.  In
11054359Sroberto * order to avoid confusion, we have renamed our program 'ntptimeset',
11154359Sroberto * which more accurately describes what it does.
11254359Sroberto *
11354359Sroberto * Jeffrey T. Hutzelman (N3NHS) <jhutz+@cmu.edu>
11454359Sroberto * School of Computer Science - Research Computing Facility
11554359Sroberto * Carnegie Mellon University - Pittsburgh, PA
11654359Sroberto * 16-Aug-1999
11754359Sroberto *
11854359Sroberto */
11954359Sroberto
12054359Sroberto#ifdef HAVE_CONFIG_H
12154359Sroberto# include <config.h>
12254359Sroberto#endif
12354359Sroberto
124106163Sroberto#include "ntp_machine.h"
12582498Sroberto#include "ntp_fp.h"
12682498Sroberto#include "ntp.h"
12782498Sroberto#include "ntp_io.h"
12882498Sroberto#include "iosignal.h"
12982498Sroberto#include "ntp_unixtime.h"
13082498Sroberto#include "ntpdate.h"
13182498Sroberto#include "ntp_string.h"
13282498Sroberto#include "ntp_syslog.h"
13382498Sroberto#include "ntp_select.h"
13482498Sroberto#include "ntp_stdlib.h"
13582498Sroberto
13654359Sroberto#ifdef HAVE_UNISTD_H
13754359Sroberto# include <unistd.h>
13854359Sroberto#endif
13954359Sroberto
14054359Sroberto#include <stdio.h>
14154359Sroberto#include <signal.h>
14254359Sroberto#include <ctype.h>
14354359Sroberto#ifndef SYS_WINNT
144106163Sroberto# ifdef HAVE_SYS_SIGNAL_H
145106163Sroberto#  include <sys/signal.h>
146106163Sroberto# else
147106163Sroberto#  include <signal.h>
148106163Sroberto# endif
14954359Sroberto# include <sys/ioctl.h>
15054359Sroberto#endif /* SYS_WINNT */
15182498Sroberto
15254359Sroberto#ifdef HAVE_SYS_RESOURCE_H
15354359Sroberto# include <sys/resource.h>
15454359Sroberto#endif /* HAVE_SYS_RESOURCE_H */
15554359Sroberto
15654359Sroberto#ifdef SYS_VXWORKS
15754359Sroberto# include "ioLib.h"
15854359Sroberto# include "sockLib.h"
15954359Sroberto# include "timers.h"
16054359Sroberto#endif
16154359Sroberto
16254359Sroberto#include "recvbuff.h"
16354359Sroberto
16454359Sroberto#ifdef SYS_WINNT
16554359Sroberto# define TARGET_RESOLUTION 1  /* Try for 1-millisecond accuracy
16654359Sroberto				on Windows NT timers. */
16754359Sroberto#pragma comment(lib, "winmm")
16854359Sroberto#endif /* SYS_WINNT */
16954359Sroberto
17054359Sroberto/*
17154359Sroberto * Scheduling priority we run at
17254359Sroberto */
17354359Sroberto#ifndef SYS_VXWORKS
17454359Sroberto# define	NTPDATE_PRIO	(-12)
17554359Sroberto#else
17654359Sroberto# define	NTPDATE_PRIO	(100)
17754359Sroberto#endif
17854359Sroberto
17954359Sroberto#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
18054359Sroberto/* POSIX TIMERS - vxWorks doesn't have itimer - casey */
18154359Srobertostatic timer_t ntpdate_timerid;
18254359Sroberto#endif
18354359Sroberto
18454359Sroberto/*
18554359Sroberto * Compatibility stuff for Version 2
18654359Sroberto */
18754359Sroberto#define NTP_MAXSKW	0x28f	/* 0.01 sec in fp format */
18854359Sroberto#define NTP_MINDIST 0x51f	/* 0.02 sec in fp format */
18954359Sroberto#define NTP_INFIN	15	/* max stratum, infinity a la Bellman-Ford */
19054359Sroberto#define NTP_MAXWGT	(8*FP_SECOND)	/* maximum select weight 8 seconds */
19154359Sroberto#define NTP_MAXLIST 5	/* maximum select list size */
19254359Sroberto#define PEER_SHIFT	8	/* 8 suitable for crystal time base */
19354359Sroberto
19454359Sroberto/*
19554359Sroberto * Debugging flag
19654359Sroberto */
19754359Srobertovolatile int debug = 0;
19854359Sroberto
19954359Sroberto/*
20054359Sroberto * File descriptor masks etc. for call to select
20154359Sroberto */
20254359Srobertoint fd;
20354359Srobertofd_set fdmask;
20454359Sroberto
20554359Sroberto/*
20654359Sroberto * Initializing flag.  All async routines watch this and only do their
20754359Sroberto * thing when it is clear.
20854359Sroberto */
20954359Srobertoint initializing = 1;
21054359Sroberto
21154359Sroberto/*
21254359Sroberto * Alarm flag.	Set when an alarm occurs
21354359Sroberto */
21454359Srobertovolatile int alarm_flag = 0;
21554359Sroberto
21654359Sroberto/*
21754359Sroberto * Set the time if valid time determined
21854359Sroberto */
21954359Srobertoint set_time = 0;
22054359Sroberto
22154359Sroberto/*
22254359Sroberto * transmission rate control
22354359Sroberto */
22454359Sroberto#define	MINTRANSMITS	(3)	/* minimum total packets per server */
22554359Sroberto#define	MAXXMITCOUNT	(2)	/* maximum packets per time interrupt */
22654359Sroberto
22754359Sroberto/*
22854359Sroberto * time setting constraints
22954359Sroberto */
23054359Sroberto#define	DESIREDDISP	(4*FP_SECOND)	/* desired dispersion, (fp 4) */
23154359Srobertoint max_period = DEFMAXPERIOD;
23254359Srobertoint min_servers = DEFMINSERVERS;
23354359Srobertoint min_valid = DEFMINVALID;
23454359Sroberto
23554359Sroberto/*
23654359Sroberto * counters related to time setting constraints
23754359Sroberto */
23854359Srobertoint contacted = 0;		/* # of servers we have sent to */
23954359Srobertoint responding = 0;		/* servers responding */
24054359Srobertoint validcount = 0;		/* servers with valid time */
24154359Srobertoint valid_n_low = 0;		/* valid time servers with low dispersion */
24254359Sroberto
24354359Sroberto/*
24454359Sroberto * Unpriviledged port flag.
24554359Sroberto */
24654359Srobertoint unpriv_port = 0;
24754359Sroberto
24854359Sroberto/*
24954359Sroberto * Program name.
25054359Sroberto */
25154359Srobertochar *progname;
25254359Sroberto
25354359Sroberto/*
25454359Sroberto * Systemwide parameters and flags
25554359Sroberto */
25654359Srobertostruct server **sys_servers;	/* the server list */
25754359Srobertoint sys_numservers = 0; 	/* number of servers to poll */
25854359Srobertoint sys_authenticate = 0;	/* true when authenticating */
25954359Srobertou_int32 sys_authkey = 0;	/* set to authentication key in use */
26054359Srobertou_long sys_authdelay = 0;	/* authentication delay */
26154359Sroberto
26254359Sroberto/*
26354359Sroberto * The current internal time
26454359Sroberto */
26554359Srobertou_long current_time = 0;
26654359Sroberto
26754359Sroberto/*
26854359Sroberto * File of encryption keys
26954359Sroberto */
27054359Sroberto
27154359Sroberto#ifndef KEYFILE
27254359Sroberto# ifndef SYS_WINNT
27354359Sroberto#define KEYFILE 	"/etc/ntp.keys"
27454359Sroberto# else
27554359Sroberto#define KEYFILE 	"%windir%\\ntp.keys"
27654359Sroberto# endif /* SYS_WINNT */
27754359Sroberto#endif /* KEYFILE */
27854359Sroberto
27954359Sroberto#ifndef SYS_WINNT
28054359Srobertoconst char *key_file = KEYFILE;
28154359Sroberto#else
28254359Srobertochar key_file_storage[MAX_PATH+1], *key_file ;
28354359Sroberto#endif	 /* SYS_WINNT */
28454359Sroberto
28554359Sroberto/*
28654359Sroberto * total packet counts
28754359Sroberto */
28854359Srobertou_long total_xmit = 0;
28954359Srobertou_long total_recv = 0;
29054359Sroberto
29154359Sroberto/*
29254359Sroberto * Miscellaneous flags
29354359Sroberto */
29454359Srobertoint verbose = 0;
29554359Sroberto#define	HORRIBLEOK	3	/* how many packets to let out */
29654359Srobertoint horrible = 0;	/* how many packets we drop for testing */
29754359Srobertoint secondhalf = 0;	/* second half of timeout period */
29854359Srobertoint printmsg = 0;	/* print time response analysis */
29954359Sroberto
30054359Sroberto/*
30154359Sroberto * The half time and finish time in internal time
30254359Sroberto */
30354359Srobertou_long half_time = 0;
30454359Srobertou_long finish_time = 0;
30554359Sroberto
30654359Sroberto
30754359Srobertoint	ntptimesetmain	P((int argc, char *argv[]));
30854359Srobertostatic	void	analysis	P((int final));
30954359Srobertostatic	int	have_enough	P((void));
31054359Srobertostatic	void	transmit	P((register struct server *server));
31154359Srobertostatic	void	receive		P((struct recvbuf *rbufp));
31254359Srobertostatic	void	clock_filter P((register struct server *server, s_fp d, l_fp *c));
31354359Srobertostatic	void	clock_count	P((void));
31454359Srobertostatic	struct server *clock_select P((void));
31554359Srobertostatic	void	set_local_clock	P((void));
31654359Srobertostatic	struct server *findserver P((struct sockaddr_in *addr));
31754359Srobertostatic	void	timer		P((void));
31854359Sroberto#ifndef SYS_WINNT
31954359Srobertostatic	RETSIGTYPE 	alarming	P((int sig));
32054359Sroberto#endif /* SYS_WINNT */
32154359Srobertostatic	void	init_alarm	P((void));
32254359Srobertostatic	void	init_io		P((void));
32354359Srobertostatic	int	sendpkt		P((struct sockaddr_in *dest, struct pkt *pkt, int len));
32454359Sroberto	void 	input_handler	P((l_fp *xts));
32554359Srobertostatic	void	printserver	P((register struct server *pp, FILE *fp));
32654359Sroberto#if !defined(HAVE_VSPRINTF)
32754359Srobertoint	vsprintf	P((char *str, const char *fmt, va_list ap));
32854359Sroberto#endif
32954359Sroberto
33054359Sroberto#ifdef HAVE_SIGNALED_IO
33154359Srobertoextern  void    wait_for_signal P((void));
33254359Srobertoextern  void    unblock_io_and_alarm P((void));
33354359Srobertoextern  void    block_io_and_alarm P((void));
33454359Sroberto#endif
33554359Sroberto
33654359Sroberto
33754359Sroberto#ifdef NO_MAIN_ALLOWED
33854359SrobertoCALL(ntptimeset,"ntptimeset",ntptimesetmain);
33954359Sroberto
34054359Srobertovoid clear_globals()
34154359Sroberto{
34254359Sroberto  /*
34354359Sroberto   * Debugging flag
34454359Sroberto   */
34554359Sroberto  debug = 0;
34654359Sroberto
34754359Sroberto  ntp_optind = 0;
34854359Sroberto
34954359Sroberto  /*
35054359Sroberto   * Initializing flag.  All async routines watch this and only do their
35154359Sroberto   * thing when it is clear.
35254359Sroberto   */
35354359Sroberto  initializing = 1;
35454359Sroberto
35554359Sroberto  /*
35654359Sroberto   * Alarm flag.  Set when an alarm occurs
35754359Sroberto   */
35854359Sroberto  alarm_flag = 0;
35954359Sroberto
36054359Sroberto  /*
36154359Sroberto   * Unpriviledged port flag.
36254359Sroberto   */
36354359Sroberto  unpriv_port = 0;
36454359Sroberto
36554359Sroberto  /*
36654359Sroberto   * Systemwide parameters and flags
36754359Sroberto   */
36854359Sroberto  sys_numservers = 0;	  /* number of servers to poll */
36954359Sroberto  sys_authenticate = 0;   /* true when authenticating */
37054359Sroberto  sys_authkey = 0;	   /* set to authentication key in use */
37154359Sroberto  sys_authdelay = 0;   /* authentication delay */
37254359Sroberto
37354359Sroberto  /*
37454359Sroberto   * The current internal time
37554359Sroberto   */
37654359Sroberto  current_time = 0;
37754359Sroberto
37854359Sroberto  verbose = 0;
37954359Sroberto}
38054359Sroberto#endif /* NO_MAIN_ALLOWED */
38154359Sroberto
38254359Sroberto/*
38354359Sroberto * Main program.  Initialize us and loop waiting for I/O and/or
38454359Sroberto * timer expiries.
38554359Sroberto */
38654359Sroberto#ifndef NO_MAIN_ALLOWED
38754359Srobertoint
38854359Srobertomain(
38954359Sroberto	int argc,
39054359Sroberto	char *argv[]
39154359Sroberto	)
39254359Sroberto{
39354359Sroberto	return ntptimesetmain(argc, argv);
39454359Sroberto}
39554359Sroberto#endif /* NO_MAIN_ALLOWED */
39654359Sroberto
39754359Sroberto
39854359Srobertoint
39954359Srobertontptimesetmain(
40054359Sroberto	int argc,
40154359Sroberto	char *argv[]
40254359Sroberto	)
40354359Sroberto{
40454359Sroberto	int was_alarmed;
405182007Sroberto	int tot_recvbufs;
40654359Sroberto	struct recvbuf *rbuf;
40754359Sroberto	l_fp tmp;
40854359Sroberto	int errflg;
40954359Sroberto	int c;
41054359Sroberto	extern char *ntp_optarg;
41154359Sroberto	extern int ntp_optind;
41254359Sroberto	int ltmp;
41354359Sroberto	char *cfgpath;
41454359Sroberto
41554359Sroberto#ifdef SYS_WINNT
41654359Sroberto	HANDLE process_handle;
41754359Sroberto
41854359Sroberto	wVersionRequested = MAKEWORD(1,1);
41954359Sroberto	if (WSAStartup(wVersionRequested, &wsaData)) {
42054359Sroberto		msyslog(LOG_ERR, "No useable winsock.dll: %m");
42154359Sroberto		exit(1);
42254359Sroberto	}
42354359Sroberto#endif /* SYS_WINNT */
42454359Sroberto
42554359Sroberto#ifdef NO_MAIN_ALLOWED
42654359Sroberto	clear_globals();
42754359Sroberto#endif
42854359Sroberto
42954359Sroberto	errflg = 0;
43054359Sroberto	cfgpath = 0;
43154359Sroberto	progname = argv[0];
43254359Sroberto	syslogit = 0;
43354359Sroberto
43454359Sroberto	/*
43554359Sroberto	 * Decode argument list
43654359Sroberto	 */
43754359Sroberto	while ((c = ntp_getopt(argc, argv, "a:c:de:slt:uvHS:V:")) != EOF)
43854359Sroberto		switch (c)
43954359Sroberto		{
44054359Sroberto		case 'a':
44154359Sroberto			c = atoi(ntp_optarg);
44254359Sroberto			sys_authenticate = 1;
44354359Sroberto			sys_authkey = c;
44454359Sroberto			break;
44554359Sroberto		case 'c':
44654359Sroberto			cfgpath = ntp_optarg;
44754359Sroberto			break;
44854359Sroberto		case 'd':
44954359Sroberto			++debug;
45054359Sroberto			break;
45154359Sroberto		case 'e':
45254359Sroberto			if (!atolfp(ntp_optarg, &tmp)
45354359Sroberto			    || tmp.l_ui != 0) {
45454359Sroberto				(void) fprintf(stderr,
45554359Sroberto				    "%s: encryption delay %s is unlikely\n",
45654359Sroberto				    progname, ntp_optarg);
45754359Sroberto				errflg++;
45854359Sroberto			} else {
45954359Sroberto				sys_authdelay = tmp.l_uf;
46054359Sroberto			}
46154359Sroberto			break;
46254359Sroberto		case 's':
46354359Sroberto			set_time = 1;
46454359Sroberto			break;
46554359Sroberto		case 'l':
46654359Sroberto			syslogit = 1;
46754359Sroberto			break;
46854359Sroberto		case 't':
46954359Sroberto			ltmp = atoi(ntp_optarg);
47054359Sroberto			if (ltmp <= 0) {
47154359Sroberto			    (void) fprintf(stderr,
47254359Sroberto				"%s: maximum time period (%d) is invalid\n",
47354359Sroberto				progname, ltmp);
47454359Sroberto			    errflg++;
47554359Sroberto			}
47654359Sroberto			else
47754359Sroberto			    max_period = ltmp;
47854359Sroberto			break;
47954359Sroberto		case 'u':
48054359Sroberto			unpriv_port = 1;
48154359Sroberto			break;
48254359Sroberto		case 'v':
48354359Sroberto			++verbose;
48454359Sroberto			break;
48554359Sroberto		case 'H':
48654359Sroberto			horrible++;
48754359Sroberto			break;
48854359Sroberto		case 'S':
48954359Sroberto			ltmp = atoi(ntp_optarg);
49054359Sroberto			if (ltmp <= 0) {
49154359Sroberto			    (void) fprintf(stderr,
49254359Sroberto				"%s: minimum responding (%d) is invalid\n",
49354359Sroberto				progname, ltmp);
49454359Sroberto			    errflg++;
49554359Sroberto			}
49654359Sroberto			else
49754359Sroberto			    min_servers = ltmp;
49854359Sroberto			break;
49954359Sroberto		case 'V':
50054359Sroberto			ltmp = atoi(ntp_optarg);
50154359Sroberto			if (ltmp <= 0) {
50254359Sroberto			    (void) fprintf(stderr,
50354359Sroberto				"%s: minimum valid (%d) is invalid\n",
50454359Sroberto				progname, ltmp);
50554359Sroberto			    errflg++;
50654359Sroberto			}
50754359Sroberto			else
50854359Sroberto			    min_valid = ltmp;
50954359Sroberto			break;
51054359Sroberto		case '?':
51154359Sroberto			++errflg;
51254359Sroberto			break;
51354359Sroberto		default:
51454359Sroberto			break;
51554359Sroberto		}
51654359Sroberto
51754359Sroberto
51854359Sroberto	if (errflg || ntp_optind < argc) {
51954359Sroberto		fprintf(stderr,"usage: %s [switches...]\n",progname);
52054359Sroberto		fprintf(stderr,"  -v       (verbose)\n");
52154359Sroberto		fprintf(stderr,"  -c path  (set config file path)\n");
52254359Sroberto		fprintf(stderr,"  -a key   (authenticate using key)\n");
52354359Sroberto		fprintf(stderr,"  -e delay (authentication delay)\n");
52454359Sroberto		fprintf(stderr,"  -S num   (# of servers that must respond)\n");
52554359Sroberto		fprintf(stderr,"  -V num   (# of servers that must valid)\n");
52654359Sroberto		fprintf(stderr,"  -s       (set the time based if okay)\n");
52754359Sroberto		fprintf(stderr,"  -t secs  (time period before ending)\n");
52854359Sroberto		fprintf(stderr,"  -l       (use syslog facility)\n");
52954359Sroberto		fprintf(stderr,"  -u       (use unprivileged port)\n");
53054359Sroberto		fprintf(stderr,"  -H       (drop packets for debugging)\n");
53154359Sroberto		fprintf(stderr,"  -d       (debug output)\n");
53254359Sroberto		exit(2);
53354359Sroberto	}
53454359Sroberto
53554359Sroberto	/*
53654359Sroberto	 * Logging.  Open the syslog if we have to
53754359Sroberto	 */
53854359Sroberto	if (syslogit) {
53954359Sroberto#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
54054359Sroberto# ifndef	LOG_DAEMON
54154359Sroberto		openlog("ntptimeset", LOG_PID);
54254359Sroberto# else
54354359Sroberto
54454359Sroberto#  ifndef	LOG_NTP
54554359Sroberto#	define	LOG_NTP LOG_DAEMON
54654359Sroberto#  endif
54754359Sroberto		openlog("ntptimeset", LOG_PID | LOG_NDELAY, LOG_NTP);
54854359Sroberto		if (debug)
54954359Sroberto			setlogmask(LOG_UPTO(LOG_DEBUG));
55054359Sroberto		else
55154359Sroberto			setlogmask(LOG_UPTO(LOG_INFO));
55254359Sroberto# endif /* LOG_DAEMON */
55354359Sroberto#endif	/* SYS_WINNT */
55454359Sroberto	}
55554359Sroberto
55654359Sroberto	if (debug || verbose)
55754359Sroberto		msyslog(LOG_INFO, "%s", Version);
55854359Sroberto
55954359Sroberto	if (horrible)
56054359Sroberto		msyslog(LOG_INFO, "Dropping %d out of %d packets",
56154359Sroberto			horrible,horrible+HORRIBLEOK);
56254359Sroberto	/*
56354359Sroberto	 * Add servers we are going to be polling
56454359Sroberto	 */
56554359Sroberto	loadservers(cfgpath);
56654359Sroberto
56754359Sroberto	if (sys_numservers < min_servers) {
56854359Sroberto		msyslog(LOG_ERR, "Found %d servers, require %d servers",
56954359Sroberto			sys_numservers,min_servers);
57054359Sroberto		exit(2);
57154359Sroberto	}
57254359Sroberto
57354359Sroberto	/*
57454359Sroberto	 * determine when we will end at least
57554359Sroberto 	 */
57654359Sroberto	finish_time = max_period * TIMER_HZ;
57754359Sroberto	half_time = finish_time >> 1;
57854359Sroberto
57954359Sroberto	/*
58054359Sroberto	 * Initialize the time of day routines and the I/O subsystem
58154359Sroberto	 */
58254359Sroberto	if (sys_authenticate) {
58354359Sroberto		init_auth();
58454359Sroberto#ifdef SYS_WINNT
58554359Sroberto		if (!key_file) key_file = KEYFILE;
58654359Sroberto		if (!ExpandEnvironmentStrings(key_file, key_file_storage, MAX_PATH))
58754359Sroberto		{
58854359Sroberto			msyslog(LOG_ERR, "ExpandEnvironmentStrings(%s) failed: %m\n",
58954359Sroberto				key_file);
59054359Sroberto		} else {
59154359Sroberto			key_file = key_file_storage;
59254359Sroberto		}
59354359Sroberto#endif /* SYS_WINNT */
59454359Sroberto
59554359Sroberto		if (!authreadkeys(key_file)) {
59654359Sroberto			msyslog(LOG_ERR, "no key file, exiting");
59754359Sroberto			exit(1);
59854359Sroberto		}
59954359Sroberto		if (!authistrusted(sys_authkey)) {
60054359Sroberto			char buf[10];
60154359Sroberto
60254359Sroberto			(void) sprintf(buf, "%lu", (unsigned long)sys_authkey);
60354359Sroberto			msyslog(LOG_ERR, "authentication key %s unknown", buf);
60454359Sroberto			exit(1);
60554359Sroberto		}
60654359Sroberto	}
60754359Sroberto	init_io();
60854359Sroberto	init_alarm();
60954359Sroberto
61054359Sroberto	/*
61154359Sroberto	 * Set the priority.
61254359Sroberto	 */
61354359Sroberto#ifdef SYS_VXWORKS
61454359Sroberto	taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
61554359Sroberto#endif
61654359Sroberto#if defined(HAVE_ATT_NICE)
61754359Sroberto	nice (NTPDATE_PRIO);
61854359Sroberto#endif
61954359Sroberto#if defined(HAVE_BSD_NICE)
62054359Sroberto	(void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
62154359Sroberto#endif
62254359Sroberto#ifdef SYS_WINNT
62354359Sroberto	process_handle = GetCurrentProcess();
62454359Sroberto	if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
62554359Sroberto		msyslog(LOG_ERR, "SetPriorityClass failed: %m");
62654359Sroberto	}
62754359Sroberto#endif /* SYS_WINNT */
62854359Sroberto
62954359Sroberto	initializing = 0;
63054359Sroberto
63154359Sroberto	/*
63254359Sroberto	 * Use select() on all on all input fd's for unlimited
63354359Sroberto	 * time.  select() will terminate on SIGALARM or on the
63454359Sroberto	 * reception of input.	Using select() means we can't do
63554359Sroberto	 * robust signal handling and we get a potential race
63654359Sroberto	 * between checking for alarms and doing the select().
63754359Sroberto	 * Mostly harmless, I think.
63854359Sroberto	 * Keep going until we have enough information, or time is up.
63954359Sroberto	 */
64054359Sroberto	/* On VMS, I suspect that select() can't be interrupted
64154359Sroberto	 * by a "signal" either, so I take the easy way out and
64254359Sroberto	 * have select() time out after one second.
64354359Sroberto	 * System clock updates really aren't time-critical,
64454359Sroberto	 * and - lacking a hardware reference clock - I have
64554359Sroberto	 * yet to learn about anything else that is.
64654359Sroberto	 */
64754359Sroberto	was_alarmed = 0;
64854359Sroberto	while (finish_time > current_time) {
64954359Sroberto#if !defined(HAVE_SIGNALED_IO)
65054359Sroberto		fd_set rdfdes;
65154359Sroberto		int nfound;
65254359Sroberto#elif defined(HAVE_SIGNALED_IO)
65354359Sroberto		block_io_and_alarm();
65454359Sroberto#endif
65554359Sroberto
656182007Sroberto		tot_recvbufs = full_recvbuffs();	/* get received buffers */
65754359Sroberto		if (printmsg) {
65854359Sroberto			printmsg = 0;
65954359Sroberto			analysis(0);
66054359Sroberto		}
66154359Sroberto		if (alarm_flag) {		/* alarmed? */
66254359Sroberto			was_alarmed = 1;
66354359Sroberto			alarm_flag = 0;
66454359Sroberto		}
66554359Sroberto
666182007Sroberto		if (!was_alarmed && tot_recvbufs > 0) {
66754359Sroberto			/*
66854359Sroberto			 * Nothing to do.  Wait for something.
66954359Sroberto			 */
67054359Sroberto#ifndef HAVE_SIGNALED_IO
67154359Sroberto			rdfdes = fdmask;
67254359Sroberto# if defined(VMS) || defined(SYS_VXWORKS)
67354359Sroberto			/* make select() wake up after one second */
67454359Sroberto			{
67554359Sroberto				struct timeval t1;
67654359Sroberto
67754359Sroberto				t1.tv_sec = 1; t1.tv_usec = 0;
67854359Sroberto				nfound = select(fd+1, &rdfdes, (fd_set *)0,
67954359Sroberto						(fd_set *)0, &t1);
68054359Sroberto			}
68154359Sroberto# else
68254359Sroberto			nfound = select(fd+1, &rdfdes, (fd_set *)0,
68354359Sroberto					(fd_set *)0, (struct timeval *)0);
68454359Sroberto# endif /* VMS */
68554359Sroberto			if (nfound > 0) {
68654359Sroberto				l_fp ts;
68754359Sroberto				get_systime(&ts);
68854359Sroberto				(void)input_handler(&ts);
68954359Sroberto			}
69054359Sroberto			else if (nfound == -1 && errno != EINTR)
69154359Sroberto				msyslog(LOG_ERR, "select() error: %m");
69254359Sroberto			else if (debug) {
69354359Sroberto# if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 /* to unclutter log */
69454359Sroberto				msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
69554359Sroberto# endif
69654359Sroberto			}
69754359Sroberto#else /* HAVE_SIGNALED_IO */
69854359Sroberto
69954359Sroberto			wait_for_signal();
70054359Sroberto#endif /* HAVE_SIGNALED_IO */
70154359Sroberto			if (alarm_flag) 	/* alarmed? */
70254359Sroberto			{
70354359Sroberto				was_alarmed = 1;
70454359Sroberto				alarm_flag = 0;
70554359Sroberto			}
706182007Sroberto			tot_recvbufs = full_recvbuffs();  /* get received buffers */
70754359Sroberto		}
70854359Sroberto#ifdef HAVE_SIGNALED_IO
70954359Sroberto		unblock_io_and_alarm();
71054359Sroberto#endif /* HAVE_SIGNALED_IO */
71154359Sroberto
71254359Sroberto		/*
71354359Sroberto		 * Out here, signals are unblocked.  Call timer routine
71454359Sroberto		 * to process expiry.
71554359Sroberto		 */
71654359Sroberto		if (was_alarmed)
71754359Sroberto		{
71854359Sroberto			timer();
71954359Sroberto			was_alarmed = 0;
72054359Sroberto		}
72154359Sroberto
72254359Sroberto		/*
72354359Sroberto		 * Call the data procedure to handle each received
72454359Sroberto		 * packet.
72554359Sroberto		 */
726182007Sroberto		rbuf = get_full_recv_buffer();
727182007Sroberto		while (rbuf != NULL)
72854359Sroberto		{
72954359Sroberto			receive(rbuf);
73054359Sroberto			freerecvbuf(rbuf);
731182007Sroberto			rbuf = get_full_recv_buffer();
73254359Sroberto		}
73354359Sroberto
73454359Sroberto		/*
73554359Sroberto		 * Do we have enough information to stop now?
73654359Sroberto		 */
73754359Sroberto		if (have_enough())
73854359Sroberto			break;	/* time to end */
73954359Sroberto
74054359Sroberto		/*
74154359Sroberto		 * Go around again
74254359Sroberto		 */
74354359Sroberto	}
74454359Sroberto
74554359Sroberto	/*
74654359Sroberto	 * adjust the clock and exit accordingly
74754359Sroberto	 */
74854359Sroberto	set_local_clock();
74954359Sroberto
75054359Sroberto	/*
75154359Sroberto	 * if we get here then we are in trouble
75254359Sroberto	 */
75354359Sroberto	return(1);
75454359Sroberto}
75554359Sroberto
75654359Sroberto
75754359Sroberto/*
75854359Sroberto * analysis - print a message indicating what is happening with time service
75954359Sroberto *	      must mimic have_enough() procedure.
76054359Sroberto */
76154359Srobertostatic void
76254359Srobertoanalysis(
76354359Sroberto	int final
76454359Sroberto	)
76554359Sroberto{
76654359Sroberto	if (contacted < sys_numservers) {
76754359Sroberto		printf("%d servers of %d have been probed with %d packets\n",
76854359Sroberto		       contacted,sys_numservers,MINTRANSMITS);
76954359Sroberto		return;
77054359Sroberto	}
77154359Sroberto	if (!responding) {
77254359Sroberto		printf("No response from any of %d servers, network problem?\n",
77354359Sroberto		       sys_numservers);
77454359Sroberto		return;
77554359Sroberto	}
77654359Sroberto	else if (responding < min_servers) {
77754359Sroberto		printf("%d servers out of %d responding, need at least %d.\n",
77854359Sroberto		       responding, sys_numservers, min_servers);
77954359Sroberto		return;
78054359Sroberto	}
78154359Sroberto	if (!validcount) {
78254359Sroberto		printf("%d servers responding but none have valid time\n",
78354359Sroberto		       responding);
78454359Sroberto		return;
78554359Sroberto	}
78654359Sroberto	else if (validcount < min_valid) {
78754359Sroberto		printf("%d servers responding, %d are valid, need %d valid\n",
78854359Sroberto		       responding,validcount,min_valid);
78954359Sroberto		return;
79054359Sroberto	}
79154359Sroberto	if (!final && valid_n_low != validcount) {
79254359Sroberto		printf("%d valid servers but only %d have low dispersion\n",
79354359Sroberto		       validcount,valid_n_low);
79454359Sroberto		return;
79554359Sroberto	}
79654359Sroberto}
79754359Sroberto
79854359Sroberto
79954359Sroberto/* have_enough - see if we have enough information to terminate probing
80054359Sroberto */
80154359Srobertostatic int
80254359Srobertohave_enough(void)
80354359Sroberto{
80454359Sroberto	/* have we contacted all servers yet? */
80554359Sroberto	if (contacted < sys_numservers)
80654359Sroberto		return 0;	/* no...try some more */
80754359Sroberto
80854359Sroberto	/* have we got at least minimum servers responding? */
80954359Sroberto	if (responding < min_servers)
81054359Sroberto		return 0;	/* no...try some more */
81154359Sroberto
81254359Sroberto	/* count the clocks */
81354359Sroberto	(void) clock_count();
81454359Sroberto
81554359Sroberto	/* have we got at least minimum valid clocks? */
81654359Sroberto	if (validcount <= 0 || validcount < min_valid)
81754359Sroberto		return 0;	/* no...try some more */
81854359Sroberto
81954359Sroberto	/* do we have all valid servers with low dispersion */
82054359Sroberto	if (!secondhalf && valid_n_low != validcount)
82154359Sroberto		return 0;
82254359Sroberto
82354359Sroberto	/* if we get into the secondhalf then we ignore dispersion */
82454359Sroberto
82554359Sroberto	/* all conditions have been met...end */
82654359Sroberto	return 1;
82754359Sroberto}
82854359Sroberto
82954359Sroberto
83054359Sroberto/*
83154359Sroberto * transmit - transmit a packet to the given server, or mark it completed.
83254359Sroberto *	      This is called by the timeout routine and by the receive
83354359Sroberto *	      procedure.
83454359Sroberto */
83554359Srobertostatic void
83654359Srobertotransmit(
83754359Sroberto	register struct server *server
83854359Sroberto	)
83954359Sroberto{
84054359Sroberto	struct pkt xpkt;
84154359Sroberto	int timeout;
84254359Sroberto
84354359Sroberto	if (debug > 2)
84454359Sroberto		printf("transmit(%s)\n", ntoa(&server->srcadr));
84554359Sroberto
84654359Sroberto	if ((server->reach & 01) == 0) {
84754359Sroberto		l_fp ts;
84854359Sroberto		/*
84954359Sroberto		 * Last message to this server timed out.  Shift
85054359Sroberto		 * zeros into the filter.
85154359Sroberto		 */
85254359Sroberto		L_CLR(&ts);
85354359Sroberto		clock_filter(server, 0, &ts);
85454359Sroberto	}
85554359Sroberto
85654359Sroberto	/*
85754359Sroberto	 * shift reachable register over
85854359Sroberto	 */
85954359Sroberto	server->reach <<= 1;
86054359Sroberto
86154359Sroberto	/*
86254359Sroberto	 * If we're here, send another message to the server.  Fill in
86354359Sroberto	 * the packet and let 'er rip.
86454359Sroberto	 */
86554359Sroberto	xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
86654359Sroberto		server->version, MODE_CLIENT);
86754359Sroberto	xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
86854359Sroberto	xpkt.ppoll = NTP_MINPOLL;
86954359Sroberto	xpkt.precision = NTPDATE_PRECISION;
87054359Sroberto	xpkt.rootdelay = htonl(NTPDATE_DISTANCE);
87154359Sroberto	xpkt.rootdispersion = htonl(NTPDATE_DISP);
87254359Sroberto	xpkt.refid = htonl(NTPDATE_REFID);
87354359Sroberto	L_CLR(&xpkt.reftime);
87454359Sroberto	L_CLR(&xpkt.org);
87554359Sroberto	L_CLR(&xpkt.rec);
87654359Sroberto
87754359Sroberto	/*
87854359Sroberto	 * Determine whether to authenticate or not.  If so,
87954359Sroberto	 * fill in the extended part of the packet and do it.
88054359Sroberto	 * If not, just timestamp it and send it away.
88154359Sroberto	 */
88254359Sroberto	if (sys_authenticate) {
88354359Sroberto		int len;
88454359Sroberto
88582498Sroberto		xpkt.exten[0] = htonl(sys_authkey);
88654359Sroberto		get_systime(&server->xmt);
88754359Sroberto		L_ADDUF(&server->xmt, sys_authdelay);
88854359Sroberto		HTONL_FP(&server->xmt, &xpkt.xmt);
88954359Sroberto		len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC);
89054359Sroberto		if (sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len))) {
89154359Sroberto			if (debug > 1)
89254359Sroberto				printf("failed transmit auth to %s\n",
89354359Sroberto				    ntoa(&(server->srcadr)));
89454359Sroberto			return;
89554359Sroberto		}
89654359Sroberto
89754359Sroberto		if (debug > 1)
89854359Sroberto			printf("transmit auth to %s\n",
89954359Sroberto			    ntoa(&(server->srcadr)));
90054359Sroberto	} else {
90154359Sroberto		get_systime(&(server->xmt));
90254359Sroberto		HTONL_FP(&server->xmt, &xpkt.xmt);
90354359Sroberto		if (sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC)) {
90454359Sroberto			if (debug > 1)
90554359Sroberto				printf("failed transmit to %s\n",
90654359Sroberto				    ntoa(&(server->srcadr)));
90754359Sroberto			return;
90854359Sroberto		}
90954359Sroberto
91054359Sroberto		if (debug > 1)
91154359Sroberto			printf("transmit to %s\n", ntoa(&(server->srcadr)));
91254359Sroberto	}
91354359Sroberto
91454359Sroberto	/*
91554359Sroberto	 * count transmits, record contacted count and set transmit time
91654359Sroberto	 */
91754359Sroberto	if (++server->xmtcnt == MINTRANSMITS)
91854359Sroberto	    contacted++;
91954359Sroberto	server->last_xmit = current_time;
92054359Sroberto
92154359Sroberto	/*
92254359Sroberto	 * determine timeout for this packet. The more packets we send
92354359Sroberto	 * to the host, the slower we get. If the host indicates that
92454359Sroberto	 * it is not "sane" then we expect even less.
92554359Sroberto	 */
92654359Sroberto	if (server->xmtcnt < MINTRANSMITS) {
92754359Sroberto	    /* we have not sent enough */
92854359Sroberto	    timeout = TIMER_HZ;		/* 1 second probe */
92954359Sroberto	}
93054359Sroberto	else if (server->rcvcnt <= 0) {
93154359Sroberto	    /* we have heard nothing */
93254359Sroberto	    if (secondhalf)
93354359Sroberto		timeout = TIMER_HZ<<4;	/* 16 second probe */
93454359Sroberto	    else
93554359Sroberto		timeout = TIMER_HZ<<3;	/* 8 second probe */
93654359Sroberto	}
93754359Sroberto	else {
93854359Sroberto	    /* if we have low dispersion then probe infrequently */
93954359Sroberto	    if (server->dispersion <= DESIREDDISP)
94054359Sroberto		timeout = TIMER_HZ<<4;	/* 16 second probe */
94154359Sroberto	    /* if the server is not in sync then let it alone */
94254359Sroberto	    else if (server->leap == LEAP_NOTINSYNC)
94354359Sroberto		timeout = TIMER_HZ<<4;	/* 16 second probe */
94454359Sroberto	    /* if the server looks broken ignore it */
94554359Sroberto	    else if (server->org.l_ui < server->reftime.l_ui)
94654359Sroberto		timeout = TIMER_HZ<<5;	/* 32 second probe */
94754359Sroberto	    else if (secondhalf)
94854359Sroberto		timeout = TIMER_HZ<<2;	/* 4 second probe */
94954359Sroberto	    else
95054359Sroberto		timeout = TIMER_HZ<<1;	/* 2 second probe */
95154359Sroberto	}
95254359Sroberto
95354359Sroberto	/*
95454359Sroberto	 * set next transmit time based on timeout
95554359Sroberto	 */
95654359Sroberto	server->event_time = current_time + timeout;
95754359Sroberto}
95854359Sroberto
95954359Sroberto
96054359Sroberto/*
96154359Sroberto * receive - receive and process an incoming frame
96254359Sroberto */
96354359Srobertostatic void
96454359Srobertoreceive(
96554359Sroberto	struct recvbuf *rbufp
96654359Sroberto	)
96754359Sroberto{
96854359Sroberto	register struct pkt *rpkt;
96954359Sroberto	register struct server *server;
97054359Sroberto	register s_fp di;
97154359Sroberto	l_fp t10, t23;
97254359Sroberto	l_fp org;
97354359Sroberto	l_fp rec;
97454359Sroberto	l_fp ci;
97554359Sroberto	int has_mac;
97654359Sroberto	int is_authentic;
97754359Sroberto
97854359Sroberto	if (debug > 2)
97954359Sroberto		printf("receive(%s)\n", ntoa(&rbufp->srcadr));
98054359Sroberto	/*
98154359Sroberto	 * Check to see if the packet basically looks like something
98254359Sroberto	 * intended for us.
98354359Sroberto	 */
98454359Sroberto	if (rbufp->recv_length == LEN_PKT_NOMAC)
98554359Sroberto		has_mac = 0;
98654359Sroberto	else if (rbufp->recv_length >= LEN_PKT_NOMAC)
98754359Sroberto		has_mac = 1;
98854359Sroberto	else {
98954359Sroberto		if (debug > 2)
99054359Sroberto			printf("receive: packet length %d\n",
99154359Sroberto			    rbufp->recv_length);
99254359Sroberto		return;		/* funny length packet */
99354359Sroberto	}
99454359Sroberto
99554359Sroberto	rpkt = &(rbufp->recv_pkt);
99654359Sroberto	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
99754359Sroberto	    PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
99854359Sroberto		if (debug > 1)
99954359Sroberto			printf("receive: bad version %d\n",
100054359Sroberto			       PKT_VERSION(rpkt->li_vn_mode));
100154359Sroberto		return;
100254359Sroberto	}
100354359Sroberto
100454359Sroberto	if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
100554359Sroberto	    && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
100682498Sroberto	    || rpkt->stratum >=STRATUM_UNSPEC) {
100754359Sroberto		if (debug > 1)
100854359Sroberto			printf("receive: mode %d stratum %d\n",
100954359Sroberto			    PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
101054359Sroberto		return;
101154359Sroberto	}
101254359Sroberto
101354359Sroberto	/*
101454359Sroberto	 * So far, so good.  See if this is from a server we know.
101554359Sroberto	 */
101654359Sroberto	server = findserver(&(rbufp->srcadr));
101754359Sroberto	if (server == NULL) {
101854359Sroberto		if (debug > 1)
101954359Sroberto			printf("receive: server not found\n");
102054359Sroberto		return;
102154359Sroberto	}
102254359Sroberto
102354359Sroberto	/*
102454359Sroberto	 * Decode the org timestamp and make sure we're getting a response
102554359Sroberto	 * to our last request.
102654359Sroberto	 */
102754359Sroberto	NTOHL_FP(&rpkt->org, &org);
102854359Sroberto	if (!L_ISEQU(&org, &server->xmt)) {
102954359Sroberto		if (debug > 1)
103054359Sroberto			printf("receive: pkt.org and peer.xmt differ\n");
103154359Sroberto		return;
103254359Sroberto	}
103354359Sroberto
103454359Sroberto	/*
103554359Sroberto	 * Check out the authenticity if we're doing that.
103654359Sroberto	 */
103754359Sroberto	if (!sys_authenticate)
103854359Sroberto		is_authentic = 1;
103954359Sroberto	else {
104054359Sroberto		is_authentic = 0;
104154359Sroberto
104254359Sroberto		if (debug > 3)
104354359Sroberto			printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n",
104482498Sroberto			   (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey,
104554359Sroberto			   (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt,
104654359Sroberto				LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC)));
104754359Sroberto
104882498Sroberto		if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey &&
104954359Sroberto			authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC,
105054359Sroberto			(int)(rbufp->recv_length - LEN_PKT_NOMAC)))
105154359Sroberto			is_authentic = 1;
105254359Sroberto		if (debug)
105354359Sroberto			printf("receive: authentication %s\n",
105454359Sroberto			   is_authentic ? "passed" : "failed");
105554359Sroberto	}
105654359Sroberto	server->trust <<= 1;
105754359Sroberto	if (!is_authentic)
105854359Sroberto		server->trust |= 1;
105954359Sroberto
106054359Sroberto	/*
106154359Sroberto	 * Looks good.  Record info from the packet.
106254359Sroberto	 */
106354359Sroberto	server->leap = PKT_LEAP(rpkt->li_vn_mode);
106454359Sroberto	server->stratum = PKT_TO_STRATUM(rpkt->stratum);
106554359Sroberto	server->precision = rpkt->precision;
106654359Sroberto	server->rootdelay = ntohl(rpkt->rootdelay);
106754359Sroberto	server->rootdispersion = ntohl(rpkt->rootdispersion);
106854359Sroberto	server->refid = rpkt->refid;
106954359Sroberto	NTOHL_FP(&rpkt->reftime, &server->reftime);
107054359Sroberto	NTOHL_FP(&rpkt->rec, &rec);
107154359Sroberto	NTOHL_FP(&rpkt->xmt, &server->org);
107254359Sroberto
107354359Sroberto	/*
107454359Sroberto	 * count this guy as responding
107554359Sroberto	 */
107654359Sroberto	server->reach |= 1;
107754359Sroberto	if (server->rcvcnt++ == 0)
107854359Sroberto		responding++;
107954359Sroberto
108054359Sroberto	/*
108154359Sroberto	 * Make sure the server is at least somewhat sane.  If not, ignore
108254359Sroberto	 * it for later.
108354359Sroberto	 */
108454359Sroberto	if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
108554359Sroberto		if (debug > 1)
108654359Sroberto			printf("receive: pkt insane\n");
108754359Sroberto		return;
108854359Sroberto	}
108954359Sroberto
109054359Sroberto	/*
109154359Sroberto	 * Calculate the round trip delay (di) and the clock offset (ci).
109254359Sroberto	 * We use the equations (reordered from those in the spec):
109354359Sroberto	 *
109454359Sroberto	 * d = (t2 - t3) - (t1 - t0)
109554359Sroberto	 * c = ((t2 - t3) + (t1 - t0)) / 2
109654359Sroberto	 */
109754359Sroberto	t10 = server->org;		/* pkt.xmt == t1 */
109854359Sroberto	L_SUB(&t10, &rbufp->recv_time);	/* recv_time == t0*/
109954359Sroberto
110054359Sroberto	t23 = rec;			/* pkt.rec == t2 */
110154359Sroberto	L_SUB(&t23, &org);		/* pkt->org == t3 */
110254359Sroberto
110354359Sroberto	/* now have (t2 - t3) and (t0 - t1).  Calculate (ci) and (di) */
110454359Sroberto	ci = t10;
110554359Sroberto	L_ADD(&ci, &t23);
110654359Sroberto	L_RSHIFT(&ci);
110754359Sroberto
110854359Sroberto	/*
110954359Sroberto	 * Calculate di in t23 in full precision, then truncate
111054359Sroberto	 * to an s_fp.
111154359Sroberto	 */
111254359Sroberto	L_SUB(&t23, &t10);
111354359Sroberto	di = LFPTOFP(&t23);
111454359Sroberto
111554359Sroberto	if (debug > 3)
111654359Sroberto		printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5));
111754359Sroberto
111854359Sroberto	di += (FP_SECOND >> (-(int)NTPDATE_PRECISION))
111954359Sroberto	    + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW;
112054359Sroberto
112154359Sroberto	if (di <= 0) {		/* value still too raunchy to use? */
112254359Sroberto		L_CLR(&ci);
112354359Sroberto		di = 0;
112454359Sroberto	} else {
112554359Sroberto		di = max(di, NTP_MINDIST);
112654359Sroberto	}
112754359Sroberto
112854359Sroberto
112954359Sroberto	/*
113054359Sroberto	 * This one is valid.  Give it to clock_filter(),
113154359Sroberto	 */
113254359Sroberto	clock_filter(server, di, &ci);
113354359Sroberto	if (debug > 1)
113454359Sroberto		printf("receive from %s\n", ntoa(&rbufp->srcadr));
113554359Sroberto
113654359Sroberto	/*
113754359Sroberto	 * See if we should goes the transmission. If not return now
113854359Sroberto	 * otherwise have the next event time be shortened
113954359Sroberto	 */
114054359Sroberto	if (server->stratum <= NTP_INFIN)
114154359Sroberto	    return;	/* server does not have a stratum */
114254359Sroberto	if (server->leap == LEAP_NOTINSYNC)
114354359Sroberto	    return;	/* just booted server or out of sync */
114454359Sroberto	if (!L_ISHIS(&server->org, &server->reftime))
114554359Sroberto	    return;	/* broken host */
114654359Sroberto	if (server->trust != 0)
114754359Sroberto	    return;	/* can not trust it */
114854359Sroberto
114954359Sroberto	if (server->dispersion < DESIREDDISP)
115054359Sroberto	    return;	/* we have the desired dispersion */
115154359Sroberto
115254359Sroberto	server->event_time -= (TIMER_HZ+1);
115354359Sroberto}
115454359Sroberto
115554359Sroberto
115654359Sroberto/*
115754359Sroberto * clock_filter - add clock sample, determine a server's delay, dispersion
115854359Sroberto *                and offset
115954359Sroberto */
116054359Srobertostatic void
116154359Srobertoclock_filter(
116254359Sroberto	register struct server *server,
116354359Sroberto	s_fp di,
116454359Sroberto	l_fp *c
116554359Sroberto	)
116654359Sroberto{
116754359Sroberto	register int i, j;
116854359Sroberto	int ord[NTP_SHIFT];
116954359Sroberto
117054359Sroberto	/*
117154359Sroberto	 * Insert sample and increment nextpt
117254359Sroberto	 */
117354359Sroberto
117454359Sroberto	i = server->filter_nextpt;
117554359Sroberto	server->filter_delay[i] = di;
117654359Sroberto	server->filter_offset[i] = *c;
117754359Sroberto	server->filter_soffset[i] = LFPTOFP(c);
117854359Sroberto	server->filter_nextpt++;
117954359Sroberto	if (server->filter_nextpt >= NTP_SHIFT)
118054359Sroberto		server->filter_nextpt = 0;
118154359Sroberto
118254359Sroberto	/*
118354359Sroberto	 * Sort indices into increasing delay order
118454359Sroberto	 */
118554359Sroberto	for (i = 0; i < NTP_SHIFT; i++)
118654359Sroberto		ord[i] = i;
118754359Sroberto
118854359Sroberto	for (i = 0; i < (NTP_SHIFT-1); i++) {
118954359Sroberto		for (j = i+1; j < NTP_SHIFT; j++) {
119054359Sroberto			if (server->filter_delay[ord[j]] == 0)
119154359Sroberto				continue;
119254359Sroberto			if (server->filter_delay[ord[i]] == 0
119354359Sroberto			    || (server->filter_delay[ord[i]]
119454359Sroberto			    > server->filter_delay[ord[j]])) {
119554359Sroberto				register int tmp;
119654359Sroberto
119754359Sroberto				tmp = ord[i];
119854359Sroberto				ord[i] = ord[j];
119954359Sroberto				ord[j] = tmp;
120054359Sroberto			}
120154359Sroberto		}
120254359Sroberto	}
120354359Sroberto
120454359Sroberto	/*
120554359Sroberto	 * Now compute the dispersion, and assign values to delay and
120654359Sroberto	 * offset.  If there are no samples in the register, delay and
120754359Sroberto	 * offset go to zero and dispersion is set to the maximum.
120854359Sroberto	 */
120954359Sroberto	if (server->filter_delay[ord[0]] == 0) {
121054359Sroberto		server->delay = 0;
121154359Sroberto		L_CLR(&server->offset);
121254359Sroberto		server->soffset = 0;
121354359Sroberto		server->dispersion = PEER_MAXDISP;
121454359Sroberto	} else {
121554359Sroberto		register s_fp d;
121654359Sroberto
121754359Sroberto		server->delay = server->filter_delay[ord[0]];
121854359Sroberto		server->offset = server->filter_offset[ord[0]];
121954359Sroberto		server->soffset = LFPTOFP(&server->offset);
122054359Sroberto		server->dispersion = 0;
122154359Sroberto		for (i = 1; i < NTP_SHIFT; i++) {
122254359Sroberto			if (server->filter_delay[ord[i]] == 0)
122354359Sroberto				d = PEER_MAXDISP;
122454359Sroberto			else {
122554359Sroberto				d = server->filter_soffset[ord[i]]
122654359Sroberto				    - server->filter_soffset[ord[0]];
122754359Sroberto				if (d < 0)
122854359Sroberto					d = -d;
122954359Sroberto				if (d > PEER_MAXDISP)
123054359Sroberto					d = PEER_MAXDISP;
123154359Sroberto			}
123254359Sroberto			/*
123354359Sroberto			 * XXX This *knows* PEER_FILTER is 1/2
123454359Sroberto			 */
123554359Sroberto			server->dispersion += (u_fp)(d) >> i;
123654359Sroberto		}
123754359Sroberto	}
123854359Sroberto	/*
123954359Sroberto	 * We're done
124054359Sroberto	 */
124154359Sroberto}
124254359Sroberto
124354359Sroberto
124454359Sroberto/* clock_count - count the clock sources we have
124554359Sroberto */
124654359Srobertostatic void
124754359Srobertoclock_count(void)
124854359Sroberto{
124954359Sroberto	register struct server *server;
125054359Sroberto	register int n;
125154359Sroberto
125254359Sroberto	/* reset counts */
125354359Sroberto	validcount = valid_n_low = 0;
125454359Sroberto
125554359Sroberto	/* go through the list of servers and count the clocks we believe
125654359Sroberto	 * and that have low dispersion
125754359Sroberto	 */
125854359Sroberto	for (n = 0; n < sys_numservers; n++) {
125954359Sroberto		server = sys_servers[n];
126054359Sroberto		if (server->delay == 0) {
126154359Sroberto			continue;	/* no data */
126254359Sroberto		}
126354359Sroberto		if (server->stratum > NTP_INFIN) {
126454359Sroberto			continue;	/* stratum no good */
126554359Sroberto		}
126654359Sroberto		if (server->delay > NTP_MAXWGT) {
126754359Sroberto			continue;	/* too far away */
126854359Sroberto		}
126954359Sroberto		if (server->leap == LEAP_NOTINSYNC)
127054359Sroberto			continue;	/* he's in trouble */
127154359Sroberto		if (!L_ISHIS(&server->org, &server->reftime)) {
127254359Sroberto			continue;	/* very broken host */
127354359Sroberto		}
127454359Sroberto		if ((server->org.l_ui - server->reftime.l_ui) >= NTP_MAXAGE) {
127554359Sroberto			continue;	/* too long without sync */
127654359Sroberto		}
127754359Sroberto		if (server->trust != 0) {
127854359Sroberto			continue;
127954359Sroberto		}
128054359Sroberto
128154359Sroberto		/*
128254359Sroberto		 * This one is a valid time source..
128354359Sroberto		 */
128454359Sroberto		validcount++;
128554359Sroberto
128654359Sroberto		/*
128754359Sroberto		 * See if this one has a okay low dispersion
128854359Sroberto		 */
128954359Sroberto		if (server->dispersion <= DESIREDDISP)
129054359Sroberto		    valid_n_low++;
129154359Sroberto	}
129254359Sroberto
129354359Sroberto	if (debug > 1)
129454359Sroberto		printf("have %d, valid %d, low %d\n",
129554359Sroberto			responding, validcount, valid_n_low);
129654359Sroberto}
129754359Sroberto
129854359Sroberto
129954359Sroberto/*
130054359Sroberto * clock_select - select the pick-of-the-litter clock from the samples
130154359Sroberto *		  we've got.
130254359Sroberto */
130354359Srobertostatic struct server *
130454359Srobertoclock_select(void)
130554359Sroberto{
130654359Sroberto	register struct server *server;
130754359Sroberto	register int i;
130854359Sroberto	register int nlist;
130954359Sroberto	register s_fp d;
131054359Sroberto	register int j;
131154359Sroberto	register int n;
131254359Sroberto	s_fp local_threshold;
131354359Sroberto	struct server *server_list[NTP_MAXCLOCK];
131454359Sroberto	u_fp server_badness[NTP_MAXCLOCK];
131554359Sroberto	struct server *sys_server;
131654359Sroberto
131754359Sroberto	/*
131854359Sroberto	 * This first chunk of code is supposed to go through all
131954359Sroberto	 * servers we know about to find the NTP_MAXLIST servers which
132054359Sroberto	 * are most likely to succeed.  We run through the list
132154359Sroberto	 * doing the sanity checks and trying to insert anyone who
132254359Sroberto	 * looks okay.  We are at all times aware that we should
132354359Sroberto	 * only keep samples from the top two strata and we only need
132454359Sroberto	 * NTP_MAXLIST of them.
132554359Sroberto	 */
132654359Sroberto	nlist = 0;	/* none yet */
132754359Sroberto	for (n = 0; n < sys_numservers; n++) {
132854359Sroberto		server = sys_servers[n];
132954359Sroberto		if (server->delay == 0)
133054359Sroberto			continue;	/* no data */
133154359Sroberto		if (server->stratum > NTP_INFIN)
133254359Sroberto			continue;	/* stratum no good */
133354359Sroberto		if (server->delay > NTP_MAXWGT) {
133454359Sroberto			continue;	/* too far away */
133554359Sroberto		}
133654359Sroberto		if (server->leap == LEAP_NOTINSYNC)
133754359Sroberto			continue;	/* he's in trouble */
133854359Sroberto		if (!L_ISHIS(&server->org, &server->reftime)) {
133954359Sroberto			continue;	/* very broken host */
134054359Sroberto		}
134154359Sroberto		if ((server->org.l_ui - server->reftime.l_ui)
134254359Sroberto		    >= NTP_MAXAGE) {
134354359Sroberto			continue;	/* too long without sync */
134454359Sroberto		}
134554359Sroberto		if (server->trust != 0) {
134654359Sroberto			continue;
134754359Sroberto		}
134854359Sroberto
134954359Sroberto		/*
135054359Sroberto		 * This one seems sane.  Find where he belongs
135154359Sroberto		 * on the list.
135254359Sroberto		 */
135354359Sroberto		d = server->dispersion + server->dispersion;
135454359Sroberto		for (i = 0; i < nlist; i++)
135554359Sroberto			if (server->stratum <= server_list[i]->stratum)
135654359Sroberto				break;
135754359Sroberto		for ( ; i < nlist; i++) {
135854359Sroberto			if (server->stratum < server_list[i]->stratum)
135954359Sroberto				break;
136054359Sroberto			if (d < (s_fp) server_badness[i])
136154359Sroberto				break;
136254359Sroberto		}
136354359Sroberto
136454359Sroberto		/*
136554359Sroberto		 * If i points past the end of the list, this
136654359Sroberto		 * guy is a loser, else stick him in.
136754359Sroberto		 */
136854359Sroberto		if (i >= NTP_MAXLIST)
136954359Sroberto			continue;
137054359Sroberto		for (j = nlist; j > i; j--)
137154359Sroberto			if (j < NTP_MAXLIST) {
137254359Sroberto				server_list[j] = server_list[j-1];
137354359Sroberto				server_badness[j]
137454359Sroberto				    = server_badness[j-1];
137554359Sroberto			}
137654359Sroberto
137754359Sroberto		server_list[i] = server;
137854359Sroberto		server_badness[i] = d;
137954359Sroberto		if (nlist < NTP_MAXLIST)
138054359Sroberto			nlist++;
138154359Sroberto	}
138254359Sroberto
138354359Sroberto	/*
138454359Sroberto	 * Got the five-or-less best.  Cut the list where the number of
138554359Sroberto	 * strata exceeds two.
138654359Sroberto	 */
138754359Sroberto	j = 0;
138854359Sroberto	for (i = 1; i < nlist; i++)
138954359Sroberto		if (server_list[i]->stratum > server_list[i-1]->stratum)
139054359Sroberto			if (++j == 2) {
139154359Sroberto				nlist = i;
139254359Sroberto				break;
139354359Sroberto			}
139454359Sroberto
139554359Sroberto	/*
139654359Sroberto	 * Whew!  What we should have by now is 0 to 5 candidates for
139754359Sroberto	 * the job of syncing us.  If we have none, we're out of luck.
139854359Sroberto	 * If we have one, he's a winner.  If we have more, do falseticker
139954359Sroberto	 * detection.
140054359Sroberto	 */
140154359Sroberto
140254359Sroberto	if (nlist == 0)
140354359Sroberto		sys_server = 0;
140454359Sroberto	else if (nlist == 1) {
140554359Sroberto		sys_server = server_list[0];
140654359Sroberto	} else {
140754359Sroberto		/*
140854359Sroberto		 * Re-sort by stratum, bdelay estimate quality and
140954359Sroberto		 * server.delay.
141054359Sroberto		 */
141154359Sroberto		for (i = 0; i < nlist-1; i++)
141254359Sroberto			for (j = i+1; j < nlist; j++) {
141354359Sroberto				if (server_list[i]->stratum
141454359Sroberto				    < server_list[j]->stratum)
141554359Sroberto					break;	/* already sorted by stratum */
141654359Sroberto				if (server_list[i]->delay
141754359Sroberto				    < server_list[j]->delay)
141854359Sroberto					continue;
141954359Sroberto				server = server_list[i];
142054359Sroberto				server_list[i] = server_list[j];
142154359Sroberto				server_list[j] = server;
142254359Sroberto			}
142354359Sroberto
142454359Sroberto		/*
142554359Sroberto		 * Calculate the fixed part of the dispersion limit
142654359Sroberto		 */
142754359Sroberto		local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION))
142854359Sroberto		    + NTP_MAXSKW;
142954359Sroberto
143054359Sroberto		/*
143154359Sroberto		 * Now drop samples until we're down to one.
143254359Sroberto		 */
143354359Sroberto		while (nlist > 1) {
143454359Sroberto			for (n = 0; n < nlist; n++) {
143554359Sroberto				server_badness[n] = 0;
143654359Sroberto				for (j = 0; j < nlist; j++) {
143754359Sroberto					if (j == n)	/* with self? */
143854359Sroberto						continue;
143954359Sroberto					d = server_list[j]->soffset
144054359Sroberto					    - server_list[n]->soffset;
144154359Sroberto					if (d < 0)	/* absolute value */
144254359Sroberto						d = -d;
144354359Sroberto					/*
144454359Sroberto					 * XXX This code *knows* that
144554359Sroberto					 * NTP_SELECT is 3/4
144654359Sroberto					 */
144754359Sroberto					for (i = 0; i < j; i++)
144854359Sroberto						d = (d>>1) + (d>>2);
144954359Sroberto					server_badness[n] += d;
145054359Sroberto				}
145154359Sroberto			}
145254359Sroberto
145354359Sroberto			/*
145454359Sroberto			 * We now have an array of nlist badness
145554359Sroberto			 * coefficients.  Find the badest.  Find
145654359Sroberto			 * the minimum precision while we're at
145754359Sroberto			 * it.
145854359Sroberto			 */
145954359Sroberto			i = 0;
146054359Sroberto			n = server_list[0]->precision;;
146154359Sroberto			for (j = 1; j < nlist; j++) {
146254359Sroberto				if (server_badness[j] >= server_badness[i])
146354359Sroberto					i = j;
146454359Sroberto				if (n > server_list[j]->precision)
146554359Sroberto					n = server_list[j]->precision;
146654359Sroberto			}
146754359Sroberto
146854359Sroberto			/*
146954359Sroberto			 * i is the index of the server with the worst
147054359Sroberto			 * dispersion.  If his dispersion is less than
147154359Sroberto			 * the threshold, stop now, else delete him and
147254359Sroberto			 * continue around again.
147354359Sroberto			 */
147454359Sroberto			if (server_badness[i] < (local_threshold
147554359Sroberto						 + (FP_SECOND >> (-n))))
147654359Sroberto				break;
147754359Sroberto			for (j = i + 1; j < nlist; j++)
147854359Sroberto				server_list[j-1] = server_list[j];
147954359Sroberto			nlist--;
148054359Sroberto		}
148154359Sroberto
148254359Sroberto		/*
148354359Sroberto		 * What remains is a list of less than 5 servers.  Take
148454359Sroberto		 * the best.
148554359Sroberto		 */
148654359Sroberto		sys_server = server_list[0];
148754359Sroberto	}
148854359Sroberto
148954359Sroberto	/*
149054359Sroberto	 * That's it.  Return our server.
149154359Sroberto	 */
149254359Sroberto	return sys_server;
149354359Sroberto}
149454359Sroberto
149554359Sroberto
149654359Sroberto/*
149754359Sroberto * set_local_clock -- handle setting the local clock or displaying info.
149854359Sroberto */
149954359Srobertostatic void
150054359Srobertoset_local_clock(void)
150154359Sroberto{
150254359Sroberto	register int i;
150354359Sroberto	register struct server *server;
150454359Sroberto	time_t tmp;
150554359Sroberto	double dtemp;
150654359Sroberto
150754359Sroberto	/*
150854359Sroberto	 * if setting time then print final analysis
150954359Sroberto	 */
151054359Sroberto	if (set_time)
151154359Sroberto	    analysis(1);
151254359Sroberto
151354359Sroberto	/*
151454359Sroberto	 * pick a clock
151554359Sroberto	 */
151654359Sroberto	server = clock_select();
151754359Sroberto
151854359Sroberto	/*
151954359Sroberto	 * do some display of information
152054359Sroberto	 */
152154359Sroberto	if (debug || verbose) {
152254359Sroberto		for (i = 0; i < sys_numservers; i++)
152354359Sroberto			printserver(sys_servers[i], stdout);
152454359Sroberto		if (debug)
152554359Sroberto			printf("packets sent %ld, received %ld\n",
152654359Sroberto				total_xmit, total_recv);
152754359Sroberto	}
152854359Sroberto
152954359Sroberto	/*
153054359Sroberto	 * see if we have a server to set the time with
153154359Sroberto	 */
153254359Sroberto	if (server == 0) {
153354359Sroberto	    if (!set_time || verbose)
153454359Sroberto		fprintf(stdout,"No servers available to sync time with\n");
153554359Sroberto	    exit(1);
153654359Sroberto	}
153754359Sroberto
153854359Sroberto	/*
153954359Sroberto	 * we have a valid and selected time to use!!!!!
154054359Sroberto	 */
154154359Sroberto
154254359Sroberto	/*
154354359Sroberto	 * if we are not setting the time then display offset and exit
154454359Sroberto	 */
154554359Sroberto	if (!set_time) {
154654359Sroberto		fprintf(stdout,
154754359Sroberto			"Your clock is off by %s seconds. (%s) [%ld/%ld]\n",
154854359Sroberto			lfptoa(&server->offset, 7),
154954359Sroberto			ntoa(&server->srcadr),
155054359Sroberto			total_xmit, total_recv);
155154359Sroberto		exit(0);
155254359Sroberto	}
155354359Sroberto
155454359Sroberto	/*
155554359Sroberto	 * set the clock
155654359Sroberto	 * XXX: Examine the more flexible approach used by ntpdate.
155754359Sroberto	 * Note that a design consideration here is that we sometimes
155854359Sroberto	 * _want_ to step the clock by a _huge_ amount in either
155954359Sroberto	 * direction, because the local clock is completely bogus.
156054359Sroberto	 * This condition must be recognized and dealt with, so
156154359Sroberto	 * that we always get a good time when this completes.
156254359Sroberto	 * -- jhutz+@cmu.edu, 16-Aug-1999
156354359Sroberto	 */
156454359Sroberto	LFPTOD(&server->offset, dtemp);
156554359Sroberto	step_systime(dtemp);
156654359Sroberto	time(&tmp);
156754359Sroberto	fprintf(stdout,"Time set to %.20s [%s %s %ld/%ld]\n",
156854359Sroberto		ctime(&tmp)+4,
156954359Sroberto		ntoa(&server->srcadr),
157054359Sroberto		lfptoa(&server->offset, 7),
157154359Sroberto		total_xmit, total_recv);
157254359Sroberto	exit(0);
157354359Sroberto}
157454359Sroberto
157554359Sroberto
157654359Sroberto/*
157754359Sroberto * findserver - find a server in the list given its address
157854359Sroberto */
157954359Srobertostatic struct server *
158054359Srobertofindserver(
158154359Sroberto	struct sockaddr_in *addr
158254359Sroberto	)
158354359Sroberto{
158454359Sroberto	register int i;
158554359Sroberto	register u_int32 netnum;
158654359Sroberto
158754359Sroberto	if (htons(addr->sin_port) != NTP_PORT)
158854359Sroberto		return 0;
158954359Sroberto	netnum = addr->sin_addr.s_addr;
159054359Sroberto
159154359Sroberto	for (i = 0; i < sys_numservers; i++) {
159254359Sroberto		if (netnum == sys_servers[i]->srcadr.sin_addr.s_addr)
159354359Sroberto			return sys_servers[i];
159454359Sroberto	}
159554359Sroberto	return 0;
159654359Sroberto}
159754359Sroberto
159854359Sroberto
159954359Sroberto/*
160054359Sroberto * timer - process a timer interrupt
160154359Sroberto */
160254359Srobertostatic void
160354359Srobertotimer(void)
160454359Sroberto{
160554359Sroberto	register int k;
160654359Sroberto
160754359Sroberto	/*
160854359Sroberto	 * Bump the current idea of the time
160954359Sroberto	 */
161054359Sroberto	current_time++;
161154359Sroberto
161254359Sroberto	/*
161354359Sroberto	 * see if we have reached half time
161454359Sroberto	 */
161554359Sroberto	if (current_time >= half_time && !secondhalf) {
161654359Sroberto	    secondhalf++;
161754359Sroberto	    if (debug)
161854359Sroberto		printf("\nSecond Half of Timeout!\n");
161954359Sroberto	    printmsg++;
162054359Sroberto	}
162154359Sroberto
162254359Sroberto	/*
162354359Sroberto	 * We only want to send a few packets per transmit interrupt
162454359Sroberto	 * to throttle things
162554359Sroberto	 */
162654359Sroberto	for(k = 0;k < MAXXMITCOUNT;k++) {
162754359Sroberto	    register int i, oldi;
162854359Sroberto	    register u_long oldxtime;
162954359Sroberto
163054359Sroberto	    /*
163154359Sroberto	     * We want to send a packet out for a server that has an
163254359Sroberto	     * expired event time. However to be mellow about this, we only
163354359Sroberto	     * use one expired event timer and to avoid starvation we use
163454359Sroberto	     * the one with the oldest last transmit time.
163554359Sroberto	     */
163654359Sroberto	    oldi = -1;
163754359Sroberto	    oldxtime = 0;
163854359Sroberto	    for (i = 0; i < sys_numservers; i++) {
163954359Sroberto		if (sys_servers[i]->event_time <= current_time) {
164054359Sroberto		    if (oldi < 0 || oldxtime > sys_servers[i]->last_xmit) {
164154359Sroberto			oldxtime = sys_servers[i]->last_xmit;
164254359Sroberto			oldi = i;
164354359Sroberto		    }
164454359Sroberto		}
164554359Sroberto	    }
164654359Sroberto	    if (oldi >= 0)
164754359Sroberto		transmit(sys_servers[oldi]);
164854359Sroberto	    else
164954359Sroberto		break;	/* no expired event */
165054359Sroberto	} /* end of transmit loop */
165154359Sroberto}
165254359Sroberto
165354359Sroberto
165454359Sroberto#ifndef SYS_WINNT
165554359Sroberto/*
165654359Sroberto * alarming - record the occurance of an alarm interrupt
165754359Sroberto */
165854359Srobertostatic RETSIGTYPE
165954359Srobertoalarming(
166054359Sroberto	int sig
166154359Sroberto	)
166254359Sroberto#else
166354359Srobertovoid CALLBACK
166454359Srobertoalarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
166554359Sroberto#endif /* SYS_WINNT */
166654359Sroberto{
166754359Sroberto	alarm_flag++;
166854359Sroberto}
166954359Sroberto
167054359Sroberto
167154359Sroberto/*
167254359Sroberto * init_alarm - set up the timer interrupt
167354359Sroberto */
167454359Srobertostatic void
167554359Srobertoinit_alarm(void)
167654359Sroberto{
167754359Sroberto#ifndef SYS_WINNT
167854359Sroberto# ifndef HAVE_TIMER_SETTIME
167954359Sroberto	struct itimerval itimer;
168054359Sroberto# else
168154359Sroberto	struct itimerspec ntpdate_itimer;
168254359Sroberto# endif
168354359Sroberto#else
168454359Sroberto	TIMECAPS tc;
168554359Sroberto	UINT wTimerRes, wTimerID;
168654359Sroberto# endif /* SYS_WINNT */
168754359Sroberto#if defined SYS_CYGWIN32 || defined SYS_WINNT
168854359Sroberto	HANDLE hToken;
168954359Sroberto	TOKEN_PRIVILEGES tkp;
169054359Sroberto	DWORD dwUser = 0;
169154359Sroberto#endif /* SYS_WINNT */
169254359Sroberto
169354359Sroberto	alarm_flag = 0;
169454359Sroberto
169554359Sroberto#ifndef SYS_WINNT
169654359Sroberto# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
169754359Sroberto	alarm_flag = 0;
169854359Sroberto	/* this code was put in as setitimer() is non existant this us the
169954359Sroberto	 * POSIX "equivalents" setup - casey
170054359Sroberto	 */
170154359Sroberto	/* ntpdate_timerid is global - so we can kill timer later */
170254359Sroberto	if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
170354359Sroberto#  ifdef SYS_VXWORKS
170454359Sroberto		ERROR
170554359Sroberto#  else
170654359Sroberto		-1
170754359Sroberto#  endif
170854359Sroberto		)
170954359Sroberto	{
171054359Sroberto		fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
171154359Sroberto		return;
171254359Sroberto	}
171354359Sroberto
171454359Sroberto	/*	TIMER_HZ = (5)
171554359Sroberto	 * Set up the alarm interrupt.	The first comes 1/(2*TIMER_HZ)
171654359Sroberto	 * seconds from now and they continue on every 1/TIMER_HZ seconds.
171754359Sroberto	 */
171854359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
171954359Sroberto	ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
172054359Sroberto	ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
172154359Sroberto	ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
172254359Sroberto	timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
172354359Sroberto# else
172454359Sroberto	/*
172554359Sroberto	 * Set up the alarm interrupt.	The first comes 1/(2*TIMER_HZ)
172654359Sroberto	 * seconds from now and they continue on every 1/TIMER_HZ seconds.
172754359Sroberto	 */
172854359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
172954359Sroberto	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
173054359Sroberto	itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
173154359Sroberto	itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
173254359Sroberto	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
173354359Sroberto# endif
173454359Sroberto#if defined SYS_CYGWIN32
173554359Sroberto	/*
173654359Sroberto	 * Get previleges needed for fiddling with the clock
173754359Sroberto	 */
173854359Sroberto
173954359Sroberto	/* get the current process token handle */
174054359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
174154359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
174254359Sroberto		exit(1);
174354359Sroberto	}
174454359Sroberto	/* get the LUID for system-time privilege. */
174554359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
174654359Sroberto	tkp.PrivilegeCount = 1;  /* one privilege to set */
174754359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
174854359Sroberto	/* get set-time privilege for this process. */
174954359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
175054359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
175154359Sroberto	if (GetLastError() != ERROR_SUCCESS)
175254359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
175354359Sroberto#endif
175454359Sroberto#else	/* SYS_WINNT */
175554359Sroberto	_tzset();
175654359Sroberto
175754359Sroberto	/*
175854359Sroberto	 * Get previleges needed for fiddling with the clock
175954359Sroberto	 */
176054359Sroberto
176154359Sroberto	/* get the current process token handle */
176254359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
176354359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
176454359Sroberto		exit(1);
176554359Sroberto	}
176654359Sroberto	/* get the LUID for system-time privilege. */
176754359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
176854359Sroberto	tkp.PrivilegeCount = 1;  /* one privilege to set */
176954359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
177054359Sroberto	/* get set-time privilege for this process. */
177154359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
177254359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
177354359Sroberto	if (GetLastError() != ERROR_SUCCESS)
177454359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
177554359Sroberto
177654359Sroberto	/*
177754359Sroberto	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
177854359Sroberto	 * Under Win/NT, expiry of timer interval leads to invocation
177954359Sroberto	 * of a callback function (on a different thread) rather than
178054359Sroberto	 * generating an alarm signal
178154359Sroberto	 */
178254359Sroberto
178354359Sroberto	/* determine max and min resolution supported */
178454359Sroberto	if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
178554359Sroberto		msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
178654359Sroberto		exit(1);
178754359Sroberto	}
178854359Sroberto	wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
178954359Sroberto	/* establish the minimum timer resolution that we'll use */
179054359Sroberto	timeBeginPeriod(wTimerRes);
179154359Sroberto
179254359Sroberto	/* start the timer event */
179354359Sroberto	wTimerID = timeSetEvent(
179454359Sroberto		(UINT) (1000/TIMER_HZ),    /* Delay */
179554359Sroberto		wTimerRes,			 /* Resolution */
179654359Sroberto		(LPTIMECALLBACK) alarming, /* Callback function */
179754359Sroberto		(DWORD) dwUser, 	 /* User data */
179854359Sroberto		TIME_PERIODIC); 	 /* Event type (periodic) */
179954359Sroberto	if (wTimerID == 0) {
180054359Sroberto		msyslog(LOG_ERR, "timeSetEvent failed: %m");
180154359Sroberto		exit(1);
180254359Sroberto	}
180354359Sroberto#endif /* SYS_WINNT */
180454359Sroberto}
180554359Sroberto
180654359Sroberto
180754359Sroberto/*
180854359Sroberto * init_io - initialize I/O data and open socket
180954359Sroberto */
181054359Srobertostatic void
181154359Srobertoinit_io(void)
181254359Sroberto{
181354359Sroberto#ifdef SYS_WINNT
181454359Sroberto    	WORD wVersionRequested;
181554359Sroberto	WSADATA wsaData;
181654359Sroberto	init_transmitbuff();
181754359Sroberto#endif /* SYS_WINNT */
181854359Sroberto
181954359Sroberto	/*
182054359Sroberto	 * Init buffer free list and stat counters
182154359Sroberto	 */
182254359Sroberto	init_recvbuff(sys_numservers + 2);
182354359Sroberto
182454359Sroberto#if defined(HAVE_SIGNALED_IO)
182554359Sroberto	set_signal();
182654359Sroberto#endif
182754359Sroberto
182854359Sroberto#ifdef SYS_WINNT
182954359Sroberto	wVersionRequested = MAKEWORD(1,1);
183054359Sroberto	if (WSAStartup(wVersionRequested, &wsaData))
183154359Sroberto	{
183254359Sroberto		msyslog(LOG_ERR, "No useable winsock.dll: %m");
183354359Sroberto		exit(1);
183454359Sroberto	}
183554359Sroberto#endif /* SYS_WINNT */
183654359Sroberto
183754359Sroberto	BLOCKIO();
183854359Sroberto
183954359Sroberto	/* create a datagram (UDP) socket */
184054359Sroberto	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
184154359Sroberto		msyslog(LOG_ERR, "socket() failed: %m");
184254359Sroberto		exit(1);
184354359Sroberto		/*NOTREACHED*/
184454359Sroberto	}
184554359Sroberto
184654359Sroberto	/*
184754359Sroberto	 * bind the socket to the NTP port
184854359Sroberto	 */
184954359Sroberto	if (!debug && set_time && !unpriv_port) {
185054359Sroberto		struct sockaddr_in addr;
185154359Sroberto
185254359Sroberto		memset((char *)&addr, 0, sizeof addr);
185354359Sroberto		addr.sin_family = AF_INET;
185454359Sroberto		addr.sin_port = htons(NTP_PORT);
185554359Sroberto		addr.sin_addr.s_addr = htonl(INADDR_ANY);
185654359Sroberto		if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
185754359Sroberto#ifndef SYS_WINNT
185854359Sroberto			if (errno == EADDRINUSE)
185954359Sroberto#else
186054359Sroberto			if (WSAGetLastError() == WSAEADDRINUSE)
186154359Sroberto#endif
186254359Sroberto				msyslog(LOG_ERR,
186354359Sroberto				    "the NTP socket is in use, exiting");
186454359Sroberto			else
186554359Sroberto				msyslog(LOG_ERR, "bind() fails: %m");
186654359Sroberto			exit(1);
186754359Sroberto		}
186854359Sroberto	}
186954359Sroberto
187054359Sroberto	FD_ZERO(&fdmask);
187154359Sroberto	FD_SET(fd, &fdmask);
187254359Sroberto
187354359Sroberto	/*
187454359Sroberto	 * set non-blocking,
187554359Sroberto	 */
187654359Sroberto
187754359Sroberto#ifdef USE_FIONBIO
187854359Sroberto	/* in vxWorks we use FIONBIO, but the others are defined for old systems, so
187954359Sroberto	 * all hell breaks loose if we leave them defined
188054359Sroberto	 */
188154359Sroberto#undef O_NONBLOCK
188254359Sroberto#undef FNDELAY
188354359Sroberto#undef O_NDELAY
188454359Sroberto#endif
188554359Sroberto
188654359Sroberto#if defined(O_NONBLOCK) /* POSIX */
188754359Sroberto	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
188854359Sroberto	{
188954359Sroberto		msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m");
189054359Sroberto		exit(1);
189154359Sroberto		/*NOTREACHED*/
189254359Sroberto	}
189354359Sroberto#elif defined(FNDELAY)
189454359Sroberto	if (fcntl(fd, F_SETFL, FNDELAY) < 0)
189554359Sroberto	{
189654359Sroberto		msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
189754359Sroberto		exit(1);
189854359Sroberto		/*NOTREACHED*/
189954359Sroberto	}
190054359Sroberto#elif defined(O_NDELAY) /* generally the same as FNDELAY */
190154359Sroberto	if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
190254359Sroberto	{
190354359Sroberto		msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m");
190454359Sroberto		exit(1);
190554359Sroberto		/*NOTREACHED*/
190654359Sroberto	}
190754359Sroberto#elif defined(FIONBIO)
190854359Sroberto	if (
190954359Sroberto# if defined(VMS)
191054359Sroberto		(ioctl(fd,FIONBIO,&1) < 0)
191154359Sroberto# elif defined(SYS_WINNT)
191254359Sroberto		(ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR)
191354359Sroberto# else
191454359Sroberto		(ioctl(fd,FIONBIO,&on) < 0)
191554359Sroberto# endif
191654359Sroberto	   )
191754359Sroberto	{
191854359Sroberto		msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
191954359Sroberto		exit(1);
192054359Sroberto		/*NOTREACHED*/
192154359Sroberto	}
192254359Sroberto#elif defined(FIOSNBIO)
192354359Sroberto	if (ioctl(fd,FIOSNBIO,&on) < 0)
192454359Sroberto	{
192554359Sroberto		msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m");
192654359Sroberto		exit(1);
192754359Sroberto		/*NOTREACHED*/
192854359Sroberto	}
192954359Sroberto#else
193054359Sroberto# include "Bletch: Need non-blocking I/O!"
193154359Sroberto#endif
193254359Sroberto
193354359Sroberto#ifdef HAVE_SIGNALED_IO
193454359Sroberto	init_socket_sig(fd);
193554359Sroberto#endif /* not HAVE_SIGNALED_IO */
193654359Sroberto
193754359Sroberto	UNBLOCKIO();
193854359Sroberto}
193954359Sroberto
194054359Sroberto
194154359Sroberto/*
194254359Sroberto * sendpkt - send a packet to the specified destination
194354359Sroberto */
194454359Srobertostatic int
194554359Srobertosendpkt(
194654359Sroberto	struct sockaddr_in *dest,
194754359Sroberto	struct pkt *pkt,
194854359Sroberto	int len
194954359Sroberto	)
195054359Sroberto{
195154359Sroberto	int cc;
195254359Sroberto	static int horriblecnt = 0;
195354359Sroberto#ifdef SYS_WINNT
195454359Sroberto	DWORD err;
195554359Sroberto#endif /* SYS_WINNT */
195654359Sroberto
195754359Sroberto	total_xmit++;	/* count it */
195854359Sroberto
195954359Sroberto	if (horrible) {
196054359Sroberto	    if (++horriblecnt > HORRIBLEOK) {
196154359Sroberto		if (debug > 3)
196254359Sroberto			printf("dropping send (%s)\n", ntoa(dest));
196354359Sroberto		if (horriblecnt >= HORRIBLEOK+horrible)
196454359Sroberto		    horriblecnt = 0;
196554359Sroberto		return 0;
196654359Sroberto	    }
196754359Sroberto	}
196854359Sroberto
196954359Sroberto
197082498Sroberto	cc = sendto(fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest,
197154359Sroberto	    sizeof(struct sockaddr_in));
197254359Sroberto#ifndef SYS_WINNT
197354359Sroberto	if (cc == -1) {
197454359Sroberto		if (errno != EWOULDBLOCK && errno != ENOBUFS)
197554359Sroberto#else
197654359Sroberto	if (cc == SOCKET_ERROR) {
197754359Sroberto		err = WSAGetLastError();
197854359Sroberto		if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
197954359Sroberto#endif /* SYS_WINNT */
198054359Sroberto			msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
198154359Sroberto		return -1;
198254359Sroberto	}
198354359Sroberto	return 0;
198454359Sroberto}
198554359Sroberto
198654359Sroberto
198754359Sroberto/*
198854359Sroberto * input_handler - receive packets asynchronously
198954359Sroberto */
199054359Srobertovoid
199154359Srobertoinput_handler(l_fp *xts)
199254359Sroberto{
199354359Sroberto	register int n;
199454359Sroberto	register struct recvbuf *rb;
199554359Sroberto	struct timeval tvzero;
199654359Sroberto	int fromlen;
199754359Sroberto	fd_set fds;
199854359Sroberto	l_fp ts;
199954359Sroberto	ts = *xts; /* we ignore xts, but make the compiler happy */
200054359Sroberto
200154359Sroberto	/*
200254359Sroberto	 * Do a poll to see if we have data
200354359Sroberto	 */
200454359Sroberto	for (;;) {
200554359Sroberto		fds = fdmask;
200654359Sroberto		tvzero.tv_sec = tvzero.tv_usec = 0;
200754359Sroberto		n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
200854359Sroberto
200954359Sroberto		/*
201054359Sroberto		 * If nothing to do, just return.  If an error occurred,
201154359Sroberto		 * complain and return.  If we've got some, freeze a
201254359Sroberto		 * timestamp.
201354359Sroberto		 */
201454359Sroberto		if (n == 0)
201554359Sroberto			return;
201654359Sroberto		else if (n == -1) {
201754359Sroberto			if (errno != EINTR) {
201854359Sroberto				msyslog(LOG_ERR, "select() error: %m");
201954359Sroberto			}
202054359Sroberto			return;
202154359Sroberto		}
202254359Sroberto		get_systime(&ts);
202354359Sroberto
202454359Sroberto		/*
202554359Sroberto		 * Get a buffer and read the frame.  If we
202654359Sroberto		 * haven't got a buffer, or this is received
202754359Sroberto		 * on the wild card socket, just dump the packet.
202854359Sroberto		 */
202954359Sroberto		if (initializing || free_recvbuffs == 0) {
203054359Sroberto			char buf[100];
203154359Sroberto
203254359Sroberto#ifndef SYS_WINNT
203354359Sroberto			(void) read(fd, buf, sizeof buf);
203454359Sroberto#else
203554359Sroberto			/* NT's _read does not operate on nonblocking sockets
203654359Sroberto			 * either recvfrom or ReadFile() has to be used here.
203754359Sroberto			 * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
203854359Sroberto			 * just to be different use recvfrom() here
203954359Sroberto			 */
204054359Sroberto			recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
204154359Sroberto#endif /* SYS_WINNT */
204254359Sroberto			continue;
204354359Sroberto		}
204454359Sroberto
204554359Sroberto		rb = get_free_recv_buffer();
204654359Sroberto
204754359Sroberto		fromlen = sizeof(struct sockaddr_in);
204854359Sroberto		rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt,
204954359Sroberto		    sizeof(rb->recv_pkt), 0,
205054359Sroberto		    (struct sockaddr *)&rb->srcadr, &fromlen);
205154359Sroberto		if (rb->recv_length == -1) {
205254359Sroberto			freerecvbuf(rb);
205354359Sroberto			continue;
205454359Sroberto		}
205554359Sroberto
205654359Sroberto		/*
205754359Sroberto		 * Got one.  Mark how and when it got here,
205854359Sroberto		 * put it on the full list.
205954359Sroberto		 */
206054359Sroberto		rb->recv_time = ts;
206154359Sroberto		add_full_recv_buffer(rb);
206254359Sroberto		total_recv++;	/* count it */
206354359Sroberto	}
206454359Sroberto}
206554359Sroberto
206654359Sroberto
206754359Sroberto/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
206854359Sroberto/*
206954359Sroberto * printserver - print detail information for a server
207054359Sroberto */
207154359Srobertostatic void
207254359Srobertoprintserver(
207354359Sroberto	register struct server *pp,
207454359Sroberto	FILE *fp
207554359Sroberto	)
207654359Sroberto{
207754359Sroberto	register int i;
207854359Sroberto	char junk[5];
207954359Sroberto	char *str;
208054359Sroberto
208154359Sroberto	if (!debug) {
208254359Sroberto	    (void) fprintf(fp,
208354359Sroberto		"%-15s %d/%d %03o v%d s%d offset %9s delay %s disp %s\n",
208454359Sroberto		ntoa(&pp->srcadr),
208554359Sroberto		pp->xmtcnt,pp->rcvcnt,pp->reach,
208654359Sroberto		pp->version,pp->stratum,
208754359Sroberto		lfptoa(&pp->offset, 6), ufptoa(pp->delay, 5),
208854359Sroberto		ufptoa(pp->dispersion, 4));
208954359Sroberto	    return;
209054359Sroberto	}
209154359Sroberto
209254359Sroberto	(void) fprintf(fp, "server %s, port %d\n",
209354359Sroberto			   ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port));
209454359Sroberto
209554359Sroberto	(void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
209654359Sroberto			   pp->stratum, pp->precision,
209754359Sroberto			   pp->leap & 0x2 ? '1' : '0',
209854359Sroberto			   pp->leap & 0x1 ? '1' : '0',
209954359Sroberto			   pp->trust);
210054359Sroberto
210154359Sroberto	if (pp->stratum == 1) {
210254359Sroberto		junk[4] = 0;
210354359Sroberto		memmove(junk, (char *)&pp->refid, 4);
210454359Sroberto		str = junk;
210554359Sroberto	} else {
210654359Sroberto		str = numtoa(pp->refid);
210754359Sroberto	}
210854359Sroberto	(void) fprintf(fp,
210954359Sroberto			   "refid [%s], delay %s, dispersion %s\n",
211054359Sroberto			   str, fptoa((s_fp)pp->delay, 5),
211154359Sroberto			   ufptoa(pp->dispersion, 5));
211254359Sroberto
211354359Sroberto	(void) fprintf(fp, "transmitted %d, received %d, reachable %03o\n",
211454359Sroberto	    pp->xmtcnt, pp->rcvcnt, pp->reach);
211554359Sroberto
211654359Sroberto	(void) fprintf(fp, "reference time:    %s\n",
211754359Sroberto			   prettydate(&pp->reftime));
211854359Sroberto	(void) fprintf(fp, "originate timestamp: %s\n",
211954359Sroberto			   prettydate(&pp->org));
212054359Sroberto	(void) fprintf(fp, "transmit timestamp:  %s\n",
212154359Sroberto			   prettydate(&pp->xmt));
212254359Sroberto
212354359Sroberto	(void) fprintf(fp, "filter delay: ");
212454359Sroberto	for (i = 0; i < NTP_SHIFT; i++) {
212554359Sroberto		(void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
212654359Sroberto		if (i == (NTP_SHIFT>>1)-1)
212754359Sroberto			(void) fprintf(fp, "\n        ");
212854359Sroberto	}
212954359Sroberto	(void) fprintf(fp, "\n");
213054359Sroberto
213154359Sroberto	(void) fprintf(fp, "filter offset:");
213254359Sroberto	for (i = 0; i < PEER_SHIFT; i++) {
213354359Sroberto		(void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
213454359Sroberto		if (i == (PEER_SHIFT>>1)-1)
213554359Sroberto			(void) fprintf(fp, "\n        ");
213654359Sroberto	}
213754359Sroberto	(void) fprintf(fp, "\n");
213854359Sroberto
213954359Sroberto	(void) fprintf(fp, "delay %s, dispersion %s\n",
214054359Sroberto			   fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
214154359Sroberto
214254359Sroberto	(void) fprintf(fp, "offset %s\n\n",
214354359Sroberto			   lfptoa(&pp->offset, 6));
214454359Sroberto}
214554359Sroberto
214654359Sroberto#if !defined(HAVE_VSPRINTF)
214754359Srobertoint
214854359Srobertovsprintf(
214954359Sroberto	char *str,
215054359Sroberto	const char *fmt,
215154359Sroberto	va_list ap
215254359Sroberto	)
215354359Sroberto{
215454359Sroberto	FILE f;
215554359Sroberto	int len;
215654359Sroberto
215754359Sroberto	f._flag = _IOWRT+_IOSTRG;
215854359Sroberto	f._ptr = str;
215954359Sroberto	f._cnt = 32767;
216054359Sroberto	len = _doprnt(fmt, ap, &f);
216154359Sroberto	*f._ptr = 0;
216254359Sroberto	return (len);
216354359Sroberto}
216454359Sroberto#endif
2165