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