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