/contrib/ntp/ntpdate/ntptimeset.c
C | 2164 lines | 1338 code | 229 blank | 597 comment | 309 complexity | 0a9a1fae0c25c8157236ff244c20d922 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
- /*
- * ntptimeset - get/set the time via ntp
- *
- * GOAL:
- * The goal of ntptime is to set the current time on system startup
- * to the best possible time using the network very wisely. It is assumed
- * that after a resonable time has been sett then ntp daemon will
- * maintain it.
- *
- * PROBLEM DOMAIN:
- * We have three sets of issues related to acheiving the goal. The first
- * issue is using the network when normal traffic is happening or when
- * the entire network world is recovering from a campus wide power failure
- * and is restarting. The second issue is the class of machine whether it
- * is a user's office workstation being handled by an uneducated user or
- * a server computer being handled by a trained operations staff. The third
- * issue is whether the ratio of people to computers and whether the
- * environment is stable and viable or not.
- *
- * NETWORK USAGE:
- * The first issue of using the network wisely is a question of whether
- * the network load and time server load and state are normal. If things
- * are normal ntptime can do what ntpdate does of sending out 4 packets
- * quickly to each server (new transmit done with each ack). However
- * if network or time load is high then this scheme will simply contribute
- * to problems. Given we have minimal state, we simply weight lost packets
- * significantly and make sure we throttle output as much as possible
- * without performance lost for quick startups.
- *
- * TRAINING AND KNOWLEDGE:
- * The second issue of uneducated user of a office workstation versus a
- * trained operation staff of a server machine translates into simply an
- * issue of untrained and trained users.
- *
- * The training issue implies that for the sake of the users involved in the
- * handling of their office workstation, problems and options should be
- * communicated simply and effectively and not in terse expert related
- * descriptions without possible options to be taken. The operator's training
- * and education enables them to deal with either type of communication and
- * control.
- *
- * AUTOMATION AND MANUAL CONTROL:
- * The last issue boils down to a design problem. If the design tends to go
- * into a manual mode when the environment is non-viable then one person
- * handling many computers all at the same time will be heavily impacted. On
- * the other hand, if the design tends to be automatic and does not indicate
- * a way for the user to take over control then the computer will be
- * unavailable for the user until the proble is resolved by someone else or
- * the user.
- *
- * NOTE: Please do not have this program print out every minute some line,
- * of output. If this happens and the environment is in trouble then
- * many pages of paper on many different machines will be filled up.
- * Save some tress in your lifetime.
- *
- * CONCLUSION:
- * The behavior of the program derived from these three issues should be
- * that during normal situations it quickly sets the time and allow the
- * system to startup.
- *
- * However during abnormal conditions as detected by unresponsive servers,
- * out-of-sync or bad responses and other detections, it should print out
- * a simple but clear message and continue in a mellow way to get the best
- * possible time. It may never get the time and if so should also indicate
- * this.
- *
- * Rudy Nedved
- * 18-May-1993
- *
- ****************************************************************
- *
- * Much of the above is confusing or no longer relevant. For example,
- * it is rare these days for a machine's console to be a printing terminal,
- * so the comment about saving trees doesn't mean much. Nonetheless,
- * the basic principles still stand:
- *
- * - Work automatically, without human control or intervention. To
- * this end, we use the same configuration file as ntpd itself, so
- * you don't have to specify servers or other information on the
- * command line. We also recognize that sometimes we won't be able
- * to contact any servers, and give up in that event instead of
- * hanging forever.
- *
- * - Behave in a sane way, both internally and externally, even in the
- * face of insane conditions. That means we back off quickly when
- * we don't hear a response, to avoid network congestion. Like
- * ntpd, we verify responses from several servers before accepting
- * the new time data.
- *
- * However, we don't assume that the local clock is right, or even
- * close, because it might not be at boot time, and we want to catch
- * and correct that situation. This behaviour has saved us in several
- * instances. On HP-UX 9.0x, there used to be a bug in adjtimed which
- * would cause the time to be set to some wild value, making the machine
- * essentially unusable (we use Kerberos authentication pervasively,
- * and it requires workstations and servers to have a time within five
- * minutes of the Kerberos server). We also have problems on PC's
- * running both Linux and some Microsoft OS -- they tend to disagree
- * on what the BIOS clock should say, and who should update it, and
- * when. On those systems, we not only run ntptimeset at boot, we
- * also reset the BIOS clock based on the result, so the correct
- * time will be retained across reboots.
- *
- * For these reasons, and others, we have continued to use this tool
- * rather than ntpdate. It is run automatically at boot time on every
- * workstation and server in our facility.
- *
- * In the past, we called this program 'ntptime'. Unfortunately, the
- * ntp v4 distribution also includes a program with that name. In
- * order to avoid confusion, we have renamed our program 'ntptimeset',
- * which more accurately describes what it does.
- *
- * Jeffrey T. Hutzelman (N3NHS) <jhutz+@cmu.edu>
- * School of Computer Science - Research Computing Facility
- * Carnegie Mellon University - Pittsburgh, PA
- * 16-Aug-1999
- *
- */
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include "ntp_machine.h"
- #include "ntp_fp.h"
- #include "ntp.h"
- #include "ntp_io.h"
- #include "iosignal.h"
- #include "ntp_unixtime.h"
- #include "ntpdate.h"
- #include "ntp_string.h"
- #include "ntp_syslog.h"
- #include "ntp_select.h"
- #include "ntp_stdlib.h"
- #ifdef HAVE_UNISTD_H
- # include <unistd.h>
- #endif
- #include <stdio.h>
- #include <signal.h>
- #include <ctype.h>
- #ifndef SYS_WINNT
- # ifdef HAVE_SYS_SIGNAL_H
- # include <sys/signal.h>
- # else
- # include <signal.h>
- # endif
- # include <sys/ioctl.h>
- #endif /* SYS_WINNT */
- #ifdef HAVE_SYS_RESOURCE_H
- # include <sys/resource.h>
- #endif /* HAVE_SYS_RESOURCE_H */
- #ifdef SYS_VXWORKS
- # include "ioLib.h"
- # include "sockLib.h"
- # include "timers.h"
- #endif
- #include "recvbuff.h"
- #ifdef SYS_WINNT
- # define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy
- on Windows NT timers. */
- #pragma comment(lib, "winmm")
- #endif /* SYS_WINNT */
- /*
- * Scheduling priority we run at
- */
- #ifndef SYS_VXWORKS
- # define NTPDATE_PRIO (-12)
- #else
- # define NTPDATE_PRIO (100)
- #endif
- #if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
- /* POSIX TIMERS - vxWorks doesn't have itimer - casey */
- static timer_t ntpdate_timerid;
- #endif
- /*
- * Compatibility stuff for Version 2
- */
- #define NTP_MAXSKW 0x28f /* 0.01 sec in fp format */
- #define NTP_MINDIST 0x51f /* 0.02 sec in fp format */
- #define NTP_INFIN 15 /* max stratum, infinity a la Bellman-Ford */
- #define NTP_MAXWGT (8*FP_SECOND) /* maximum select weight 8 seconds */
- #define NTP_MAXLIST 5 /* maximum select list size */
- #define PEER_SHIFT 8 /* 8 suitable for crystal time base */
- /*
- * Debugging flag
- */
- volatile int debug = 0;
- /*
- * File descriptor masks etc. for call to select
- */
- int fd;
- fd_set fdmask;
- /*
- * Initializing flag. All async routines watch this and only do their
- * thing when it is clear.
- */
- int initializing = 1;
- /*
- * Alarm flag. Set when an alarm occurs
- */
- volatile int alarm_flag = 0;
- /*
- * Set the time if valid time determined
- */
- int set_time = 0;
- /*
- * transmission rate control
- */
- #define MINTRANSMITS (3) /* minimum total packets per server */
- #define MAXXMITCOUNT (2) /* maximum packets per time interrupt */
- /*
- * time setting constraints
- */
- #define DESIREDDISP (4*FP_SECOND) /* desired dispersion, (fp 4) */
- int max_period = DEFMAXPERIOD;
- int min_servers = DEFMINSERVERS;
- int min_valid = DEFMINVALID;
- /*
- * counters related to time setting constraints
- */
- int contacted = 0; /* # of servers we have sent to */
- int responding = 0; /* servers responding */
- int validcount = 0; /* servers with valid time */
- int valid_n_low = 0; /* valid time servers with low dispersion */
- /*
- * Unpriviledged port flag.
- */
- int unpriv_port = 0;
- /*
- * Program name.
- */
- char *progname;
- /*
- * Systemwide parameters and flags
- */
- struct server **sys_servers; /* the server list */
- int sys_numservers = 0; /* number of servers to poll */
- int sys_authenticate = 0; /* true when authenticating */
- u_int32 sys_authkey = 0; /* set to authentication key in use */
- u_long sys_authdelay = 0; /* authentication delay */
- /*
- * The current internal time
- */
- u_long current_time = 0;
- /*
- * File of encryption keys
- */
- #ifndef KEYFILE
- # ifndef SYS_WINNT
- #define KEYFILE "/etc/ntp.keys"
- # else
- #define KEYFILE "%windir%\\ntp.keys"
- # endif /* SYS_WINNT */
- #endif /* KEYFILE */
- #ifndef SYS_WINNT
- const char *key_file = KEYFILE;
- #else
- char key_file_storage[MAX_PATH+1], *key_file ;
- #endif /* SYS_WINNT */
- /*
- * total packet counts
- */
- u_long total_xmit = 0;
- u_long total_recv = 0;
- /*
- * Miscellaneous flags
- */
- int verbose = 0;
- #define HORRIBLEOK 3 /* how many packets to let out */
- int horrible = 0; /* how many packets we drop for testing */
- int secondhalf = 0; /* second half of timeout period */
- int printmsg = 0; /* print time response analysis */
- /*
- * The half time and finish time in internal time
- */
- u_long half_time = 0;
- u_long finish_time = 0;
- int ntptimesetmain P((int argc, char *argv[]));
- static void analysis P((int final));
- static int have_enough P((void));
- static void transmit P((register struct server *server));
- static void receive P((struct recvbuf *rbufp));
- static void clock_filter P((register struct server *server, s_fp d, l_fp *c));
- static void clock_count P((void));
- static struct server *clock_select P((void));
- static void set_local_clock P((void));
- static struct server *findserver P((struct sockaddr_in *addr));
- static void timer P((void));
- #ifndef SYS_WINNT
- static RETSIGTYPE alarming P((int sig));
- #endif /* SYS_WINNT */
- static void init_alarm P((void));
- static void init_io P((void));
- static int sendpkt P((struct sockaddr_in *dest, struct pkt *pkt, int len));
- void input_handler P((l_fp *xts));
- static void printserver P((register struct server *pp, FILE *fp));
- #if !defined(HAVE_VSPRINTF)
- int vsprintf P((char *str, const char *fmt, va_list ap));
- #endif
- #ifdef HAVE_SIGNALED_IO
- extern void wait_for_signal P((void));
- extern void unblock_io_and_alarm P((void));
- extern void block_io_and_alarm P((void));
- #endif
- #ifdef NO_MAIN_ALLOWED
- CALL(ntptimeset,"ntptimeset",ntptimesetmain);
- void clear_globals()
- {
- /*
- * Debugging flag
- */
- debug = 0;
- ntp_optind = 0;
- /*
- * Initializing flag. All async routines watch this and only do their
- * thing when it is clear.
- */
- initializing = 1;
- /*
- * Alarm flag. Set when an alarm occurs
- */
- alarm_flag = 0;
- /*
- * Unpriviledged port flag.
- */
- unpriv_port = 0;
- /*
- * Systemwide parameters and flags
- */
- sys_numservers = 0; /* number of servers to poll */
- sys_authenticate = 0; /* true when authenticating */
- sys_authkey = 0; /* set to authentication key in use */
- sys_authdelay = 0; /* authentication delay */
- /*
- * The current internal time
- */
- current_time = 0;
- verbose = 0;
- }
- #endif /* NO_MAIN_ALLOWED */
- /*
- * Main program. Initialize us and loop waiting for I/O and/or
- * timer expiries.
- */
- #ifndef NO_MAIN_ALLOWED
- int
- main(
- int argc,
- char *argv[]
- )
- {
- return ntptimesetmain(argc, argv);
- }
- #endif /* NO_MAIN_ALLOWED */
-
- int
- ntptimesetmain(
- int argc,
- char *argv[]
- )
- {
- int was_alarmed;
- int tot_recvbufs;
- struct recvbuf *rbuf;
- l_fp tmp;
- int errflg;
- int c;
- extern char *ntp_optarg;
- extern int ntp_optind;
- int ltmp;
- char *cfgpath;
- #ifdef SYS_WINNT
- HANDLE process_handle;
- wVersionRequested = MAKEWORD(1,1);
- if (WSAStartup(wVersionRequested, &wsaData)) {
- msyslog(LOG_ERR, "No useable winsock.dll: %m");
- exit(1);
- }
- #endif /* SYS_WINNT */
- #ifdef NO_MAIN_ALLOWED
- clear_globals();
- #endif
- errflg = 0;
- cfgpath = 0;
- progname = argv[0];
- syslogit = 0;
- /*
- * Decode argument list
- */
- while ((c = ntp_getopt(argc, argv, "a:c:de:slt:uvHS:V:")) != EOF)
- switch (c)
- {
- case 'a':
- c = atoi(ntp_optarg);
- sys_authenticate = 1;
- sys_authkey = c;
- break;
- case 'c':
- cfgpath = ntp_optarg;
- break;
- case 'd':
- ++debug;
- break;
- case 'e':
- if (!atolfp(ntp_optarg, &tmp)
- || tmp.l_ui != 0) {
- (void) fprintf(stderr,
- "%s: encryption delay %s is unlikely\n",
- progname, ntp_optarg);
- errflg++;
- } else {
- sys_authdelay = tmp.l_uf;
- }
- break;
- case 's':
- set_time = 1;
- break;
- case 'l':
- syslogit = 1;
- break;
- case 't':
- ltmp = atoi(ntp_optarg);
- if (ltmp <= 0) {
- (void) fprintf(stderr,
- "%s: maximum time period (%d) is invalid\n",
- progname, ltmp);
- errflg++;
- }
- else
- max_period = ltmp;
- break;
- case 'u':
- unpriv_port = 1;
- break;
- case 'v':
- ++verbose;
- break;
- case 'H':
- horrible++;
- break;
- case 'S':
- ltmp = atoi(ntp_optarg);
- if (ltmp <= 0) {
- (void) fprintf(stderr,
- "%s: minimum responding (%d) is invalid\n",
- progname, ltmp);
- errflg++;
- }
- else
- min_servers = ltmp;
- break;
- case 'V':
- ltmp = atoi(ntp_optarg);
- if (ltmp <= 0) {
- (void) fprintf(stderr,
- "%s: minimum valid (%d) is invalid\n",
- progname, ltmp);
- errflg++;
- }
- else
- min_valid = ltmp;
- break;
- case '?':
- ++errflg;
- break;
- default:
- break;
- }
-
- if (errflg || ntp_optind < argc) {
- fprintf(stderr,"usage: %s [switches...]\n",progname);
- fprintf(stderr," -v (verbose)\n");
- fprintf(stderr," -c path (set config file path)\n");
- fprintf(stderr," -a key (authenticate using key)\n");
- fprintf(stderr," -e delay (authentication delay)\n");
- fprintf(stderr," -S num (# of servers that must respond)\n");
- fprintf(stderr," -V num (# of servers that must valid)\n");
- fprintf(stderr," -s (set the time based if okay)\n");
- fprintf(stderr," -t secs (time period before ending)\n");
- fprintf(stderr," -l (use syslog facility)\n");
- fprintf(stderr," -u (use unprivileged port)\n");
- fprintf(stderr," -H (drop packets for debugging)\n");
- fprintf(stderr," -d (debug output)\n");
- exit(2);
- }
- /*
- * Logging. Open the syslog if we have to
- */
- if (syslogit) {
- #if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
- # ifndef LOG_DAEMON
- openlog("ntptimeset", LOG_PID);
- # else
- # ifndef LOG_NTP
- # define LOG_NTP LOG_DAEMON
- # endif
- openlog("ntptimeset", LOG_PID | LOG_NDELAY, LOG_NTP);
- if (debug)
- setlogmask(LOG_UPTO(LOG_DEBUG));
- else
- setlogmask(LOG_UPTO(LOG_INFO));
- # endif /* LOG_DAEMON */
- #endif /* SYS_WINNT */
- }
- if (debug || verbose)
- msyslog(LOG_INFO, "%s", Version);
- if (horrible)
- msyslog(LOG_INFO, "Dropping %d out of %d packets",
- horrible,horrible+HORRIBLEOK);
- /*
- * Add servers we are going to be polling
- */
- loadservers(cfgpath);
- if (sys_numservers < min_servers) {
- msyslog(LOG_ERR, "Found %d servers, require %d servers",
- sys_numservers,min_servers);
- exit(2);
- }
- /*
- * determine when we will end at least
- */
- finish_time = max_period * TIMER_HZ;
- half_time = finish_time >> 1;
- /*
- * Initialize the time of day routines and the I/O subsystem
- */
- if (sys_authenticate) {
- init_auth();
- #ifdef SYS_WINNT
- if (!key_file) key_file = KEYFILE;
- if (!ExpandEnvironmentStrings(key_file, key_file_storage, MAX_PATH))
- {
- msyslog(LOG_ERR, "ExpandEnvironmentStrings(%s) failed: %m\n",
- key_file);
- } else {
- key_file = key_file_storage;
- }
- #endif /* SYS_WINNT */
- if (!authreadkeys(key_file)) {
- msyslog(LOG_ERR, "no key file, exiting");
- exit(1);
- }
- if (!authistrusted(sys_authkey)) {
- char buf[10];
- (void) sprintf(buf, "%lu", (unsigned long)sys_authkey);
- msyslog(LOG_ERR, "authentication key %s unknown", buf);
- exit(1);
- }
- }
- init_io();
- init_alarm();
- /*
- * Set the priority.
- */
- #ifdef SYS_VXWORKS
- taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
- #endif
- #if defined(HAVE_ATT_NICE)
- nice (NTPDATE_PRIO);
- #endif
- #if defined(HAVE_BSD_NICE)
- (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
- #endif
- #ifdef SYS_WINNT
- process_handle = GetCurrentProcess();
- if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
- msyslog(LOG_ERR, "SetPriorityClass failed: %m");
- }
- #endif /* SYS_WINNT */
- initializing = 0;
- /*
- * Use select() on all on all input fd's for unlimited
- * time. select() will terminate on SIGALARM or on the
- * reception of input. Using select() means we can't do
- * robust signal handling and we get a potential race
- * between checking for alarms and doing the select().
- * Mostly harmless, I think.
- * Keep going until we have enough information, or time is up.
- */
- /* On VMS, I suspect that select() can't be interrupted
- * by a "signal" either, so I take the easy way out and
- * have select() time out after one second.
- * System clock updates really aren't time-critical,
- * and - lacking a hardware reference clock - I have
- * yet to learn about anything else that is.
- */
- was_alarmed = 0;
- while (finish_time > current_time) {
- #if !defined(HAVE_SIGNALED_IO)
- fd_set rdfdes;
- int nfound;
- #elif defined(HAVE_SIGNALED_IO)
- block_io_and_alarm();
- #endif
- tot_recvbufs = full_recvbuffs(); /* get received buffers */
- if (printmsg) {
- printmsg = 0;
- analysis(0);
- }
- if (alarm_flag) { /* alarmed? */
- was_alarmed = 1;
- alarm_flag = 0;
- }
- if (!was_alarmed && tot_recvbufs > 0) {
- /*
- * Nothing to do. Wait for something.
- */
- #ifndef HAVE_SIGNALED_IO
- rdfdes = fdmask;
- # if defined(VMS) || defined(SYS_VXWORKS)
- /* make select() wake up after one second */
- {
- struct timeval t1;
- t1.tv_sec = 1; t1.tv_usec = 0;
- nfound = select(fd+1, &rdfdes, (fd_set *)0,
- (fd_set *)0, &t1);
- }
- # else
- nfound = select(fd+1, &rdfdes, (fd_set *)0,
- (fd_set *)0, (struct timeval *)0);
- # endif /* VMS */
- if (nfound > 0) {
- l_fp ts;
- get_systime(&ts);
- (void)input_handler(&ts);
- }
- else if (nfound == -1 && errno != EINTR)
- msyslog(LOG_ERR, "select() error: %m");
- else if (debug) {
- # if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 /* to unclutter log */
- msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
- # endif
- }
- #else /* HAVE_SIGNALED_IO */
-
- wait_for_signal();
- #endif /* HAVE_SIGNALED_IO */
- if (alarm_flag) /* alarmed? */
- {
- was_alarmed = 1;
- alarm_flag = 0;
- }
- tot_recvbufs = full_recvbuffs(); /* get received buffers */
- }
- #ifdef HAVE_SIGNALED_IO
- unblock_io_and_alarm();
- #endif /* HAVE_SIGNALED_IO */
- /*
- * Out here, signals are unblocked. Call timer routine
- * to process expiry.
- */
- if (was_alarmed)
- {
- timer();
- was_alarmed = 0;
- }
- /*
- * Call the data procedure to handle each received
- * packet.
- */
- rbuf = get_full_recv_buffer();
- while (rbuf != NULL)
- {
- receive(rbuf);
- freerecvbuf(rbuf);
- rbuf = get_full_recv_buffer();
- }
- /*
- * Do we have enough information to stop now?
- */
- if (have_enough())
- break; /* time to end */
- /*
- * Go around again
- */
- }
- /*
- * adjust the clock and exit accordingly
- */
- set_local_clock();
- /*
- * if we get here then we are in trouble
- */
- return(1);
- }
- /*
- * analysis - print a message indicating what is happening with time service
- * must mimic have_enough() procedure.
- */
- static void
- analysis(
- int final
- )
- {
- if (contacted < sys_numservers) {
- printf("%d servers of %d have been probed with %d packets\n",
- contacted,sys_numservers,MINTRANSMITS);
- return;
- }
- if (!responding) {
- printf("No response from any of %d servers, network problem?\n",
- sys_numservers);
- return;
- }
- else if (responding < min_servers) {
- printf("%d servers out of %d responding, need at least %d.\n",
- responding, sys_numservers, min_servers);
- return;
- }
- if (!validcount) {
- printf("%d servers responding but none have valid time\n",
- responding);
- return;
- }
- else if (validcount < min_valid) {
- printf("%d servers responding, %d are valid, need %d valid\n",
- responding,validcount,min_valid);
- return;
- }
- if (!final && valid_n_low != validcount) {
- printf("%d valid servers but only %d have low dispersion\n",
- validcount,valid_n_low);
- return;
- }
- }
- /* have_enough - see if we have enough information to terminate probing
- */
- static int
- have_enough(void)
- {
- /* have we contacted all servers yet? */
- if (contacted < sys_numservers)
- return 0; /* no...try some more */
- /* have we got at least minimum servers responding? */
- if (responding < min_servers)
- return 0; /* no...try some more */
- /* count the clocks */
- (void) clock_count();
- /* have we got at least minimum valid clocks? */
- if (validcount <= 0 || validcount < min_valid)
- return 0; /* no...try some more */
- /* do we have all valid servers with low dispersion */
- if (!secondhalf && valid_n_low != validcount)
- return 0;
- /* if we get into the secondhalf then we ignore dispersion */
- /* all conditions have been met...end */
- return 1;
- }
- /*
- * transmit - transmit a packet to the given server, or mark it completed.
- * This is called by the timeout routine and by the receive
- * procedure.
- */
- static void
- transmit(
- register struct server *server
- )
- {
- struct pkt xpkt;
- int timeout;
- if (debug > 2)
- printf("transmit(%s)\n", ntoa(&server->srcadr));
- if ((server->reach & 01) == 0) {
- l_fp ts;
- /*
- * Last message to this server timed out. Shift
- * zeros into the filter.
- */
- L_CLR(&ts);
- clock_filter(server, 0, &ts);
- }
- /*
- * shift reachable register over
- */
- server->reach <<= 1;
- /*
- * If we're here, send another message to the server. Fill in
- * the packet and let 'er rip.
- */
- xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
- server->version, MODE_CLIENT);
- xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
- xpkt.ppoll = NTP_MINPOLL;
- xpkt.precision = NTPDATE_PRECISION;
- xpkt.rootdelay = htonl(NTPDATE_DISTANCE);
- xpkt.rootdispersion = htonl(NTPDATE_DISP);
- xpkt.refid = htonl(NTPDATE_REFID);
- L_CLR(&xpkt.reftime);
- L_CLR(&xpkt.org);
- L_CLR(&xpkt.rec);
- /*
- * Determine whether to authenticate or not. If so,
- * fill in the extended part of the packet and do it.
- * If not, just timestamp it and send it away.
- */
- if (sys_authenticate) {
- int len;
- xpkt.exten[0] = htonl(sys_authkey);
- get_systime(&server->xmt);
- L_ADDUF(&server->xmt, sys_authdelay);
- HTONL_FP(&server->xmt, &xpkt.xmt);
- len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC);
- if (sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len))) {
- if (debug > 1)
- printf("failed transmit auth to %s\n",
- ntoa(&(server->srcadr)));
- return;
- }
- if (debug > 1)
- printf("transmit auth to %s\n",
- ntoa(&(server->srcadr)));
- } else {
- get_systime(&(server->xmt));
- HTONL_FP(&server->xmt, &xpkt.xmt);
- if (sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC)) {
- if (debug > 1)
- printf("failed transmit to %s\n",
- ntoa(&(server->srcadr)));
- return;
- }
- if (debug > 1)
- printf("transmit to %s\n", ntoa(&(server->srcadr)));
- }
- /*
- * count transmits, record contacted count and set transmit time
- */
- if (++server->xmtcnt == MINTRANSMITS)
- contacted++;
- server->last_xmit = current_time;
- /*
- * determine timeout for this packet. The more packets we send
- * to the host, the slower we get. If the host indicates that
- * it is not "sane" then we expect even less.
- */
- if (server->xmtcnt < MINTRANSMITS) {
- /* we have not sent enough */
- timeout = TIMER_HZ; /* 1 second probe */
- }
- else if (server->rcvcnt <= 0) {
- /* we have heard nothing */
- if (secondhalf)
- timeout = TIMER_HZ<<4; /* 16 second probe */
- else
- timeout = TIMER_HZ<<3; /* 8 second probe */
- }
- else {
- /* if we have low dispersion then probe infrequently */
- if (server->dispersion <= DESIREDDISP)
- timeout = TIMER_HZ<<4; /* 16 second probe */
- /* if the server is not in sync then let it alone */
- else if (server->leap == LEAP_NOTINSYNC)
- timeout = TIMER_HZ<<4; /* 16 second probe */
- /* if the server looks broken ignore it */
- else if (server->org.l_ui < server->reftime.l_ui)
- timeout = TIMER_HZ<<5; /* 32 second probe */
- else if (secondhalf)
- timeout = TIMER_HZ<<2; /* 4 second probe */
- else
- timeout = TIMER_HZ<<1; /* 2 second probe */
- }
- /*
- * set next transmit time based on timeout
- */
- server->event_time = current_time + timeout;
- }
- /*
- * receive - receive and process an incoming frame
- */
- static void
- receive(
- struct recvbuf *rbufp
- )
- {
- register struct pkt *rpkt;
- register struct server *server;
- register s_fp di;
- l_fp t10, t23;
- l_fp org;
- l_fp rec;
- l_fp ci;
- int has_mac;
- int is_authentic;
- if (debug > 2)
- printf("receive(%s)\n", ntoa(&rbufp->srcadr));
- /*
- * Check to see if the packet basically looks like something
- * intended for us.
- */
- if (rbufp->recv_length == LEN_PKT_NOMAC)
- has_mac = 0;
- else if (rbufp->recv_length >= LEN_PKT_NOMAC)
- has_mac = 1;
- else {
- if (debug > 2)
- printf("receive: packet length %d\n",
- rbufp->recv_length);
- return; /* funny length packet */
- }
- rpkt = &(rbufp->recv_pkt);
- if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
- PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
- if (debug > 1)
- printf("receive: bad version %d\n",
- PKT_VERSION(rpkt->li_vn_mode));
- return;
- }
- if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
- && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
- || rpkt->stratum >=STRATUM_UNSPEC) {
- if (debug > 1)
- printf("receive: mode %d stratum %d\n",
- PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
- return;
- }
-
- /*
- * So far, so good. See if this is from a server we know.
- */
- server = findserver(&(rbufp->srcadr));
- if (server == NULL) {
- if (debug > 1)
- printf("receive: server not found\n");
- return;
- }
- /*
- * Decode the org timestamp and make sure we're getting a response
- * to our last request.
- */
- NTOHL_FP(&rpkt->org, &org);
- if (!L_ISEQU(&org, &server->xmt)) {
- if (debug > 1)
- printf("receive: pkt.org and peer.xmt differ\n");
- return;
- }
-
- /*
- * Check out the authenticity if we're doing that.
- */
- if (!sys_authenticate)
- is_authentic = 1;
- else {
- is_authentic = 0;
- if (debug > 3)
- printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n",
- (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey,
- (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt,
- LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC)));
- if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey &&
- authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC,
- (int)(rbufp->recv_length - LEN_PKT_NOMAC)))
- is_authentic = 1;
- if (debug)
- printf("receive: authentication %s\n",
- is_authentic ? "passed" : "failed");
- }
- server->trust <<= 1;
- if (!is_authentic)
- server->trust |= 1;
-
- /*
- * Looks good. Record info from the packet.
- */
- server->leap = PKT_LEAP(rpkt->li_vn_mode);
- server->stratum = PKT_TO_STRATUM(rpkt->stratum);
- server->precision = rpkt->precision;
- server->rootdelay = ntohl(rpkt->rootdelay);
- server->rootdispersion = ntohl(rpkt->rootdispersion);
- server->refid = rpkt->refid;
- NTOHL_FP(&rpkt->reftime, &server->reftime);
- NTOHL_FP(&rpkt->rec, &rec);
- NTOHL_FP(&rpkt->xmt, &server->org);
- /*
- * count this guy as responding
- */
- server->reach |= 1;
- if (server->rcvcnt++ == 0)
- responding++;
- /*
- * Make sure the server is at least somewhat sane. If not, ignore
- * it for later.
- */
- if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
- if (debug > 1)
- printf("receive: pkt insane\n");
- return;
- }
- /*
- * Calculate the round trip delay (di) and the clock offset (ci).
- * We use the equations (reordered from those in the spec):
- *
- * d = (t2 - t3) - (t1 - t0)
- * c = ((t2 - t3) + (t1 - t0)) / 2
- */
- t10 = server->org; /* pkt.xmt == t1 */
- L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
- t23 = rec; /* pkt.rec == t2 */
- L_SUB(&t23, &org); /* pkt->org == t3 */
- /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */
- ci = t10;
- L_ADD(&ci, &t23);
- L_RSHIFT(&ci);
- /*
- * Calculate di in t23 in full precision, then truncate
- * to an s_fp.
- */
- L_SUB(&t23, &t10);
- di = LFPTOFP(&t23);
- if (debug > 3)
- printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5));
- di += (FP_SECOND >> (-(int)NTPDATE_PRECISION))
- + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW;
- if (di <= 0) { /* value still too raunchy to use? */
- L_CLR(&ci);
- di = 0;
- } else {
- di = max(di, NTP_MINDIST);
- }
- /*
- * This one is valid. Give it to clock_filter(),
- */
- clock_filter(server, di, &ci);
- if (debug > 1)
- printf("receive from %s\n", ntoa(&rbufp->srcadr));
- /*
- * See if we should goes the transmission. If not return now
- * otherwise have the next event time be shortened
- */
- if (server->stratum <= NTP_INFIN)
- return; /* server does not have a stratum */
- if (server->leap == LEAP_NOTINSYNC)
- return; /* just booted server or out of sync */
- if (!L_ISHIS(&server->org, &server->reftime))
- return; /* broken host */
- if (server->trust != 0)
- return; /* can not trust it */
- if (server->dispersion < DESIREDDISP)
- return; /* we have the desired dispersion */
- server->event_time -= (TIMER_HZ+1);
- }
- /*
- * clock_filter - add clock sample, determine a server's delay, dispersion
- * and offset
- */
- static void
- clock_filter(
- register struct server *server,
- s_fp di,
- l_fp *c
- )
- {
- register int i, j;
- int ord[NTP_SHIFT];
- /*
- * Insert sample and increment nextpt
- */
- i = server->filter_nextpt;
- server->filter_delay[i] = di;
- server->filter_offset[i] = *c;
- server->filter_soffset[i] = LFPTOFP(c);
- server->filter_nextpt++;
- if (server->filter_nextpt >= NTP_SHIFT)
- server->filter_nextpt = 0;
- /*
- * Sort indices into increasing delay order
- */
- for (i = 0; i < NTP_SHIFT; i++)
- ord[i] = i;
-
- for (i = 0; i < (NTP_SHIFT-1); i++) {
- for (j = i+1; j < NTP_SHIFT; j++) {
- if (server->filter_delay[ord[j]] == 0)
- continue;
- if (server->filter_delay[ord[i]] == 0
- || (server->filter_delay[ord[i]]
- > server->filter_delay[ord[j]])) {
- register int tmp;
- tmp = ord[i];
- ord[i] = ord[j];
- ord[j] = tmp;
- }
- }
- }
- /*
- * Now compute the dispersion, and assign values to delay and
- * offset. If there are no samples in the register, delay and
- * offset go to zero and dispersion is set to the maximum.
- */
- if (server->filter_delay[ord[0]] == 0) {
- server->delay = 0;
- L_CLR(&server->offset);
- server->soffset = 0;
- server->dispersion = PEER_MAXDISP;
- } else {
- register s_fp d;
- server->delay = server->filter_delay[ord[0]];
- server->offset = server->filter_offset[ord[0]];
- server->soffset = LFPTOFP(&server->offset);
- server->dispersion = 0;
- for (i = 1; i < NTP_SHIFT; i++) {
- if (server->filter_delay[ord[i]] == 0)
- d = PEER_MAXDISP;
- else {
- d = server->filter_soffset[ord[i]]
- - server->filter_soffset[ord[0]];
- if (d < 0)
- d = -d;
- if (d > PEER_MAXDISP)
- d = PEER_MAXDISP;
- }
- /*
- * XXX This *knows* PEER_FILTER is 1/2
- */
- server->dispersion += (u_fp)(d) >> i;
- }
- }
- /*
- * We're done
- */
- }
- /* clock_count - count the clock sources we have
- */
- static void
- clock_count(void)
- {
- register struct server *server;
- register int n;
- /* reset counts */
- validcount = valid_n_low = 0;
- /* go through the list of servers and count the clocks we believe
- * and that have low dispersion
- */
- for (n = 0; n < sys_numservers; n++) {
- server = sys_servers[n];
- if (server->delay == 0) {
- continue; /* no data */
- }
- if (server->stratum > NTP_INFIN) {
- continue; /* stratum no good */
- }
- if (server->delay > NTP_MAXWGT) {
- continue; /* too far away */
- }
- if (server->leap == LEAP_NOTINSYNC)
- continue; /* he's in trouble */
- if (!L_ISHIS(&server->org, &server->reftime)) {
- continue; /* very broken host */
- }
- if ((server->org.l_ui - server->reftime.l_ui) >= NTP_MAXAGE) {
- continue; /* too long without sync */
- }
- if (server->trust != 0) {
- continue;
- }
- /*
- * This one is a valid time source..
- */
- validcount++;
- /*
- * See if this one has a okay low dispersion
- */
- if (server->dispersion <= DESIREDDISP)
- valid_n_low++;
- }
- if (debug > 1)
- printf("have %d, valid %d, low %d\n",
- responding, validcount, valid_n_low);
- }
- /*
- * clock_select - select the pick-of-the-litter clock from the samples
- * we've got.
- */
- static struct server *
- clock_select(void)
- {
- register struct server *server;
- register int i;
- register int nlist;
- register s_fp d;
- register int j;
- register int n;
- s_fp local_threshold;
- struct server *server_list[NTP_MAXCLOCK];
- u_fp server_badness[NTP_MAXCLOCK];
- struct server *sys_server;
- /*
- * This first chunk of code is supposed to go through all
- * servers we know about to find the NTP_MAXLIST servers which
- * are most likely to succeed. We run through the list
- * doing the sanity checks and trying to insert anyone who
- * looks okay. We are at all times aware that we should
- * only keep samples from the top two strata and we only need
- * NTP_MAXLIST of them.
- */
- nlist = 0; /* none yet */
- for (n = 0; n < sys_numservers; n++) {
- server = sys_servers[n];
- if (server->delay == 0)
- continue; /* no data */
- if (server->stratum > NTP_INFIN)
- continue; /* stratum no good */
- if (server->delay > NTP_MAXWGT) {
- continue; /* too far away */
- }
- if (server->leap == LEAP_NOTINSYNC)
- continue; /* he's in trouble */
- if (!L_ISHIS(&server->org, &server->reftime)) {
- continue; /* very broken host */
- }
- if ((server->org.l_ui - server->reftime.l_ui)
- >= NTP_MAXAGE) {
- continue; /* too long without sync */
- }
- if (server->trust != 0) {
- continue;
- }
- /*
- * This one seems sane. Find where he belongs
- * on the list.
- */
- d = server->dispersion + server->dispersion;
- for (i = 0; i < nlist; i++)
- if (server->stratum <= server_list[i]->stratum)
- break;
- for ( ; i < nlist; i++) {
- if (server->stratum < server_list[i]->stratum)
- break;
- if (d < (s_fp) server_badness[i])
- break;
- }
- /*
- * If i points past the end of the list, this
- * guy is a loser, else stick him in.
- */
- if (i >= NTP_MAXLIST)
- continue;
- for (j = nlist; j > i; j--)
- if (j < NTP_MAXLIST) {
- server_list[j] = server_list[j-1];
- server_badness[j]
- = server_badness[j-1];
- }
- server_list[i] = server;
- server_badness[i] = d;
- if (nlist < NTP_MAXLIST)
- nlist++;
- }
- /*
- * Got the five-or-less best. Cut the list where the number of
- * strata exceeds two.
- */
- j = 0;
- for (i = 1; i < nlist; i++)
- if (server_list[i]->stratum > server_list[i-1]->stratum)
- if (++j == 2) {
- nlist = i;
- break;
- }
- /*
- * Whew! What we should have by now is 0 to 5 candidates for
- * the job of syncing us. If we have none, we're out of luck.
- * If we have one, he's a winner. If we have more, do falseticker
- * detection.
- */
- if (nlist == 0)
- sys_server = 0;
- else if (nlist == 1) {
- sys_server = server_list[0];
- } else {
- /*
- * Re-sort by stratum, bdelay estimate quality and
- * server.delay.
- */
- for (i = 0; i < nlist-1; i++)
- for (j = i+1; j < nlist; j++) {
- if (server_list[i]->stratum
- < server_list[j]->stratum)
- break; /* already sorted by stratum */
- if (server_list[i]->delay
- < server_list[j]->delay)
- continue;
- server = server_list[i];
- server_list[i] = server_list[j];
- server_list[j] = server;
- }
-
- /*
- * Calculate the fixed part of the dispersion limit
- */
- local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION))
- + NTP_MAXSKW;
- /*
- * Now drop samples until we're down to one.
- */
- while (nlist > 1) {
- for (n = 0; n < nlist; n++) {
- server_badness[n] = 0;
- for (j = 0; j < nlist; j++) {
- if (j == n) /* with self? */
- continue;
- d = server_list[j]->soffset
- - server_list[n]->soffset;
- if (d < 0) /* absolute value */
- d = -d;
- /*
- * XXX This code *knows* that
- * NTP_SELECT is 3/4
- */
- for (i = 0; i < j; i++)
- d = (d>>1) + (d>>2);
- server_badness[n] += d;
- }
- }
- /*
- * We now have an array of nlist badness
- * coefficients. Find the badest. Find
- * the minimum precision while we're at
- * it.
- */
- i = 0;
- n = server_list[0]->precision;;
- for (j = 1; j < nlist; j++) {
- if (server_badness[j] >= server_badness[i])
- i = j;
- if (n > server_list[j]->precision)
- n = server_list[j]->precision;
- }
-
- /*
- * i is the index of the server with the worst
- * dispersion. If his dispersion is less than
- * the threshold, stop now, else delete him and
- * continue around again.
- */
- if (server_badness[i] < (local_threshold
- + (FP_SECOND >> (-n))))
- break;
- for (j = i + 1; j < nlist; j++)
- server_list[j-1] = server_list[j];
- nlist--;
- }
- /*
- * What remains is a list of less than 5 servers. Take
- * the best.
- */
- sys_server = server_list[0];
- }
- /*
- * That's it. Return our server.
- */
- return sys_server;
- }
- /*
- * set_local_clock -- handle setting the local clock or displaying info.
- */
- static void
- set_local_clock(void)
- {
- register int i;
- register struct server *server;
- time_t tmp;
- double dtemp;
- /*
- * if setting time then print final analysis
- */
- if (set_time)
- analysis(1);
- /*
- * pick a clock
- */
- server = clock_select();
- /*
- * do some display of information
- */
- if (debug || verbose) {
- for (i = 0; i < sys_numservers; i++)
- printserver(sys_servers[i], stdout);
- if (debug)
- printf("packets sent %ld, received %ld\n",
- total_xmit, total_recv);
- }
- /*
- * see if we have a server to set the time with
- */
- if (server == 0) {
- if (!set_time || verbose)
- fprintf(stdout,"No servers available to sync time with\n");
- exit(1);
- }
- /*
- * we have a valid and selected time to use!!!!!
- */
- /*
- * if we are not setting the time then display offset and exit
- */
- if (!set_time) {
- fprintf(stdout,
- "Your clock is off by %s seconds. (%s) [%ld/%ld]\n",
- lfptoa(&server->offset, 7),
- ntoa(&server->srcadr),
- total_xmit, total_recv);
- exit(0);
- }
- /*
- * set the clock
- * XXX: Examine the more flexible approach used by ntpdate.
- * Note that a design consideration here is that we sometimes
- * _want_ to step the clock by a _huge_ amount in either
- * direction, because the local clock is completely bogus.
- * This condition must be recognized and dealt with, so
- * that we always get a good time when this completes.
- * -- jhutz+@cmu.edu, 16-Aug-1999
- */
- LFPTOD(&server->offset, dtemp);
- step_systime(dtemp);
- time(&tmp);
- fprintf(stdout,"Time set to %.20s [%s %s %ld/%ld]\n",
- ctime(&tmp)+4,
- ntoa(&server->srcadr),
- lfptoa(&server->offset, 7),
- total_xmit, total_recv);
- exit(0);
- }
- /*
- * findserver - find a server in the list given its address
- */
- static struct server *
- findserver(
- struct sockaddr_in *addr
- )
- {
- register int i;
- register u_int32 netnum;
- if (htons(addr->sin_port) != NTP_PORT)
- return 0;
- netnum = addr->sin_addr.s_addr;
- for (i = 0; i < sys_numservers; i++) {
- if (netnum == sys_servers[i]->srcadr.sin_addr.s_addr)
- return sys_servers[i];
- }
- return 0;
- }
- /*
- * timer - process a timer interrupt
- */
- static void
- timer(void)
- {
- register int k;
- /*
- * Bump the current idea of the time
- */
- current_time++;
- /*
- * see if we have reached half time
- */
- if (current_time >= half_time && !secondhalf) {
- secondhalf++;
- if (debug)
- printf("\nSecond Half of Timeout!\n");
- printmsg++;
- }
- /*
- * We only want to send a few packets per transmit interrupt
- * to throttle things
- */
- for(k = 0;k < MAXXMITCOUNT;k++) {
- register int i, oldi;
- register u_long oldxtime;
- /*
- * We want to send a packet out for a server that has an
- * expired event time. However to be mellow about this, we only
- * use one expired event timer and to avoid starvation we use
- * the one with the oldest last transmit time.
- */
- oldi = -1;
- oldxtime = 0;
- for (i = 0; i < sys_numservers; i++) {
- if (sys_servers[i]->event_time <= current_time) {
- if (oldi < 0 || oldxtime > sys_servers[i]->last_xmit) {
- oldxtime = sys_servers[i]->last_xmit;
- oldi = i;
- }
- }
- }
- if (oldi >= 0)
- transmit(sys_servers[oldi]);
- else
- break; /* no expired event */
- } /* end of transmit loop */
- }
- #ifndef SYS_WINNT
- /*
- * alarming - record the occurance of an alarm interrupt
- */
- static RETSIGTYPE
- alarming(
- int sig
- )
- #else
- void CALLBACK
- alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
- #endif /* SYS_WINNT */
- {
- alarm_flag++;
- }
- /*
- * init_alarm - set up the timer interrupt
- */
- static void
- init_alarm(void)
- {
- #ifndef SYS_WINNT
- # ifndef HAVE_TIMER_SETTIME
- struct itimerval itimer;
- # else
- struct itimerspec ntpdate_itimer;
- # endif
- #else
- TIMECAPS tc;
- UINT wTimerRes, wTimerID;
- # endif /* SYS_WINNT */
- #if defined SYS_CYGWIN32 || defined SYS_WINNT
- HANDLE hToken;
- TOKEN_PRIVILEGES tkp;
- DWORD dwUser = 0;
- #endif /* SYS_WINNT */
- alarm_flag = 0;
- #ifndef SYS_WINNT
- # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
- alarm_flag = 0;
- /* this code was put in as setitimer() is non existant this us the
- * POSIX "equivalents" setup - casey
- */
- /* ntpdate_timerid is global - so we can kill timer later */
- if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
- # ifdef SYS_VXWORKS
- ERROR
- # else
- -1
- # endif
- )
- {
- fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
- return;
- }
- /* TIMER_HZ = (5)
- * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
- * seconds from now and they continue on every 1/TIMER_HZ seconds.
- */
- (void) signal_no_reset(SIGALRM, alarming);
- ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
- ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
- ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
- timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
- # else
- /*
- * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
- * seconds from now and they continue on every 1/TIMER_HZ seconds.
- */
- (void) signal_no_reset(SIGALRM, alarming);
- itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
- itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
- itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
- setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
- # endif
- #if defined SYS_CYGWIN32
- /*
- * Get previleges needed for fiddling with the clock
- */
- /* get the current process token handle */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
- msyslog(LOG_ERR, "OpenProcessToken failed: %m");
- exit(1);
- }
- /* get the LUID for system-time privilege. */
- LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
- tkp.PrivilegeCount = 1; /* one privilege to set */
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- /* get set-time privilege for this process. */
- AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
- /* cannot test return value of AdjustTokenPrivileges. */
- if (GetLastError() != ERROR_SUCCESS)
- msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
- #endif
- #else /* SYS_WINNT */
- _tzset();
- /*
- * Get previleges needed for fiddling with the clock
- */
- /* get the current process token handle */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
- msyslog(LOG_ERR, "OpenProcessToken failed: %m");
- exit(1);
- }
- /* get the LUID for system-time privilege. */
- LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
- tkp.PrivilegeCount = 1; /* one privilege to set */
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- /* get set-time privilege for this process. */
- AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
- /* cannot test return value of AdjustTokenPrivileges. */
- if (GetLastError() != ERROR_SUCCESS)
- msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
- /*
- * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
- * Under Win/NT, expiry of timer interval leads to invocation
- * of a callback function (on a different thread) rather than
- * generating an alarm signal
- */
- /* determine max and min resolution supported */
- if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
- msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
- exit(1);
- }
- wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
- /* establish the minimum timer resolution that we'll use */
- timeBeginPeriod(wTimerRes);
- /* start the timer event */
- wTimerID = timeSetEvent(
- (UINT) (1000/TIMER_HZ), /* Delay */
- wTimerRes, /* Resolution */
- (LPTIMECALLBACK) alarming, /* Callback function */
- (DWORD) dwUser, /* User data */
- TIME_PERIODIC); /* Event type (periodic) */
- if (wTimerID == 0) {
- msyslog(LOG_ERR, "timeSetEvent failed: %m");
- exit(1);
- }
- #endif /* SYS_WINNT */
- }
- /*
- * init_io - initialize I/O data and open socket
- */
- static void
- init_io(void)
- {
- #ifdef SYS_WINNT
- WORD wVersionRequested;
- WSADATA wsaData;
- init_transmitbuff();
- #endif /* SYS_WINNT */
- /*
- * Init buffer free list and stat counters
- */
- init_recvbuff(sys_numservers + 2);
- #if defined(HAVE_SIGNALED_IO)
- set_signal();
- #endif
- #ifdef SYS_WINNT
- wVersionRequested = MAKEWORD(1,1);
- if (WSAStartup(wVersionRequested, &wsaData))
- {
- msyslog(LOG_ERR, "No useable winsock.dll: %m");
- exit(1);
- }
- #endif /* SYS_WINNT */
- BLOCKIO();
- /* create a datagram (UDP) socket */
- if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- msyslog(LOG_ERR, "socket() failed: %m");
- exit(1);
- /*NOTREACHED*/
- }
- /*
- * bind the socket to the NTP port
- */
- if (!debug && set_time && !unpriv_port) {
- struct sockaddr_in addr;
- memset((char *)&addr, 0, sizeof addr);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(NTP_PORT);
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- #ifndef SYS_WINNT
- if (errno == EADDRINUSE)
- #else
- if (WSAGetLastError() == WSAEADDRINUSE)
- #endif
- msyslog(LOG_ERR,
- "the NTP socket is in use, exiting");
- else
- msyslog(LOG_ERR, "bind() fails: %m");
- exit(1);
- }
- }
- FD_ZERO(&fdmask);
- FD_SET(fd, &fdmask);
- /*
- * set non-blocking,
- */
- #ifdef USE_FIONBIO
- /* in vxWorks we use FIONBIO, but the others are defined for old systems, so
- * all hell breaks loose if we leave them defined
- */
- #undef O_NONBLOCK
- #undef FNDELAY
- #undef O_NDELAY
- #endif
- #if defined(O_NONBLOCK) /* POSIX */
- if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
- {
- msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m");
- exit(1);
- /*NOTREACHED*/
- }
- #elif defined(FNDELAY)
- if (fcntl(fd, F_SETFL, FNDELAY) < 0)
- {
- msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
- exit(1);
- /*NOTREACHED*/
- }
- #elif defined(O_NDELAY) /* generally the same as FNDELAY */
- if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
- {
- msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m");
- exit(1);
- /*NOTREACHED*/
- }
- #elif defined(FIONBIO)
- if (
- # if defined(VMS)
- (ioctl(fd,FIONBIO,&1) < 0)
- # elif defined(SYS_WINNT)
- (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR)
- # else
- (ioctl(fd,FIONBIO,&on) < 0)
- # endif
- )
- {
- msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
- exit(1);
- /*NOTREACHED*/
- }
- #elif defined(FIOSNBIO)
- if (ioctl(fd,FIOSNBIO,&on) < 0)
- {
- msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m");
- exit(1);
- /*NOTREACHED*/
- }
- #else
- # include "Bletch: Need non-blocking I/O!"
- #endif
- #ifdef HAVE_SIGNALED_IO
- init_socket_sig(fd);
- #endif /* not HAVE_SIGNALED_IO */
- UNBLOCKIO();
- }
- /*
- * sendpkt - send a packet to the specified destination
- */
- static int
- sendpkt(
- struct sockaddr_in *dest,
- struct pkt *pkt,
- int len
- )
- {
- int cc;
- static int horriblecnt = 0;
- #ifdef SYS_WINNT
- DWORD err;
- #endif /* SYS_WINNT */
- total_xmit++; /* count it */
- if (horrible) {
- if (++horriblecnt > HORRIBLEOK) {
- if (debug > 3)
- printf("dropping send (%s)\n", ntoa(dest));
- if (horriblecnt >= HORRIBLEOK+horrible)
- horriblecnt = 0;
- return 0;
- }
- }
- cc = sendto(fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest,
- sizeof(struct sockaddr_in));
- #ifndef SYS_WINNT
- if (cc == -1) {
- if (errno != EWOULDBLOCK && errno != ENOBUFS)
- #else
- if (cc == SOCKET_ERROR) {
- err = WSAGetLastError();
- if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
- #endif /* SYS_WINNT */
- msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
- return -1;
- }
- return 0;
- }
- /*
- * input_handler - receive packets asynchronously
- */
- void
- input_handler(l_fp *xts)
- {
- register int n;
- register struct recvbuf *rb;
- struct timeval tvzero;
- int fromlen;
- fd_set fds;
- l_fp ts;
- ts = *xts; /* we ignore xts, but make the compiler happy */
- /*
- * Do a poll to see if we have data
- */
- for (;;) {
- fds = fdmask;
- tvzero.tv_sec = tvzero.tv_usec = 0;
- n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
- /*
- * If nothing to do, just return. If an error occurred,
- * complain and return. If we've got some, freeze a
- * timestamp.
- */
- if (n == 0)
- return;
- else if (n == -1) {
- if (errno != EINTR) {
- msyslog(LOG_ERR, "select() error: %m");
- }
- return;
- }
- get_systime(&ts);
- /*
- * Get a buffer and read the frame. If we
- * haven't got a buffer, or this is received
- * on the wild card socket, just dump the packet.
- */
- if (initializing || free_recvbuffs == 0) {
- char buf[100];
- #ifndef SYS_WINNT
- (void) read(fd, buf, sizeof buf);
- #else
- /* NT's _read does not operate on nonblocking sockets
- * either recvfrom or ReadFile() has to be used here.
- * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
- * just to be different use recvfrom() here
- */
- recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
- #endif /* SYS_WINNT */
- continue;
- }
- rb = get_free_recv_buffer();
- fromlen = sizeof(struct sockaddr_in);
- rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt,
- sizeof(rb->recv_pkt), 0,
- (struct sockaddr *)&rb->srcadr, &fromlen);
- if (rb->recv_length == -1) {
- freerecvbuf(rb);
- continue;
- }
- /*
- * Got one. Mark how and when it got here,
- * put it on the full list.
- */
- rb->recv_time = ts;
- add_full_recv_buffer(rb);
- total_recv++; /* count it */
- }
- }
- /* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
- /*
- * printserver - print detail information for a server
- */
- static void
- printserver(
- register struct server *pp,
- FILE *fp
- )
- {
- register int i;
- char junk[5];
- char *str;
- if (!debug) {
- (void) fprintf(fp,
- "%-15s %d/%d %03o v%d s%d offset %9s delay %s disp %s\n",
- ntoa(&pp->srcadr),
- pp->xmtcnt,pp->rcvcnt,pp->reach,
- pp->version,pp->stratum,
- lfptoa(&pp->offset, 6), ufptoa(pp->delay, 5),
- ufptoa(pp->dispersion, 4));
- return;
- }
- (void) fprintf(fp, "server %s, port %d\n",
- ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port));
- (void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
- pp->stratum, pp->precision,
- pp->leap & 0x2 ? '1' : '0',
- pp->leap & 0x1 ? '1' : '0',
- pp->trust);
- if (pp->stratum == 1) {
- junk[4] = 0;
- memmove(junk, (char *)&pp->refid, 4);
- str = junk;
- } else {
- str = numtoa(pp->refid);
- }
- (void) fprintf(fp,
- "refid [%s], delay %s, dispersion %s\n",
- str, fptoa((s_fp)pp->delay, 5),
- ufptoa(pp->dispersion, 5));
- (void) fprintf(fp, "transmitted %d, received %d, reachable %03o\n",
- pp->xmtcnt, pp->rcvcnt, pp->reach);
- (void) fprintf(fp, "reference time: %s\n",
- prettydate(&pp->reftime));
- (void) fprintf(fp, "originate timestamp: %s\n",
- prettydate(&pp->org));
- (void) fprintf(fp, "transmit timestamp: %s\n",
- prettydate(&pp->xmt));
- (void) fprintf(fp, "filter delay: ");
- for (i = 0; i < NTP_SHIFT; i++) {
- (void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
- if (i == (NTP_SHIFT>>1)-1)
- (void) fprintf(fp, "\n ");
- }
- (void) fprintf(fp, "\n");
- (void) fprintf(fp, "filter offset:");
- for (i = 0; i < PEER_SHIFT; i++) {
- (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
- if (i == (PEER_SHIFT>>1)-1)
- (void) fprintf(fp, "\n ");
- }
- (void) fprintf(fp, "\n");
- (void) fprintf(fp, "delay %s, dispersion %s\n",
- fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
- (void) fprintf(fp, "offset %s\n\n",
- lfptoa(&pp->offset, 6));
- }
- #if !defined(HAVE_VSPRINTF)
- int
- vsprintf(
- char *str,
- const char *fmt,
- va_list ap
- )
- {
- FILE f;
- int len;
- f._flag = _IOWRT+_IOSTRG;
- f._ptr = str;
- f._cnt = 32767;
- len = _doprnt(fmt, ap, &f);
- *f._ptr = 0;
- return (len);
- }
- #endif