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