ntpdate.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ntpdate - set the time of day by polling one or more NTP servers
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifndef SYS_WINNT
#include <netdb.h>
#include <sys/resource.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#endif /* SYS_WINNT */
#ifdef SYS_VXWORKS
#include "ioLib.h"
#include "sockLib.h"
#include "timers.h"
/* select wants a zero structure ... */
#endif
#if defined(SYS_HPUX)
#include <utmp.h>
#endif
#include "ntp_fp.h"
#include "ntp.h"
#include "ntp_io.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 SYS_WINNT
on Windows NT timers. */
#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
*/
/*
* Debugging flag
*/
int debug = 0;
/*
* File descriptor masks etc. for call to select
*/
int fd;
#ifdef HAVE_POLL_H
#else
#endif
/*
* 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;
/*
* Simple query flag.
*/
int simple_query = 0;
/*
* Unpriviledged port flag.
*/
int unpriv_port = 0;
/*
* Time to spend measuring drift rate
*/
int rate = 0;
/*
* Program name.
*/
char *progname;
/*
* Systemwide parameters and flags
*/
int sys_numservers = 0; /* number of servers to poll */
int sys_maxservers = 0; /* max number of servers to deal with */
int sys_authenticate = 0; /* true when authenticating */
/*
* The current internal time
*/
u_long current_time = 0;
/*
* Counter for keeping track of completed servers
*/
int complete_servers = 0;
/*
* File of encryption keys
*/
#ifndef KEYFILE
# ifndef SYS_WINNT
# ifdef SYS_SOLARIS
# else
# endif
# else
#define KEYFILE "%windir%\\ntp.keys"
# endif /* SYS_WINNT */
#endif /* KEYFILE */
#ifndef SYS_WINNT
#else
#endif /* SYS_WINNT */
/*
* Miscellaneous flags
*/
extern int syslogit;
int verbose = 0;
int always_step = 0;
int never_step = 0;
#ifndef SYS_WINNT
extern int errno;
#endif /* SYS_WINNT */
/*
* Wait option used when ntpdate is to wait until clock synch.
*/
int wait_secs = 0;
/*
* Multicast option used to auto synch in a NTP Multicast environment.
*/
char *mc_message = "";
#define MC_NONE 0
#define MC_ENABLED 1
#define MC_BROADCAST 2
#define MC_SENDTO 3
#define MC_JOIN 4
#define MC_LISTEN 5
#define MC_TIMEOUT 6
static void clock_filter P((struct server *));
static struct server *clock_select P((void));
static int clock_adjust P((void));
static void addserver P((char *));
static void timer P((void));
static void init_alarm P((void));
#ifndef SYS_WINNT
static RETSIGTYPE alarming P((int));
#else
#endif /* SYS_WINNT */
static void init_io P((void));
static struct recvbuf *getrecvbufs P((void));
static void freerecvbuf P((struct recvbuf *));
static void input_handler P((void));
static void re_init_servers P((void));
static int l_adj_systime P((l_fp *));
static int l_step_systime P((l_fp *));
static void collect P((void));
#ifdef SYS_WINNT
int on = 1;
#endif /* SYS_WINNT */
#ifdef NO_MAIN_ALLOWED
void ntpdatemain P((int, char *[]));
void
void clear_globals()
{
extern int ntp_optind;
/*
* 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;
/*
* Simple query flag.
*/
simple_query = 0;
/*
* Unpriviledged port flag.
*/
unpriv_port = 0;
/*
* Time to spend measuring drift rate
*/
rate = 0;
/*
* Systemwide parameters and flags
*/
sys_numservers = 0; /* number of servers to poll */
sys_maxservers = 0; /* max number of servers to deal with */
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;
/*
* Counter for keeping track of completed servers
*/
complete_servers = 0;
verbose = 0;
always_step = 0;
never_step = 0;
}
#else
int main P((int, char *[]));
#endif
/*
* timer expiries.
*/
#ifndef NO_MAIN_ALLOWED
int main
#else
void ntpdatemain
#endif /* NO_MAIN_ALLOWED */
int argc;
char *argv[];
{
int errflg;
int c;
extern char *ntp_optarg;
extern int ntp_optind;
extern char *Version;
#ifdef SYS_WINNT
exit(1);
}
{
}
#endif /* SYS_WINNT */
#ifdef NO_MAIN_ALLOWED
#endif
errflg = 0;
syslogit = 0;
/*
* Decode argument list
*/
switch (c)
{
case 'a':
c = atoi(ntp_optarg);
sys_authenticate = 1;
sys_authkey = c;
break;
case 'b':
always_step++;
never_step = 0;
break;
case 'B':
never_step++;
always_step = 0;
break;
case 'd':
++debug;
break;
case 'e':
"%s: encryption delay %s is unlikely\n",
errflg++;
} else {
}
break;
case 'k':
break;
case 'm':
break;
case 'o':
break;
case 'p':
c = atoi(ntp_optarg);
if (c <= 0 || c > NTP_SHIFT) {
"%s: number of samples (%d) is invalid\n",
progname, c);
errflg++;
} else {
sys_samples = c;
}
break;
case 'q':
simple_query = 1;
break;
case 'r':
c = atoi(ntp_optarg);
if (c <= 0 || c > (60 * 60)) {
"%s: rate (%d) is invalid: 0 - %d\n",
errflg++;
} else {
rate = c;
}
break;
case 's':
syslogit = 1;
break;
case 't':
"%s: timeout %s is undecodeable\n",
errflg++;
} else {
+ 0x8000) >> 16;
if (sys_timeout == 0)
sys_timeout = 1;
}
break;
case 'v':
verbose = 1;
break;
case 'u':
unpriv_port = 1;
break;
case 'w':
break;
case '?':
++errflg;
break;
default:
break;
}
if (multicast)
sys_maxservers = 255;
else
if (errflg || sys_maxservers == 0) {
"usage: %s [-bBdqsv] [-a key#] [-e delay] [-k file] [-p samples] [-o version#] [-r rate] [-t timeo] server ...\n",
progname);
exit(2);
}
sys_servers = (struct server **)
if (debug || simple_query) {
#ifdef HAVE_SETVBUF
#else
#endif
}
/*
* Logging. Open the syslog if we have to
*/
if (syslogit) {
#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS)
#ifndef LOG_DAEMON
#else
#ifndef LOG_NTP
#define LOG_NTP LOG_DAEMON
#endif
if (debug)
else
#endif /* LOG_DAEMON */
#endif /* SYS_WINNT */
}
/*
* Add servers we are going to be polling
*/
if (sys_numservers == 0) {
exit(1);
}
exit(1);
}
/*
* Initialize the time of day routines and the I/O subsystem
*/
if (sys_authenticate) {
init_auth();
if (!authreadkeys(key_file)) {
exit(1);
}
if (!authhavekey(sys_authkey)) {
char buf[10];
exit(1);
}
}
init_io();
init_alarm();
/*
* Set the priority.
*/
#ifdef SYS_VXWORKS
#endif
#if defined(HAVE_ATT_NICE)
nice (NTPDATE_PRIO);
#endif
#if defined(HAVE_BSD_NICE)
#endif
#ifdef SYS_WINNT
}
#endif /* SYS_WINNT */
initializing = 0;
for (;;) {
collect();
/*
* We've collect()ed all the data we want, so try to adjust the clock.
*/
errflg = clock_adjust();
/*
* Either no server answered our multicast broadcast request or none was
* suitable, so last we try to join the multicast group with incremental
* ttl's until either we receive a broadcast from a server we can use or
* we have reached a max ttl and give up.
*/
int ttl;
sys_servers[0]->event_time = 0;
u_char n;
"trying ttl %d for multicast server synchronization", ttl);
sizeof(mreq));
n = ttl;
collect();
sizeof(mreq));
mc_message = "";
if (! (errflg = clock_adjust()))
break;
"no multicast server suitable for synchronization found");
}
}
if (! errflg)
break;
if (! wait_secs)
break;
/*
* Wait option specified, so we keep trying until we synch up but first we
* go to sleep awhile before trying again. Use a an exponential backed off
* value.
*/
}
/*
* That's all folks ... Just exit() with the clock_adjust() ret value.
*/
if (errflg)
}
void
collect() {
int was_alarmed;
was_alarmed = 0;
#ifdef HAVE_POLL_H
#else
#endif
int nfound;
if (alarm_flag) { /* alarmed? */
was_alarmed = 1;
alarm_flag = 0;
}
/*
* Nothing to do. Wait for something.
*/
#ifndef SYS_VXWORKS
#ifdef HAVE_POLL_H
#else
#endif
#else
#endif
if (nfound > 0)
else if (
#ifndef SYS_WINNT
nfound == -1
#else
#endif /* SYS_WINNT */
) {
#ifndef SYS_WINNT
#endif
#ifdef HAVE_POLL_H
#else
#endif
} else {
#ifndef SYS_VXWORKS
#ifdef HAVE_POLL_H
#else
#endif
#endif
}
if (alarm_flag) { /* alarmed? */
was_alarmed = 1;
alarm_flag = 0;
}
}
/*
* Out here, signals are unblocked. Call receive
* procedure for each incoming packet.
*/
}
/*
* Call timer to process any timeouts
*/
if (was_alarmed) {
if (multicast == MC_BROADCAST) {
/*
* First alarm after a sendto() to the multicast addr, so from now on
* only deal with those servers we've heard from (if any).
*/
}
timer();
was_alarmed = 0;
}
/*
* Go around again
*/
}
/*
* When we get here we've completed the polling of all servers.
* Adjust the clock, then exit.
*/
#ifdef SYS_WINNT
WSACleanup();
#endif
#ifdef SYS_VXWORKS
clock_adjust();
#else
# ifndef SYS_SOLARIS
exit(clock_adjust());
# endif
#endif /* SYS_VXWORKS */
}
/*
* 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
{
if (debug)
/*
* Last message to this server timed out. Shift
* zeros into the filter.
*/
}
/*
* Got all the data we need. Mark this guy
* completed and return.
*/
server->event_time = 0;
return;
}
/*
* If we're here, send another message to the server. Fill in
* the packet and let 'er rip.
*/
/*
* 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;
if (debug > 1)
printf("transmit auth to %s\n",
} else {
if (debug > 1)
}
/*
* Update the server timeout and transmit count
*/
}
/*
* receive - receive and process an incoming frame
*/
static void
{
int has_mac;
int is_authentic;
if (debug)
/*
* Check to see if the packet basically looks like something
* intended for us.
*/
has_mac = 0;
has_mac = 1;
else {
if (debug)
printf("receive: packet length %d\n",
rbufp->recv_length);
return; /* funny length packet */
}
return;
}
if (debug)
printf("receive: mode %d stratum %d\n",
return;
}
/*
* So far, so good. See if this is from a server we know.
*/
if (debug)
printf("receive: server not found\n");
return;
}
/*
* Decode the org timestamp and make sure we're getting a response
* to our last request.
*/
if (debug)
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",
is_authentic = 1;
if (debug)
printf("receive: authentication %s\n",
}
if (!is_authentic)
/*
* Looks good. Record info from the packet.
*/
/*
* Make sure the server is at least somewhat sane. If not, try
* again.
*/
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
*/
/* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */
/*
* Calculate (ci) = ((t1 - t0)/2)+((t2-t3)/2)
* By pushing the division to earlier in the calculation
* we prevent overflow in large offsets.
*/
/*
* Calculate di in t23 in full precision, then truncate
* to an s_fp.
*/
if (debug > 3)
if (di <= 0) { /* value still too raunchy to use? */
di = 0;
} else {
}
/*
* Shift this data in, then transmit again.
*/
}
/*
* server_data - add a sample to the server's filter registers
*/
static void
server_data(server, d, c, e)
s_fp d;
l_fp *c;
u_fp e;
{
register int i;
i = server->filter_nextpt;
if (i < NTP_SHIFT) {
server->filter_delay[i] = d;
server->filter_offset[i] = *c;
server->filter_error[i] = e;
}
}
/*
* clock_filter - determine a server's delay, dispersion and offset
*/
static void
{
register int i, j;
/*
* Sort indices into increasing delay order
*/
for (i = 0; i < sys_samples; i++)
ord[i] = i;
for (i = 0; i < (sys_samples-1); i++) {
for (j = i+1; j < sys_samples; j++) {
continue;
register int 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.
*/
} else {
register s_fp d;
server->dispersion = 0;
for (i = 1; i < sys_samples; i++) {
d = PEER_MAXDISP;
else {
if (d < 0)
d = -d;
if (d > PEER_MAXDISP)
d = PEER_MAXDISP;
}
/*
* XXX This *knows* PEER_FILTER is 1/2
*/
}
}
/*
* We're done
*/
}
/*
* clock_select - select the pick-of-the-litter clock from the samples
* we've got.
*/
static struct server *
{
register int i;
register int nlist;
register s_fp d;
register int j;
register int n;
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];
continue; /* no data */
continue; /* stratum no good */
continue; /* too far away */
}
continue; /* he's in trouble */
continue; /* very broken host */
}
>= NTP_MAXAGE) {
continue; /* too long without sync */
}
continue;
}
/*
* This one seems sane. Find where he belongs
* on the list.
*/
for (i = 0; i < nlist; i++)
break;
for ( ; i < nlist; i++) {
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_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 (++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
*/
+ 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.
*/
+ (FP_SECOND >> (-n))))
break;
for (j = i + 1; j < nlist; 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;
}
/*
* clock_adjust - process what we've received, and adjust the time
* if we got anything decent.
*/
static int
{
register int i;
int dostep;
for (i = 0; i < sys_numservers; i++)
clock_filter(sys_servers[i]);
server = clock_select();
if (debug || simple_query) {
for (i = 0; i < sys_numservers; i++)
}
if (server == 0) {
return(1);
}
if (always_step) {
dostep = 1;
} else if (never_step) {
dostep = 0;
} else {
}
if (dostep) {
}
} else {
#ifndef SYS_WINNT
}
#else
/* The NT SetSystemTimeAdjustment() call achieves slewing by
* changing the clock frequency. This means that we cannot specify
* it to slew the clock by a definite amount and then stop like
* the Unix adjtime() routine. We can technically adjust the clock
* frequency, have ntpdate sleep for a while, and then wake
* up and reset the clock frequency, but this might cause some
* grief if the user attempts to run xntpd immediately after
* ntpdate and the socket is in use.
*/
printf("\nThe -b option is required by ntpdate on Windows NT platforms\n");
exit(1);
#endif /* SYS_WINNT */
}
return(0);
}
/*
* addserver - determine a server's address and allocate a new structure
* for it.
*/
static void
char *serv;
{
static int toomany = 0;
if (sys_numservers >= sys_maxservers) {
if (!toomany) {
/*
* This is actually a `can't happen' now. Leave
* the error message in anyway, though
*/
toomany = 1;
"too many servers (> %d) specified, remainder not used",
}
return;
}
return;
}
}
/*
* findserver - find a server in the list given its address
*/
static struct server *
struct sockaddr_in *addr;
{
register int i;
return 0;
for (i = 0; i < sys_numservers; i++) {
return sys_servers[i];
}
if (multicast == MC_ENABLED) {
/*
* First transmit was done to the muticast addr, so set
* multicast state and mark the multicast addr as complete
* so no additional transmit will be done to it.
*/
sys_servers[0]->event_time = 0;
}
&& sys_numservers < sys_maxservers) {
/*
* We're awaiting replys to our sendto the multicast addr, so
* just add this addr to the server list as if it was speced.
*/
return server;
}
return 0;
}
/*
* timer - process a timer interrupt
*/
static void
timer()
{
register int i;
/*
* Bump the current idea of the time
*/
current_time++;
if (debug) {
static ix = 0;
ix = 0;
}
/*
* Search through the server list looking for guys
* who's event timers have expired. Give these to
* the transmit routine.
*/
for (i = 0; i < sys_numservers; i++) {
if (sys_servers[i]->event_time != 0
transmit(sys_servers[i]);
}
}
/*
* Need to initialize these counters so after a timeout a new set of requests
* (ie: packets) will be transmitted to the servers.
*/
static void
{
int i;
for (i = 0; i < sys_numservers; i++) {
sys_servers[i]->filter_nextpt = 0;
sys_servers[i]->xmtcnt = 0;
}
complete_servers = 0;
}
/*
* init_alarm - set up the timer interrupt
*/
static void
{
#ifndef SYS_WINNT
#ifndef HAVE_TIMER_SETTIME
#else
struct itimerspec ntpdate_itimer;
#endif
#else
#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 */
#ifdef SYS_VXWORKS
#else
-1
#endif
)
{
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.
*/
#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.
*/
#endif
#else /* SYS_WINNT */
_tzset();
/*
* Get previleges needed for fiddling with the clock
*/
/* get the current process token handle */
exit(1);
}
/* get the LUID for system-time privilege. */
/* get set-time privilege for this process. */
/* cannot test return value of AdjustTokenPrivileges. */
if (GetLastError() != ERROR_SUCCESS)
/*
* Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
* of a callback function (on a different thread) rather than
* generating an alarm signal
*/
/* determine max and min resolution supported */
exit(1);
}
/* establish the minimum timer resolution that we'll use */
/* start the timer event */
wTimerRes, /* Resolution */
TIME_PERIODIC); /* Event type (periodic) */
if (wTimerID == 0) {
exit(1);
}
#endif /* SYS_WINNT */
}
#ifndef SYS_WINNT
/*
* alarming - record the occurance of an alarm interrupt
*/
static RETSIGTYPE
int sig;
{
alarm_flag++;
}
#else /* SYS_WINNT */
/*
* alarming for WinNT - invoke the timer() routine
*/
{
extern int debug;
static int initializing2 = 1;
extern int fd;
#ifdef DEBUG
#endif
if (initializing2) {
initializing2 = 0;
}
#ifdef DEBUG
if (debug > 3) {
GetSystemTime(&st);
printf("thread %u (timer callback): time %02u:%02u:%02u:%03u\n",
}
#endif
timer();
}
#endif /* SYS_WINNT */
/*
* We do asynchronous input using the SIGIO facility. A number of
* recvbuf buffers are preallocated for input. In the signal
* handler we poll to see if the socket is ready and read the
* packets from it into the recvbuf's along with a time stamp and
* an indication of the source host and the interface it was received
* through. This allows us to get as accurate receive time stamps
* as possible independent of other processing going on.
*
* We allocate a number of recvbufs equal to the number of servers
* plus 2. This should be plenty.
*/
/*
* recvbuf lists
*/
int full_recvbufs; /* number of full ones */
int free_recvbufs;
/*
* init_io - initialize I/O data and open socket
*/
static void
init_io()
{
register int i;
/*
* Init buffer free list and stat counters
*/
freelist = 0;
for (i = sys_numservers + 2; i > 0; i--) {
rb++;
}
fulllist = 0;
full_recvbufs = 0;
/*
* Open the socket
*/
/* create a datagram (UDP) socket */
exit(1);
/*NOTREACHED*/
}
/*
* bind the socket to the NTP port
*/
struct sockaddr_in addr;
#ifndef SYS_WINNT
if (errno == EADDRINUSE)
#else
if (WSAGetLastError() == WSAEADDRINUSE)
#endif /* SYS_WINNT */
"the NTP socket is in use, exiting");
else
exit(1);
}
}
#ifdef HAVE_POLL_H
#else
#endif
/*
* set non-blocking,
*/
#ifndef SYS_WINNT
#ifdef SYS_VXWORKS
{
exit(1);
}
}
#else
#if defined(O_NONBLOCK)
exit(1);
/*NOTREACHED*/
}
#else /* O_NONBLOCK */
#if defined(FNDELAY)
exit(1);
/*NOTREACHED*/
}
#else /* FNDELAY */
# include "Bletch: Need non blocking I/O"
#endif /* FNDELAY */
#endif /* SYS_VXWORKS */
#endif /* O_NONBLOCK */
#else /* SYS_WINNT */
exit(1);
}
#endif /* SYS_WINNT */
}
/* XXX ELIMINATE getrecvbufs (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */
/*
* getrecvbufs - get receive buffers which have data in them
*
* ***N.B. must be called with SIGIO blocked***
*/
static struct recvbuf *
{
if (full_recvbufs == 0) {
return (struct recvbuf *)0; /* nothing has arrived */
}
/*
* Get the fulllist chain and mark it empty
*/
fulllist = 0;
full_recvbufs = 0;
/*
* Return the chain
*/
return rb;
}
/* XXX ELIMINATE freerecvbuf (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */
/*
* freerecvbuf - make a single recvbuf available for reuse
*/
static void
{
}
/*
* sendpkt - send a packet to the specified destination
*/
static void
struct sockaddr_in *dest;
int len;
{
int cc;
#ifdef SYS_WINNT
#endif /* SYS_WINNT */
sizeof(struct sockaddr_in));
#ifndef SYS_WINNT
if (cc == -1) {
}
#else
if (cc == SOCKET_ERROR) {
err = WSAGetLastError();
}
#endif /* SYS_WINNT */
}
/*
* input_handler - receive packets asynchronously
*/
static void
{
register int n;
#ifdef HAVE_POLL_H
#else
#endif
/*
* Do a poll to see if we have data
*/
for (;;) {
#ifdef HAVE_POLL_H
#else
#endif
/*
* 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) {
#ifdef HAVE_POLL_H
#else
#endif
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_recvbufs == 0) {
char buf[100];
if (debug)
#ifndef SYS_WINNT
#else
/* NT's _read does not operate on nonblocking sockets
* either recvfrom or ReadFile() has to be used here.
* ReadFile is used in [xntpd]ntp_intres() and xntpdc,
* just to be different use recvfrom() here
*/
#endif /* SYS_WINNT */
continue;
}
continue;
}
/*
* Got one. Mark how and when it got here,
* put it on the full list.
*/
}
}
#ifndef SYS_WINNT
/*
* adj_systime - do a big long slew of the system time
*/
static int
{
int isneg = 0;
#ifndef STEP_SLEW
#endif
/*
* Take the absolute value of the offset
*/
isneg = 1;
}
#ifndef STEP_SLEW
/*
* Calculate the overshoot. XXX N.B. This code *knows*
* ADJ_OVERSHOOT is 1/2.
*/
}
#endif
if (isneg) {
}
return 0;
}
}
return 1;
}
#endif /* SYS_WINNT */
/*
*/
static int
{
#ifdef SLEWALWAYS
#ifdef STEP_SLEW
int isneg;
int n;
if (debug) return 1;
/*
* Take the absolute value of the offset
*/
isneg = 1;
} else
isneg = 0;
n = step_systime_real(ts);
if (!n)
return n;
if (isneg)
else
}
/*
* Just add adjustment into the current offset. The update
* routine will take care of bringing the system clock into
* line.
*/
#endif
if (debug)
return 1;
#ifdef FORCE_NTPDATE_STEP
return step_systime_real(ts);
#else
return 1;
#endif
#else /* SLEWALWAYS */
if (debug)
return 1;
return step_systime_real(ts);
#endif /* SLEWALWAYS */
}
/*
* getnetnum - given a host name, return its net number
*/
static int
char *host;
{
return 1;
return (1);
}
return (0);
}
/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
/*
* printserver - print detail information for a server
*/
static void
{
register int i;
char junk[5];
char *str;
if (!debug) {
return;
}
junk[4] = 0;
} else {
}
"refid [%s], delay %s, dispersion %s\n",
for (i = 0; i < NTP_SHIFT; i++) {
}
for (i = 0; i < PEER_SHIFT; i++) {
}
}
#if !defined(HAVE_VSPRINTF)
/*
* This nugget for pre-tahoe 4.3bsd systems
*/
#define const
#endif
int
char *str;
const char *fmt;
{
FILE f;
int len;
f._cnt = 32767;
*f._ptr = 0;
return (len);
}
#endif
#if 0
/* override function in library since SA_RESTART makes ALL syscalls restart */
#ifdef SA_RESTART
void
int sig;
void (*func)();
{
int n;
while (1)
{
continue;
break;
}
if (n == -1)
{
perror("sigaction");
exit(1);
}
}
#endif
#endif