Initial import from FreeBSD RELENG_4:
[games.git] / contrib / ntp / ntpdate / ntptimeset.c
1 /*
2  * ntptimeset - get/set the time via ntp
3  *
4  * GOAL:
5  * The goal of ntptime is to set the current time on system startup
6  * to the best possible time using the network very wisely. It is assumed
7  * that after a resonable time has been sett then ntp daemon will
8  * maintain it.
9  *
10  * PROBLEM DOMAIN:
11  * We have three sets of issues related to acheiving the goal. The first
12  * issue is using the network when normal traffic is happening or when
13  * the entire network world is recovering from a campus wide power failure
14  * and is restarting. The second issue is the class of machine whether it
15  * is a user's office workstation being handled by an uneducated user or
16  * a server computer being handled by a trained operations staff. The third
17  * issue is whether the ratio of people to computers and whether the 
18  * environment is stable and viable or not.
19  *
20  * NETWORK USAGE:
21  * The first issue of using the network wisely is a question of whether
22  * the network load and time server load and state are normal. If things
23  * are normal ntptime can do what ntpdate does of sending out 4 packets
24  * quickly to each server (new transmit done with each ack). However
25  * if network or time load is high then this scheme will simply contribute
26  * to problems. Given we have minimal state, we simply weight lost packets
27  * significantly and make sure we throttle output as much as possible
28  * without performance lost for quick startups.
29  *
30  * TRAINING AND KNOWLEDGE:
31  * The second issue of uneducated user of a office workstation versus a
32  * trained operation staff of a server machine translates into simply an
33  * issue of untrained and trained users.
34  * 
35  * The training issue implies that for the sake of the users involved in the
36  * handling of their office workstation, problems and options should be
37  * communicated simply and effectively and not in terse expert related
38  * descriptions without possible options to be taken. The operator's training
39  * and education enables them to deal with either type of communication and
40  * control.
41  *
42  * AUTOMATION AND MANUAL CONTROL:
43  * The last issue boils down to a design problem. If the design tends to go
44  * into a manual mode when the environment is non-viable then one person
45  * handling many computers all at the same time will be heavily impacted. On
46  * the other hand, if the design tends to be automatic and does not indicate
47  * a way for the user to take over control then the computer will be
48  * unavailable for the user until the proble is resolved by someone else or
49  * the user.
50  *
51  * NOTE: Please do not have this program print out every minute some line,
52  *       of output. If this happens and the environment is in trouble then
53  *       many pages of paper on many different machines will be filled up.
54  *       Save some tress in your lifetime.
55  * 
56  * CONCLUSION:
57  * The behavior of the program derived from these three issues should be
58  * that during normal situations it quickly sets the time and allow the
59  * system to startup.
60  *
61  * However during abnormal conditions as detected by unresponsive servers,
62  * out-of-sync or bad responses and other detections, it should print out
63  * a simple but clear message and continue in a mellow way to get the best
64  * possible time. It may never get the time and if so should also indicate
65  * this.
66  *
67  * Rudy Nedved
68  * 18-May-1993
69  *
70  ****************************************************************
71  *
72  * Much of the above is confusing or no longer relevant.  For example,
73  * it is rare these days for a machine's console to be a printing terminal,
74  * so the comment about saving trees doesn't mean much.  Nonetheless,
75  * the basic principles still stand:
76  *
77  * - Work automatically, without human control or intervention.  To
78  *   this end, we use the same configuration file as ntpd itself, so
79  *   you don't have to specify servers or other information on the
80  *   command line.  We also recognize that sometimes we won't be able
81  *   to contact any servers, and give up in that event instead of
82  *   hanging forever.
83  *
84  * - Behave in a sane way, both internally and externally, even in the
85  *   face of insane conditions.  That means we back off quickly when
86  *   we don't hear a response, to avoid network congestion.  Like
87  *   ntpd, we verify responses from several servers before accepting
88  *   the new time data.
89  *
90  *   However, we don't assume that the local clock is right, or even
91  *   close, because it might not be at boot time, and we want to catch
92  *   and correct that situation.  This behaviour has saved us in several
93  *   instances.  On HP-UX 9.0x, there used to be a bug in adjtimed which
94  *   would cause the time to be set to some wild value, making the machine
95  *   essentially unusable (we use Kerberos authentication pervasively,
96  *   and it requires workstations and servers to have a time within five
97  *   minutes of the Kerberos server).  We also have problems on PC's
98  *   running both Linux and some Microsoft OS -- they tend to disagree
99  *   on what the BIOS clock should say, and who should update it, and
100  *   when.  On those systems, we not only run ntptimeset at boot, we
101  *   also reset the BIOS clock based on the result, so the correct
102  *   time will be retained across reboots.
103  *
104  * For these reasons, and others, we have continued to use this tool
105  * rather than ntpdate.  It is run automatically at boot time on every
106  * workstation and server in our facility.
107  *
108  * In the past, we called this program 'ntptime'.  Unfortunately, the
109  * ntp v4 distribution also includes a program with that name.  In
110  * order to avoid confusion, we have renamed our program 'ntptimeset',
111  * which more accurately describes what it does.
112  *
113  * Jeffrey T. Hutzelman (N3NHS) <jhutz+@cmu.edu>
114  * School of Computer Science - Research Computing Facility
115  * Carnegie Mellon University - Pittsburgh, PA
116  * 16-Aug-1999
117  *
118  */
119
120 #ifdef HAVE_CONFIG_H
121 # include <config.h>
122 #endif
123
124 #include "ntp_fp.h"
125 #include "ntp.h"
126 #include "ntp_io.h"
127 #include "iosignal.h"
128 #include "ntp_unixtime.h"
129 #include "ntpdate.h"
130 #include "ntp_string.h"
131 #include "ntp_syslog.h"
132 #include "ntp_select.h"
133 #include "ntp_stdlib.h"
134
135 #ifdef HAVE_UNISTD_H
136 # include <unistd.h>
137 #endif
138
139 #include <stdio.h>
140 #include <signal.h>
141 #include <ctype.h>
142 #ifndef SYS_WINNT
143 # include <netdb.h>
144 # include <sys/signal.h>
145 # include <sys/ioctl.h>
146 #endif /* SYS_WINNT */
147
148 #ifdef HAVE_SYS_RESOURCE_H
149 # include <sys/resource.h>
150 #endif /* HAVE_SYS_RESOURCE_H */
151
152 #ifdef SYS_VXWORKS
153 # include "ioLib.h"
154 # include "sockLib.h"
155 # include "timers.h"
156 #endif
157
158 #include "recvbuff.h"
159
160 #ifdef SYS_WINNT
161 # define TARGET_RESOLUTION 1  /* Try for 1-millisecond accuracy
162                                 on Windows NT timers. */
163 #pragma comment(lib, "winmm")
164 #endif /* SYS_WINNT */
165
166 /*
167  * Scheduling priority we run at
168  */
169 #ifndef SYS_VXWORKS
170 # define        NTPDATE_PRIO    (-12)
171 #else
172 # define        NTPDATE_PRIO    (100)
173 #endif
174
175 #if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
176 /* POSIX TIMERS - vxWorks doesn't have itimer - casey */
177 static timer_t ntpdate_timerid;
178 #endif
179
180 /*
181  * Compatibility stuff for Version 2
182  */
183 #define NTP_MAXSKW      0x28f   /* 0.01 sec in fp format */
184 #define NTP_MINDIST 0x51f       /* 0.02 sec in fp format */
185 #define NTP_INFIN       15      /* max stratum, infinity a la Bellman-Ford */
186 #define NTP_MAXWGT      (8*FP_SECOND)   /* maximum select weight 8 seconds */
187 #define NTP_MAXLIST 5   /* maximum select list size */
188 #define PEER_SHIFT      8       /* 8 suitable for crystal time base */
189
190 /*
191  * Debugging flag
192  */
193 volatile int debug = 0;
194
195 /*
196  * File descriptor masks etc. for call to select
197  */
198 int fd;
199 fd_set fdmask;
200
201 /*
202  * Initializing flag.  All async routines watch this and only do their
203  * thing when it is clear.
204  */
205 int initializing = 1;
206
207 /*
208  * Alarm flag.  Set when an alarm occurs
209  */
210 volatile int alarm_flag = 0;
211
212 /*
213  * Set the time if valid time determined
214  */
215 int set_time = 0;
216
217 /*
218  * transmission rate control
219  */
220 #define MINTRANSMITS    (3)     /* minimum total packets per server */
221 #define MAXXMITCOUNT    (2)     /* maximum packets per time interrupt */
222
223 /*
224  * time setting constraints
225  */
226 #define DESIREDDISP     (4*FP_SECOND)   /* desired dispersion, (fp 4) */
227 int max_period = DEFMAXPERIOD;
228 int min_servers = DEFMINSERVERS;
229 int min_valid = DEFMINVALID;
230
231 /*
232  * counters related to time setting constraints
233  */
234 int contacted = 0;              /* # of servers we have sent to */
235 int responding = 0;             /* servers responding */
236 int validcount = 0;             /* servers with valid time */
237 int valid_n_low = 0;            /* valid time servers with low dispersion */
238
239 /*
240  * Unpriviledged port flag.
241  */
242 int unpriv_port = 0;
243
244 /*
245  * Program name.
246  */
247 char *progname;
248
249 /*
250  * Systemwide parameters and flags
251  */
252 struct server **sys_servers;    /* the server list */
253 int sys_numservers = 0;         /* number of servers to poll */
254 int sys_authenticate = 0;       /* true when authenticating */
255 u_int32 sys_authkey = 0;        /* set to authentication key in use */
256 u_long sys_authdelay = 0;       /* authentication delay */
257
258 /*
259  * The current internal time
260  */
261 u_long current_time = 0;
262
263 /*
264  * File of encryption keys
265  */
266
267 #ifndef KEYFILE
268 # ifndef SYS_WINNT
269 #define KEYFILE         "/etc/ntp.keys"
270 # else
271 #define KEYFILE         "%windir%\\ntp.keys"
272 # endif /* SYS_WINNT */
273 #endif /* KEYFILE */
274
275 #ifndef SYS_WINNT
276 const char *key_file = KEYFILE;
277 #else
278 char key_file_storage[MAX_PATH+1], *key_file ;
279 #endif   /* SYS_WINNT */
280
281 /*
282  * total packet counts
283  */
284 u_long total_xmit = 0;
285 u_long total_recv = 0;
286
287 /*
288  * Miscellaneous flags
289  */
290 int verbose = 0;
291 #define HORRIBLEOK      3       /* how many packets to let out */
292 int horrible = 0;       /* how many packets we drop for testing */
293 int secondhalf = 0;     /* second half of timeout period */
294 int printmsg = 0;       /* print time response analysis */
295
296 /*
297  * The half time and finish time in internal time
298  */
299 u_long half_time = 0;
300 u_long finish_time = 0;
301
302
303 int     ntptimesetmain  P((int argc, char *argv[]));
304 static  void    analysis        P((int final));
305 static  int     have_enough     P((void));
306 static  void    transmit        P((register struct server *server));
307 static  void    receive         P((struct recvbuf *rbufp));
308 static  void    clock_filter P((register struct server *server, s_fp d, l_fp *c));
309 static  void    clock_count     P((void));
310 static  struct server *clock_select P((void));
311 static  void    set_local_clock P((void));
312 static  struct server *findserver P((struct sockaddr_in *addr));
313 static  void    timer           P((void));
314 #ifndef SYS_WINNT
315 static  RETSIGTYPE      alarming        P((int sig));
316 #endif /* SYS_WINNT */
317 static  void    init_alarm      P((void));
318 static  void    init_io         P((void));
319 static  int     sendpkt         P((struct sockaddr_in *dest, struct pkt *pkt, int len));
320         void    input_handler   P((l_fp *xts));
321 static  void    printserver     P((register struct server *pp, FILE *fp));
322 #if !defined(HAVE_VSPRINTF)
323 int     vsprintf        P((char *str, const char *fmt, va_list ap));
324 #endif
325
326 #ifdef HAVE_SIGNALED_IO
327 extern  void    wait_for_signal P((void));
328 extern  void    unblock_io_and_alarm P((void));
329 extern  void    block_io_and_alarm P((void));
330 #endif
331
332
333 #ifdef NO_MAIN_ALLOWED
334 CALL(ntptimeset,"ntptimeset",ntptimesetmain);
335
336 void clear_globals()
337 {
338   /*
339    * Debugging flag
340    */
341   debug = 0;
342
343   ntp_optind = 0;
344
345   /*
346    * Initializing flag.  All async routines watch this and only do their
347    * thing when it is clear.
348    */
349   initializing = 1;
350
351   /*
352    * Alarm flag.  Set when an alarm occurs
353    */
354   alarm_flag = 0;
355
356   /*
357    * Unpriviledged port flag.
358    */
359   unpriv_port = 0;
360
361   /*
362    * Systemwide parameters and flags
363    */
364   sys_numservers = 0;     /* number of servers to poll */
365   sys_authenticate = 0;   /* true when authenticating */
366   sys_authkey = 0;         /* set to authentication key in use */
367   sys_authdelay = 0;   /* authentication delay */
368
369   /*
370    * The current internal time
371    */
372   current_time = 0;
373
374   verbose = 0;
375 }
376 #endif /* NO_MAIN_ALLOWED */
377
378 /*
379  * Main program.  Initialize us and loop waiting for I/O and/or
380  * timer expiries.
381  */
382 #ifndef NO_MAIN_ALLOWED
383 int
384 main(
385         int argc,
386         char *argv[]
387         )
388 {
389         return ntptimesetmain(argc, argv);
390 }
391 #endif /* NO_MAIN_ALLOWED */
392            
393
394 int
395 ntptimesetmain(
396         int argc,
397         char *argv[]
398         )
399 {
400         int was_alarmed;
401         struct recvbuf *rbuflist;
402         struct recvbuf *rbuf;
403         l_fp tmp;
404         int errflg;
405         int c;
406         extern char *ntp_optarg;
407         extern int ntp_optind;
408         int ltmp;
409         char *cfgpath;
410
411 #ifdef SYS_WINNT
412         HANDLE process_handle;
413
414         wVersionRequested = MAKEWORD(1,1);
415         if (WSAStartup(wVersionRequested, &wsaData)) {
416                 msyslog(LOG_ERR, "No useable winsock.dll: %m");
417                 exit(1);
418         }
419 #endif /* SYS_WINNT */
420
421 #ifdef NO_MAIN_ALLOWED
422         clear_globals();
423 #endif
424
425         errflg = 0;
426         cfgpath = 0;
427         progname = argv[0];
428         syslogit = 0;
429
430         /*
431          * Decode argument list
432          */
433         while ((c = ntp_getopt(argc, argv, "a:c:de:slt:uvHS:V:")) != EOF)
434                 switch (c)
435                 {
436                 case 'a':
437                         c = atoi(ntp_optarg);
438                         sys_authenticate = 1;
439                         sys_authkey = c;
440                         break;
441                 case 'c':
442                         cfgpath = ntp_optarg;
443                         break;
444                 case 'd':
445                         ++debug;
446                         break;
447                 case 'e':
448                         if (!atolfp(ntp_optarg, &tmp)
449                             || tmp.l_ui != 0) {
450                                 (void) fprintf(stderr,
451                                     "%s: encryption delay %s is unlikely\n",
452                                     progname, ntp_optarg);
453                                 errflg++;
454                         } else {
455                                 sys_authdelay = tmp.l_uf;
456                         }
457                         break;
458                 case 's':
459                         set_time = 1;
460                         break;
461                 case 'l':
462                         syslogit = 1;
463                         break;
464                 case 't':
465                         ltmp = atoi(ntp_optarg);
466                         if (ltmp <= 0) {
467                             (void) fprintf(stderr,
468                                 "%s: maximum time period (%d) is invalid\n",
469                                 progname, ltmp);
470                             errflg++;
471                         }
472                         else
473                             max_period = ltmp;
474                         break;
475                 case 'u':
476                         unpriv_port = 1;
477                         break;
478                 case 'v':
479                         ++verbose;
480                         break;
481                 case 'H':
482                         horrible++;
483                         break;
484                 case 'S':
485                         ltmp = atoi(ntp_optarg);
486                         if (ltmp <= 0) {
487                             (void) fprintf(stderr,
488                                 "%s: minimum responding (%d) is invalid\n",
489                                 progname, ltmp);
490                             errflg++;
491                         }
492                         else
493                             min_servers = ltmp;
494                         break;
495                 case 'V':
496                         ltmp = atoi(ntp_optarg);
497                         if (ltmp <= 0) {
498                             (void) fprintf(stderr,
499                                 "%s: minimum valid (%d) is invalid\n",
500                                 progname, ltmp);
501                             errflg++;
502                         }
503                         else
504                             min_valid = ltmp;
505                         break;
506                 case '?':
507                         ++errflg;
508                         break;
509                 default:
510                         break;
511                 }
512
513         
514         if (errflg || ntp_optind < argc) {
515                 fprintf(stderr,"usage: %s [switches...]\n",progname);
516                 fprintf(stderr,"  -v       (verbose)\n");
517                 fprintf(stderr,"  -c path  (set config file path)\n");
518                 fprintf(stderr,"  -a key   (authenticate using key)\n");
519                 fprintf(stderr,"  -e delay (authentication delay)\n");
520                 fprintf(stderr,"  -S num   (# of servers that must respond)\n");
521                 fprintf(stderr,"  -V num   (# of servers that must valid)\n");
522                 fprintf(stderr,"  -s       (set the time based if okay)\n");
523                 fprintf(stderr,"  -t secs  (time period before ending)\n");
524                 fprintf(stderr,"  -l       (use syslog facility)\n");
525                 fprintf(stderr,"  -u       (use unprivileged port)\n");
526                 fprintf(stderr,"  -H       (drop packets for debugging)\n");
527                 fprintf(stderr,"  -d       (debug output)\n");
528                 exit(2);
529         }
530
531         /*
532          * Logging.  Open the syslog if we have to
533          */
534         if (syslogit) {
535 #if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
536 # ifndef        LOG_DAEMON
537                 openlog("ntptimeset", LOG_PID);
538 # else
539
540 #  ifndef       LOG_NTP
541 #       define  LOG_NTP LOG_DAEMON
542 #  endif
543                 openlog("ntptimeset", LOG_PID | LOG_NDELAY, LOG_NTP);
544                 if (debug)
545                         setlogmask(LOG_UPTO(LOG_DEBUG));
546                 else
547                         setlogmask(LOG_UPTO(LOG_INFO));
548 # endif /* LOG_DAEMON */
549 #endif  /* SYS_WINNT */
550         }
551
552         if (debug || verbose)
553                 msyslog(LOG_INFO, "%s", Version);
554
555         if (horrible)
556                 msyslog(LOG_INFO, "Dropping %d out of %d packets",
557                         horrible,horrible+HORRIBLEOK);
558         /*
559          * Add servers we are going to be polling
560          */
561         loadservers(cfgpath);
562
563         if (sys_numservers < min_servers) {
564                 msyslog(LOG_ERR, "Found %d servers, require %d servers",
565                         sys_numservers,min_servers);
566                 exit(2);
567         }
568
569         /*
570          * determine when we will end at least
571          */
572         finish_time = max_period * TIMER_HZ;
573         half_time = finish_time >> 1;
574
575         /*
576          * Initialize the time of day routines and the I/O subsystem
577          */
578         if (sys_authenticate) {
579                 init_auth();
580 #ifdef SYS_WINNT
581                 if (!key_file) key_file = KEYFILE;
582                 if (!ExpandEnvironmentStrings(key_file, key_file_storage, MAX_PATH))
583                 {
584                         msyslog(LOG_ERR, "ExpandEnvironmentStrings(%s) failed: %m\n",
585                                 key_file);
586                 } else {
587                         key_file = key_file_storage;
588                 }
589 #endif /* SYS_WINNT */
590
591                 if (!authreadkeys(key_file)) {
592                         msyslog(LOG_ERR, "no key file, exiting");
593                         exit(1);
594                 }
595                 if (!authistrusted(sys_authkey)) {
596                         char buf[10];
597
598                         (void) sprintf(buf, "%lu", (unsigned long)sys_authkey);
599                         msyslog(LOG_ERR, "authentication key %s unknown", buf);
600                         exit(1);
601                 }
602         }
603         init_io();
604         init_alarm();
605
606         /*
607          * Set the priority.
608          */
609 #ifdef SYS_VXWORKS
610         taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
611 #endif
612 #if defined(HAVE_ATT_NICE)
613         nice (NTPDATE_PRIO);
614 #endif
615 #if defined(HAVE_BSD_NICE)
616         (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
617 #endif
618 #ifdef SYS_WINNT
619         process_handle = GetCurrentProcess();
620         if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
621                 msyslog(LOG_ERR, "SetPriorityClass failed: %m");
622         }
623 #endif /* SYS_WINNT */
624
625         initializing = 0;
626
627         /*
628          * Use select() on all on all input fd's for unlimited
629          * time.  select() will terminate on SIGALARM or on the
630          * reception of input.  Using select() means we can't do
631          * robust signal handling and we get a potential race
632          * between checking for alarms and doing the select().
633          * Mostly harmless, I think.
634          * Keep going until we have enough information, or time is up.
635          */
636         /* On VMS, I suspect that select() can't be interrupted
637          * by a "signal" either, so I take the easy way out and
638          * have select() time out after one second.
639          * System clock updates really aren't time-critical,
640          * and - lacking a hardware reference clock - I have
641          * yet to learn about anything else that is.
642          */
643         was_alarmed = 0;
644         rbuflist = (struct recvbuf *)0;
645         while (finish_time > current_time) {
646 #if !defined(HAVE_SIGNALED_IO) 
647                 fd_set rdfdes;
648                 int nfound;
649 #elif defined(HAVE_SIGNALED_IO)
650                 block_io_and_alarm();
651 #endif
652
653                 rbuflist = getrecvbufs();       /* get received buffers */
654                 if (printmsg) {
655                         printmsg = 0;
656                         analysis(0);
657                 }
658                 if (alarm_flag) {               /* alarmed? */
659                         was_alarmed = 1;
660                         alarm_flag = 0;
661                 }
662
663                 if (!was_alarmed && rbuflist == (struct recvbuf *)0) {
664                         /*
665                          * Nothing to do.  Wait for something.
666                          */
667 #ifndef HAVE_SIGNALED_IO
668                         rdfdes = fdmask;
669 # if defined(VMS) || defined(SYS_VXWORKS)
670                         /* make select() wake up after one second */
671                         {
672                                 struct timeval t1;
673
674                                 t1.tv_sec = 1; t1.tv_usec = 0;
675                                 nfound = select(fd+1, &rdfdes, (fd_set *)0,
676                                                 (fd_set *)0, &t1);
677                         }
678 # else
679                         nfound = select(fd+1, &rdfdes, (fd_set *)0,
680                                         (fd_set *)0, (struct timeval *)0);
681 # endif /* VMS */
682                         if (nfound > 0) {
683                                 l_fp ts;
684                                 get_systime(&ts);
685                                 (void)input_handler(&ts);
686                         }
687                         else if (nfound == -1 && errno != EINTR)
688                                 msyslog(LOG_ERR, "select() error: %m");
689                         else if (debug) {
690 # if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 /* to unclutter log */
691                                 msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
692 # endif
693                         }
694 #else /* HAVE_SIGNALED_IO */
695                         
696                         wait_for_signal();
697 #endif /* HAVE_SIGNALED_IO */
698                         if (alarm_flag)         /* alarmed? */
699                         {
700                                 was_alarmed = 1;
701                                 alarm_flag = 0;
702                         }
703                         rbuflist = getrecvbufs();  /* get received buffers */
704                 }
705 #ifdef HAVE_SIGNALED_IO
706                 unblock_io_and_alarm();
707 #endif /* HAVE_SIGNALED_IO */
708
709                 /*
710                  * Out here, signals are unblocked.  Call timer routine
711                  * to process expiry.
712                  */
713                 if (was_alarmed)
714                 {
715                         timer();
716                         was_alarmed = 0;
717                 }
718
719                 /*
720                  * Call the data procedure to handle each received
721                  * packet.
722                  */
723                 while (rbuflist != (struct recvbuf *)0)
724                 {
725                         rbuf = rbuflist;
726                         rbuflist = rbuf->next;
727                         receive(rbuf);
728                         freerecvbuf(rbuf);
729                 }
730 #if defined DEBUG && defined SYS_WINNT
731                 if (debug > 4)
732                     printf("getrecvbufs: %ld handler interrupts, %ld frames\n",
733                            handler_calls, handler_pkts);
734 #endif
735
736                 /*
737                  * Do we have enough information to stop now?
738                  */
739                 if (have_enough())
740                         break;  /* time to end */
741
742                 /*
743                  * Go around again
744                  */
745         }
746
747         /*
748          * adjust the clock and exit accordingly
749          */
750         set_local_clock();
751
752         /*
753          * if we get here then we are in trouble
754          */
755         return(1);
756 }
757
758
759 /*
760  * analysis - print a message indicating what is happening with time service
761  *            must mimic have_enough() procedure.
762  */
763 static void
764 analysis(
765         int final
766         )
767 {
768         if (contacted < sys_numservers) {
769                 printf("%d servers of %d have been probed with %d packets\n",
770                        contacted,sys_numservers,MINTRANSMITS);
771                 return;
772         }
773         if (!responding) {
774                 printf("No response from any of %d servers, network problem?\n",
775                        sys_numservers);
776                 return;
777         }
778         else if (responding < min_servers) {
779                 printf("%d servers out of %d responding, need at least %d.\n",
780                        responding, sys_numservers, min_servers);
781                 return;
782         }
783         if (!validcount) {
784                 printf("%d servers responding but none have valid time\n",
785                        responding);
786                 return;
787         }
788         else if (validcount < min_valid) {
789                 printf("%d servers responding, %d are valid, need %d valid\n",
790                        responding,validcount,min_valid);
791                 return;
792         }
793         if (!final && valid_n_low != validcount) {
794                 printf("%d valid servers but only %d have low dispersion\n",
795                        validcount,valid_n_low);
796                 return;
797         }
798 }
799
800
801 /* have_enough - see if we have enough information to terminate probing
802  */
803 static int
804 have_enough(void)
805 {
806         /* have we contacted all servers yet? */
807         if (contacted < sys_numservers)
808                 return 0;       /* no...try some more */
809
810         /* have we got at least minimum servers responding? */
811         if (responding < min_servers)
812                 return 0;       /* no...try some more */
813
814         /* count the clocks */
815         (void) clock_count();
816
817         /* have we got at least minimum valid clocks? */
818         if (validcount <= 0 || validcount < min_valid)
819                 return 0;       /* no...try some more */
820
821         /* do we have all valid servers with low dispersion */
822         if (!secondhalf && valid_n_low != validcount)
823                 return 0;
824
825         /* if we get into the secondhalf then we ignore dispersion */
826
827         /* all conditions have been met...end */
828         return 1;
829 }
830
831
832 /*
833  * transmit - transmit a packet to the given server, or mark it completed.
834  *            This is called by the timeout routine and by the receive
835  *            procedure.
836  */
837 static void
838 transmit(
839         register struct server *server
840         )
841 {
842         struct pkt xpkt;
843         int timeout;
844
845         if (debug > 2)
846                 printf("transmit(%s)\n", ntoa(&server->srcadr));
847
848         if ((server->reach & 01) == 0) {
849                 l_fp ts;
850                 /*
851                  * Last message to this server timed out.  Shift
852                  * zeros into the filter.
853                  */
854                 L_CLR(&ts);
855                 clock_filter(server, 0, &ts);
856         }
857
858         /*
859          * shift reachable register over
860          */
861         server->reach <<= 1;
862
863         /*
864          * If we're here, send another message to the server.  Fill in
865          * the packet and let 'er rip.
866          */
867         xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
868                 server->version, MODE_CLIENT);
869         xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
870         xpkt.ppoll = NTP_MINPOLL;
871         xpkt.precision = NTPDATE_PRECISION;
872         xpkt.rootdelay = htonl(NTPDATE_DISTANCE);
873         xpkt.rootdispersion = htonl(NTPDATE_DISP);
874         xpkt.refid = htonl(NTPDATE_REFID);
875         L_CLR(&xpkt.reftime);
876         L_CLR(&xpkt.org);
877         L_CLR(&xpkt.rec);
878
879         /*
880          * Determine whether to authenticate or not.  If so,
881          * fill in the extended part of the packet and do it.
882          * If not, just timestamp it and send it away.
883          */
884         if (sys_authenticate) {
885                 int len;
886
887                 xpkt.exten[0] = htonl(sys_authkey);
888                 get_systime(&server->xmt);
889                 L_ADDUF(&server->xmt, sys_authdelay);
890                 HTONL_FP(&server->xmt, &xpkt.xmt);
891                 len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC);
892                 if (sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len))) {
893                         if (debug > 1)
894                                 printf("failed transmit auth to %s\n",
895                                     ntoa(&(server->srcadr)));
896                         return;
897                 }
898
899                 if (debug > 1)
900                         printf("transmit auth to %s\n",
901                             ntoa(&(server->srcadr)));
902         } else {
903                 get_systime(&(server->xmt));
904                 HTONL_FP(&server->xmt, &xpkt.xmt);
905                 if (sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC)) {
906                         if (debug > 1)
907                                 printf("failed transmit to %s\n", 
908                                     ntoa(&(server->srcadr)));
909                         return;
910                 }
911
912                 if (debug > 1)
913                         printf("transmit to %s\n", ntoa(&(server->srcadr)));
914         }
915
916         /*
917          * count transmits, record contacted count and set transmit time
918          */
919         if (++server->xmtcnt == MINTRANSMITS)
920             contacted++;
921         server->last_xmit = current_time;
922
923         /*
924          * determine timeout for this packet. The more packets we send
925          * to the host, the slower we get. If the host indicates that
926          * it is not "sane" then we expect even less.
927          */
928         if (server->xmtcnt < MINTRANSMITS) {
929             /* we have not sent enough */
930             timeout = TIMER_HZ;         /* 1 second probe */
931         }
932         else if (server->rcvcnt <= 0) {
933             /* we have heard nothing */
934             if (secondhalf)
935                 timeout = TIMER_HZ<<4;  /* 16 second probe */
936             else
937                 timeout = TIMER_HZ<<3;  /* 8 second probe */
938         }
939         else {
940             /* if we have low dispersion then probe infrequently */
941             if (server->dispersion <= DESIREDDISP)
942                 timeout = TIMER_HZ<<4;  /* 16 second probe */
943             /* if the server is not in sync then let it alone */
944             else if (server->leap == LEAP_NOTINSYNC)
945                 timeout = TIMER_HZ<<4;  /* 16 second probe */
946             /* if the server looks broken ignore it */
947             else if (server->org.l_ui < server->reftime.l_ui)
948                 timeout = TIMER_HZ<<5;  /* 32 second probe */
949             else if (secondhalf)
950                 timeout = TIMER_HZ<<2;  /* 4 second probe */
951             else
952                 timeout = TIMER_HZ<<1;  /* 2 second probe */
953         }
954
955         /*
956          * set next transmit time based on timeout
957          */
958         server->event_time = current_time + timeout;
959 }
960
961
962 /*
963  * receive - receive and process an incoming frame
964  */
965 static void
966 receive(
967         struct recvbuf *rbufp
968         )
969 {
970         register struct pkt *rpkt;
971         register struct server *server;
972         register s_fp di;
973         l_fp t10, t23;
974         l_fp org;
975         l_fp rec;
976         l_fp ci;
977         int has_mac;
978         int is_authentic;
979
980         if (debug > 2)
981                 printf("receive(%s)\n", ntoa(&rbufp->srcadr));
982         /*
983          * Check to see if the packet basically looks like something
984          * intended for us.
985          */
986         if (rbufp->recv_length == LEN_PKT_NOMAC)
987                 has_mac = 0;
988         else if (rbufp->recv_length >= LEN_PKT_NOMAC)
989                 has_mac = 1;
990         else {
991                 if (debug > 2)
992                         printf("receive: packet length %d\n",
993                             rbufp->recv_length);
994                 return;         /* funny length packet */
995         }
996
997         rpkt = &(rbufp->recv_pkt);
998         if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
999             PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
1000                 if (debug > 1)
1001                         printf("receive: bad version %d\n",
1002                                PKT_VERSION(rpkt->li_vn_mode));
1003                 return;
1004         }
1005
1006         if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
1007             && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
1008             || rpkt->stratum >=STRATUM_UNSPEC) {
1009                 if (debug > 1)
1010                         printf("receive: mode %d stratum %d\n",
1011                             PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
1012                 return;
1013         }
1014         
1015         /*
1016          * So far, so good.  See if this is from a server we know.
1017          */
1018         server = findserver(&(rbufp->srcadr));
1019         if (server == NULL) {
1020                 if (debug > 1)
1021                         printf("receive: server not found\n");
1022                 return;
1023         }
1024
1025         /*
1026          * Decode the org timestamp and make sure we're getting a response
1027          * to our last request.
1028          */
1029         NTOHL_FP(&rpkt->org, &org);
1030         if (!L_ISEQU(&org, &server->xmt)) {
1031                 if (debug > 1)
1032                         printf("receive: pkt.org and peer.xmt differ\n");
1033                 return;
1034         }
1035         
1036         /*
1037          * Check out the authenticity if we're doing that.
1038          */
1039         if (!sys_authenticate)
1040                 is_authentic = 1;
1041         else {
1042                 is_authentic = 0;
1043
1044                 if (debug > 3)
1045                         printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n",
1046                            (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey,
1047                            (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt,
1048                                 LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC)));
1049
1050                 if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey &&
1051                         authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC,
1052                         (int)(rbufp->recv_length - LEN_PKT_NOMAC)))
1053                         is_authentic = 1;
1054                 if (debug)
1055                         printf("receive: authentication %s\n",
1056                            is_authentic ? "passed" : "failed");
1057         }
1058         server->trust <<= 1;
1059         if (!is_authentic)
1060                 server->trust |= 1;
1061         
1062         /*
1063          * Looks good.  Record info from the packet.
1064          */
1065         server->leap = PKT_LEAP(rpkt->li_vn_mode);
1066         server->stratum = PKT_TO_STRATUM(rpkt->stratum);
1067         server->precision = rpkt->precision;
1068         server->rootdelay = ntohl(rpkt->rootdelay);
1069         server->rootdispersion = ntohl(rpkt->rootdispersion);
1070         server->refid = rpkt->refid;
1071         NTOHL_FP(&rpkt->reftime, &server->reftime);
1072         NTOHL_FP(&rpkt->rec, &rec);
1073         NTOHL_FP(&rpkt->xmt, &server->org);
1074
1075         /*
1076          * count this guy as responding
1077          */
1078         server->reach |= 1;
1079         if (server->rcvcnt++ == 0)
1080                 responding++;
1081
1082         /*
1083          * Make sure the server is at least somewhat sane.  If not, ignore
1084          * it for later.
1085          */
1086         if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
1087                 if (debug > 1)
1088                         printf("receive: pkt insane\n");
1089                 return;
1090         }
1091
1092         /*
1093          * Calculate the round trip delay (di) and the clock offset (ci).
1094          * We use the equations (reordered from those in the spec):
1095          *
1096          * d = (t2 - t3) - (t1 - t0)
1097          * c = ((t2 - t3) + (t1 - t0)) / 2
1098          */
1099         t10 = server->org;              /* pkt.xmt == t1 */
1100         L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
1101
1102         t23 = rec;                      /* pkt.rec == t2 */
1103         L_SUB(&t23, &org);              /* pkt->org == t3 */
1104
1105         /* now have (t2 - t3) and (t0 - t1).  Calculate (ci) and (di) */
1106         ci = t10;
1107         L_ADD(&ci, &t23);
1108         L_RSHIFT(&ci);
1109
1110         /*
1111          * Calculate di in t23 in full precision, then truncate
1112          * to an s_fp.
1113          */
1114         L_SUB(&t23, &t10);
1115         di = LFPTOFP(&t23);
1116
1117         if (debug > 3)
1118                 printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5));
1119
1120         di += (FP_SECOND >> (-(int)NTPDATE_PRECISION))
1121             + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW;
1122
1123         if (di <= 0) {          /* value still too raunchy to use? */
1124                 L_CLR(&ci);
1125                 di = 0;
1126         } else {
1127                 di = max(di, NTP_MINDIST);
1128         }
1129
1130
1131         /*
1132          * This one is valid.  Give it to clock_filter(),
1133          */
1134         clock_filter(server, di, &ci);
1135         if (debug > 1)
1136                 printf("receive from %s\n", ntoa(&rbufp->srcadr));
1137
1138         /*
1139          * See if we should goes the transmission. If not return now
1140          * otherwise have the next event time be shortened
1141          */
1142         if (server->stratum <= NTP_INFIN)
1143             return;     /* server does not have a stratum */
1144         if (server->leap == LEAP_NOTINSYNC)
1145             return;     /* just booted server or out of sync */
1146         if (!L_ISHIS(&server->org, &server->reftime))
1147             return;     /* broken host */
1148         if (server->trust != 0)
1149             return;     /* can not trust it */
1150
1151         if (server->dispersion < DESIREDDISP)
1152             return;     /* we have the desired dispersion */
1153
1154         server->event_time -= (TIMER_HZ+1);
1155 }
1156
1157
1158 /*
1159  * clock_filter - add clock sample, determine a server's delay, dispersion
1160  *                and offset
1161  */
1162 static void
1163 clock_filter(
1164         register struct server *server,
1165         s_fp di,
1166         l_fp *c
1167         )
1168 {
1169         register int i, j;
1170         int ord[NTP_SHIFT];
1171
1172         /*
1173          * Insert sample and increment nextpt
1174          */
1175
1176         i = server->filter_nextpt;
1177         server->filter_delay[i] = di;
1178         server->filter_offset[i] = *c;
1179         server->filter_soffset[i] = LFPTOFP(c);
1180         server->filter_nextpt++;
1181         if (server->filter_nextpt >= NTP_SHIFT)
1182                 server->filter_nextpt = 0;
1183
1184         /*
1185          * Sort indices into increasing delay order
1186          */
1187         for (i = 0; i < NTP_SHIFT; i++)
1188                 ord[i] = i;
1189         
1190         for (i = 0; i < (NTP_SHIFT-1); i++) {
1191                 for (j = i+1; j < NTP_SHIFT; j++) {
1192                         if (server->filter_delay[ord[j]] == 0)
1193                                 continue;
1194                         if (server->filter_delay[ord[i]] == 0
1195                             || (server->filter_delay[ord[i]]
1196                             > server->filter_delay[ord[j]])) {
1197                                 register int tmp;
1198
1199                                 tmp = ord[i];
1200                                 ord[i] = ord[j];
1201                                 ord[j] = tmp;
1202                         }
1203                 }
1204         }
1205
1206         /*
1207          * Now compute the dispersion, and assign values to delay and
1208          * offset.  If there are no samples in the register, delay and
1209          * offset go to zero and dispersion is set to the maximum.
1210          */
1211         if (server->filter_delay[ord[0]] == 0) {
1212                 server->delay = 0;
1213                 L_CLR(&server->offset);
1214                 server->soffset = 0;
1215                 server->dispersion = PEER_MAXDISP;
1216         } else {
1217                 register s_fp d;
1218
1219                 server->delay = server->filter_delay[ord[0]];
1220                 server->offset = server->filter_offset[ord[0]];
1221                 server->soffset = LFPTOFP(&server->offset);
1222                 server->dispersion = 0;
1223                 for (i = 1; i < NTP_SHIFT; i++) {
1224                         if (server->filter_delay[ord[i]] == 0)
1225                                 d = PEER_MAXDISP;
1226                         else {
1227                                 d = server->filter_soffset[ord[i]]
1228                                     - server->filter_soffset[ord[0]];
1229                                 if (d < 0)
1230                                         d = -d;
1231                                 if (d > PEER_MAXDISP)
1232                                         d = PEER_MAXDISP;
1233                         }
1234                         /*
1235                          * XXX This *knows* PEER_FILTER is 1/2
1236                          */
1237                         server->dispersion += (u_fp)(d) >> i;
1238                 }
1239         }
1240         /*
1241          * We're done
1242          */
1243 }
1244
1245
1246 /* clock_count - count the clock sources we have
1247  */
1248 static void
1249 clock_count(void)
1250 {
1251         register struct server *server;
1252         register int n;
1253
1254         /* reset counts */
1255         validcount = valid_n_low = 0;
1256
1257         /* go through the list of servers and count the clocks we believe
1258          * and that have low dispersion
1259          */
1260         for (n = 0; n < sys_numservers; n++) {
1261                 server = sys_servers[n];
1262                 if (server->delay == 0) {
1263                         continue;       /* no data */
1264                 }
1265                 if (server->stratum > NTP_INFIN) {
1266                         continue;       /* stratum no good */
1267                 }
1268                 if (server->delay > NTP_MAXWGT) {
1269                         continue;       /* too far away */
1270                 }
1271                 if (server->leap == LEAP_NOTINSYNC)
1272                         continue;       /* he's in trouble */
1273                 if (!L_ISHIS(&server->org, &server->reftime)) {
1274                         continue;       /* very broken host */
1275                 }
1276                 if ((server->org.l_ui - server->reftime.l_ui) >= NTP_MAXAGE) {
1277                         continue;       /* too long without sync */
1278                 }
1279                 if (server->trust != 0) {
1280                         continue;
1281                 }
1282
1283                 /*
1284                  * This one is a valid time source..
1285                  */
1286                 validcount++;
1287
1288                 /*
1289                  * See if this one has a okay low dispersion
1290                  */
1291                 if (server->dispersion <= DESIREDDISP)
1292                     valid_n_low++;
1293         }
1294
1295         if (debug > 1)
1296                 printf("have %d, valid %d, low %d\n",
1297                         responding, validcount, valid_n_low);
1298 }
1299
1300
1301 /*
1302  * clock_select - select the pick-of-the-litter clock from the samples
1303  *                we've got.
1304  */
1305 static struct server *
1306 clock_select(void)
1307 {
1308         register struct server *server;
1309         register int i;
1310         register int nlist;
1311         register s_fp d;
1312         register int j;
1313         register int n;
1314         s_fp local_threshold;
1315         struct server *server_list[NTP_MAXCLOCK];
1316         u_fp server_badness[NTP_MAXCLOCK];
1317         struct server *sys_server;
1318
1319         /*
1320          * This first chunk of code is supposed to go through all
1321          * servers we know about to find the NTP_MAXLIST servers which
1322          * are most likely to succeed.  We run through the list
1323          * doing the sanity checks and trying to insert anyone who
1324          * looks okay.  We are at all times aware that we should
1325          * only keep samples from the top two strata and we only need
1326          * NTP_MAXLIST of them.
1327          */
1328         nlist = 0;      /* none yet */
1329         for (n = 0; n < sys_numservers; n++) {
1330                 server = sys_servers[n];
1331                 if (server->delay == 0)
1332                         continue;       /* no data */
1333                 if (server->stratum > NTP_INFIN)
1334                         continue;       /* stratum no good */
1335                 if (server->delay > NTP_MAXWGT) {
1336                         continue;       /* too far away */
1337                 }
1338                 if (server->leap == LEAP_NOTINSYNC)
1339                         continue;       /* he's in trouble */
1340                 if (!L_ISHIS(&server->org, &server->reftime)) {
1341                         continue;       /* very broken host */
1342                 }
1343                 if ((server->org.l_ui - server->reftime.l_ui)
1344                     >= NTP_MAXAGE) {
1345                         continue;       /* too long without sync */
1346                 }
1347                 if (server->trust != 0) {
1348                         continue;
1349                 }
1350
1351                 /*
1352                  * This one seems sane.  Find where he belongs
1353                  * on the list.
1354                  */
1355                 d = server->dispersion + server->dispersion;
1356                 for (i = 0; i < nlist; i++)
1357                         if (server->stratum <= server_list[i]->stratum)
1358                                 break;
1359                 for ( ; i < nlist; i++) {
1360                         if (server->stratum < server_list[i]->stratum)
1361                                 break;
1362                         if (d < (s_fp) server_badness[i])
1363                                 break;
1364                 }
1365
1366                 /*
1367                  * If i points past the end of the list, this
1368                  * guy is a loser, else stick him in.
1369                  */
1370                 if (i >= NTP_MAXLIST)
1371                         continue;
1372                 for (j = nlist; j > i; j--)
1373                         if (j < NTP_MAXLIST) {
1374                                 server_list[j] = server_list[j-1];
1375                                 server_badness[j]
1376                                     = server_badness[j-1];
1377                         }
1378
1379                 server_list[i] = server;
1380                 server_badness[i] = d;
1381                 if (nlist < NTP_MAXLIST)
1382                         nlist++;
1383         }
1384
1385         /*
1386          * Got the five-or-less best.  Cut the list where the number of
1387          * strata exceeds two.
1388          */
1389         j = 0;
1390         for (i = 1; i < nlist; i++)
1391                 if (server_list[i]->stratum > server_list[i-1]->stratum)
1392                         if (++j == 2) {
1393                                 nlist = i;
1394                                 break;
1395                         }
1396
1397         /*
1398          * Whew!  What we should have by now is 0 to 5 candidates for
1399          * the job of syncing us.  If we have none, we're out of luck.
1400          * If we have one, he's a winner.  If we have more, do falseticker
1401          * detection.
1402          */
1403
1404         if (nlist == 0)
1405                 sys_server = 0;
1406         else if (nlist == 1) {
1407                 sys_server = server_list[0];
1408         } else {
1409                 /*
1410                  * Re-sort by stratum, bdelay estimate quality and
1411                  * server.delay.
1412                  */
1413                 for (i = 0; i < nlist-1; i++)
1414                         for (j = i+1; j < nlist; j++) {
1415                                 if (server_list[i]->stratum
1416                                     < server_list[j]->stratum)
1417                                         break;  /* already sorted by stratum */
1418                                 if (server_list[i]->delay
1419                                     < server_list[j]->delay)
1420                                         continue;
1421                                 server = server_list[i];
1422                                 server_list[i] = server_list[j];
1423                                 server_list[j] = server;
1424                         }
1425                 
1426                 /*
1427                  * Calculate the fixed part of the dispersion limit
1428                  */
1429                 local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION))
1430                     + NTP_MAXSKW;
1431
1432                 /*
1433                  * Now drop samples until we're down to one.
1434                  */
1435                 while (nlist > 1) {
1436                         for (n = 0; n < nlist; n++) {
1437                                 server_badness[n] = 0;
1438                                 for (j = 0; j < nlist; j++) {
1439                                         if (j == n)     /* with self? */
1440                                                 continue;
1441                                         d = server_list[j]->soffset
1442                                             - server_list[n]->soffset;
1443                                         if (d < 0)      /* absolute value */
1444                                                 d = -d;
1445                                         /*
1446                                          * XXX This code *knows* that
1447                                          * NTP_SELECT is 3/4
1448                                          */
1449                                         for (i = 0; i < j; i++)
1450                                                 d = (d>>1) + (d>>2);
1451                                         server_badness[n] += d;
1452                                 }
1453                         }
1454
1455                         /*
1456                          * We now have an array of nlist badness
1457                          * coefficients.  Find the badest.  Find
1458                          * the minimum precision while we're at
1459                          * it.
1460                          */
1461                         i = 0;
1462                         n = server_list[0]->precision;;
1463                         for (j = 1; j < nlist; j++) {
1464                                 if (server_badness[j] >= server_badness[i])
1465                                         i = j;
1466                                 if (n > server_list[j]->precision)
1467                                         n = server_list[j]->precision;
1468                         }
1469                         
1470                         /*
1471                          * i is the index of the server with the worst
1472                          * dispersion.  If his dispersion is less than
1473                          * the threshold, stop now, else delete him and
1474                          * continue around again.
1475                          */
1476                         if (server_badness[i] < (local_threshold
1477                                                  + (FP_SECOND >> (-n))))
1478                                 break;
1479                         for (j = i + 1; j < nlist; j++)
1480                                 server_list[j-1] = server_list[j];
1481                         nlist--;
1482                 }
1483
1484                 /*
1485                  * What remains is a list of less than 5 servers.  Take
1486                  * the best.
1487                  */
1488                 sys_server = server_list[0];
1489         }
1490
1491         /*
1492          * That's it.  Return our server.
1493          */
1494         return sys_server;
1495 }
1496
1497
1498 /*
1499  * set_local_clock -- handle setting the local clock or displaying info.
1500  */
1501 static void
1502 set_local_clock(void)
1503 {
1504         register int i;
1505         register struct server *server;
1506         time_t tmp;
1507         double dtemp;
1508
1509         /*
1510          * if setting time then print final analysis
1511          */
1512         if (set_time)
1513             analysis(1);
1514
1515         /*
1516          * pick a clock
1517          */
1518         server = clock_select();
1519
1520         /*
1521          * do some display of information
1522          */
1523         if (debug || verbose) {
1524                 for (i = 0; i < sys_numservers; i++)
1525                         printserver(sys_servers[i], stdout);
1526                 if (debug)
1527                         printf("packets sent %ld, received %ld\n",
1528                                 total_xmit, total_recv);
1529         }
1530
1531         /*
1532          * see if we have a server to set the time with
1533          */
1534         if (server == 0) {
1535             if (!set_time || verbose)
1536                 fprintf(stdout,"No servers available to sync time with\n");
1537             exit(1);
1538         }
1539
1540         /*
1541          * we have a valid and selected time to use!!!!!
1542          */
1543
1544         /*
1545          * if we are not setting the time then display offset and exit
1546          */
1547         if (!set_time) {
1548                 fprintf(stdout,
1549                         "Your clock is off by %s seconds. (%s) [%ld/%ld]\n",
1550                         lfptoa(&server->offset, 7),
1551                         ntoa(&server->srcadr),
1552                         total_xmit, total_recv);
1553                 exit(0);
1554         }
1555
1556         /*
1557          * set the clock
1558          * XXX: Examine the more flexible approach used by ntpdate.
1559          * Note that a design consideration here is that we sometimes
1560          * _want_ to step the clock by a _huge_ amount in either
1561          * direction, because the local clock is completely bogus.
1562          * This condition must be recognized and dealt with, so
1563          * that we always get a good time when this completes.
1564          * -- jhutz+@cmu.edu, 16-Aug-1999
1565          */
1566         LFPTOD(&server->offset, dtemp);
1567         step_systime(dtemp);
1568         time(&tmp);
1569         fprintf(stdout,"Time set to %.20s [%s %s %ld/%ld]\n",
1570                 ctime(&tmp)+4,
1571                 ntoa(&server->srcadr),
1572                 lfptoa(&server->offset, 7),
1573                 total_xmit, total_recv);
1574         exit(0);
1575 }
1576
1577
1578 /*
1579  * findserver - find a server in the list given its address
1580  */
1581 static struct server *
1582 findserver(
1583         struct sockaddr_in *addr
1584         )
1585 {
1586         register int i;
1587         register u_int32 netnum;
1588
1589         if (htons(addr->sin_port) != NTP_PORT)
1590                 return 0;
1591         netnum = addr->sin_addr.s_addr;
1592
1593         for (i = 0; i < sys_numservers; i++) {
1594                 if (netnum == sys_servers[i]->srcadr.sin_addr.s_addr)
1595                         return sys_servers[i];
1596         }
1597         return 0;
1598 }
1599
1600
1601 /*
1602  * timer - process a timer interrupt
1603  */
1604 static void
1605 timer(void)
1606 {
1607         register int k;
1608
1609         /*
1610          * Bump the current idea of the time
1611          */
1612         current_time++;
1613
1614         /*
1615          * see if we have reached half time
1616          */
1617         if (current_time >= half_time && !secondhalf) {
1618             secondhalf++;
1619             if (debug)
1620                 printf("\nSecond Half of Timeout!\n");
1621             printmsg++;
1622         }
1623
1624         /*
1625          * We only want to send a few packets per transmit interrupt
1626          * to throttle things
1627          */
1628         for(k = 0;k < MAXXMITCOUNT;k++) {
1629             register int i, oldi;
1630             register u_long oldxtime;
1631
1632             /*
1633              * We want to send a packet out for a server that has an
1634              * expired event time. However to be mellow about this, we only
1635              * use one expired event timer and to avoid starvation we use
1636              * the one with the oldest last transmit time.
1637              */
1638             oldi = -1;
1639             oldxtime = 0;
1640             for (i = 0; i < sys_numservers; i++) {
1641                 if (sys_servers[i]->event_time <= current_time) {
1642                     if (oldi < 0 || oldxtime > sys_servers[i]->last_xmit) {
1643                         oldxtime = sys_servers[i]->last_xmit;
1644                         oldi = i;
1645                     }
1646                 }
1647             }
1648             if (oldi >= 0)
1649                 transmit(sys_servers[oldi]);
1650             else
1651                 break;  /* no expired event */
1652         } /* end of transmit loop */
1653 }
1654
1655
1656 #ifndef SYS_WINNT
1657 /*
1658  * alarming - record the occurance of an alarm interrupt
1659  */
1660 static RETSIGTYPE
1661 alarming(
1662         int sig
1663         )
1664 #else
1665 void CALLBACK 
1666 alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
1667 #endif /* SYS_WINNT */
1668 {
1669         alarm_flag++;
1670 }
1671
1672
1673 /*
1674  * init_alarm - set up the timer interrupt
1675  */
1676 static void
1677 init_alarm(void)
1678 {
1679 #ifndef SYS_WINNT
1680 # ifndef HAVE_TIMER_SETTIME
1681         struct itimerval itimer;
1682 # else
1683         struct itimerspec ntpdate_itimer;
1684 # endif
1685 #else
1686         TIMECAPS tc;
1687         UINT wTimerRes, wTimerID;
1688 # endif /* SYS_WINNT */
1689 #if defined SYS_CYGWIN32 || defined SYS_WINNT
1690         HANDLE hToken;
1691         TOKEN_PRIVILEGES tkp;
1692         DWORD dwUser = 0;
1693 #endif /* SYS_WINNT */
1694
1695         alarm_flag = 0;
1696
1697 #ifndef SYS_WINNT
1698 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
1699         alarm_flag = 0;
1700         /* this code was put in as setitimer() is non existant this us the
1701          * POSIX "equivalents" setup - casey
1702          */
1703         /* ntpdate_timerid is global - so we can kill timer later */
1704         if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
1705 #  ifdef SYS_VXWORKS
1706                 ERROR
1707 #  else
1708                 -1
1709 #  endif
1710                 )
1711         {
1712                 fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
1713                 return;
1714         }
1715
1716         /*      TIMER_HZ = (5)
1717          * Set up the alarm interrupt.  The first comes 1/(2*TIMER_HZ)
1718          * seconds from now and they continue on every 1/TIMER_HZ seconds.
1719          */
1720         (void) signal_no_reset(SIGALRM, alarming);
1721         ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
1722         ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
1723         ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
1724         timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
1725 # else
1726         /*
1727          * Set up the alarm interrupt.  The first comes 1/(2*TIMER_HZ)
1728          * seconds from now and they continue on every 1/TIMER_HZ seconds.
1729          */
1730         (void) signal_no_reset(SIGALRM, alarming);
1731         itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
1732         itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
1733         itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
1734         setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
1735 # endif
1736 #if defined SYS_CYGWIN32
1737         /*
1738          * Get previleges needed for fiddling with the clock
1739          */
1740
1741         /* get the current process token handle */
1742         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
1743                 msyslog(LOG_ERR, "OpenProcessToken failed: %m");
1744                 exit(1);
1745         }
1746         /* get the LUID for system-time privilege. */
1747         LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
1748         tkp.PrivilegeCount = 1;  /* one privilege to set */
1749         tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1750         /* get set-time privilege for this process. */
1751         AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
1752         /* cannot test return value of AdjustTokenPrivileges. */
1753         if (GetLastError() != ERROR_SUCCESS)
1754                 msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
1755 #endif
1756 #else   /* SYS_WINNT */
1757         _tzset();
1758
1759         /*
1760          * Get previleges needed for fiddling with the clock
1761          */
1762
1763         /* get the current process token handle */
1764         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
1765                 msyslog(LOG_ERR, "OpenProcessToken failed: %m");
1766                 exit(1);
1767         }
1768         /* get the LUID for system-time privilege. */
1769         LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
1770         tkp.PrivilegeCount = 1;  /* one privilege to set */
1771         tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1772         /* get set-time privilege for this process. */
1773         AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
1774         /* cannot test return value of AdjustTokenPrivileges. */
1775         if (GetLastError() != ERROR_SUCCESS)
1776                 msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
1777
1778         /*
1779          * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
1780          * Under Win/NT, expiry of timer interval leads to invocation
1781          * of a callback function (on a different thread) rather than
1782          * generating an alarm signal
1783          */
1784
1785         /* determine max and min resolution supported */
1786         if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
1787                 msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
1788                 exit(1);
1789         }
1790         wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
1791         /* establish the minimum timer resolution that we'll use */
1792         timeBeginPeriod(wTimerRes);
1793
1794         /* start the timer event */
1795         wTimerID = timeSetEvent(
1796                 (UINT) (1000/TIMER_HZ),    /* Delay */
1797                 wTimerRes,                       /* Resolution */
1798                 (LPTIMECALLBACK) alarming, /* Callback function */
1799                 (DWORD) dwUser,          /* User data */
1800                 TIME_PERIODIC);          /* Event type (periodic) */
1801         if (wTimerID == 0) {
1802                 msyslog(LOG_ERR, "timeSetEvent failed: %m");
1803                 exit(1);
1804         }
1805 #endif /* SYS_WINNT */
1806 }
1807
1808
1809 /*
1810  * init_io - initialize I/O data and open socket
1811  */
1812 static void
1813 init_io(void)
1814 {
1815 #ifdef SYS_WINNT
1816         WORD wVersionRequested;
1817         WSADATA wsaData;
1818         init_transmitbuff();
1819 #endif /* SYS_WINNT */
1820
1821         /*
1822          * Init buffer free list and stat counters
1823          */
1824         init_recvbuff(sys_numservers + 2);
1825
1826 #if defined(HAVE_SIGNALED_IO)
1827         set_signal();
1828 #endif
1829
1830 #ifdef SYS_WINNT
1831         wVersionRequested = MAKEWORD(1,1);
1832         if (WSAStartup(wVersionRequested, &wsaData))
1833         {
1834                 msyslog(LOG_ERR, "No useable winsock.dll: %m");
1835                 exit(1);
1836         }
1837 #endif /* SYS_WINNT */
1838
1839         BLOCKIO();
1840
1841         /* create a datagram (UDP) socket */
1842         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1843                 msyslog(LOG_ERR, "socket() failed: %m");
1844                 exit(1);
1845                 /*NOTREACHED*/
1846         }
1847
1848         /*
1849          * bind the socket to the NTP port
1850          */
1851         if (!debug && set_time && !unpriv_port) {
1852                 struct sockaddr_in addr;
1853
1854                 memset((char *)&addr, 0, sizeof addr);
1855                 addr.sin_family = AF_INET;
1856                 addr.sin_port = htons(NTP_PORT);
1857                 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1858                 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1859 #ifndef SYS_WINNT
1860                         if (errno == EADDRINUSE)
1861 #else
1862                         if (WSAGetLastError() == WSAEADDRINUSE)
1863 #endif
1864                                 msyslog(LOG_ERR,
1865                                     "the NTP socket is in use, exiting");
1866                         else
1867                                 msyslog(LOG_ERR, "bind() fails: %m");
1868                         exit(1);
1869                 }
1870         }
1871
1872         FD_ZERO(&fdmask);
1873         FD_SET(fd, &fdmask);
1874
1875         /*
1876          * set non-blocking,
1877          */
1878
1879 #ifdef USE_FIONBIO
1880         /* in vxWorks we use FIONBIO, but the others are defined for old systems, so
1881          * all hell breaks loose if we leave them defined
1882          */
1883 #undef O_NONBLOCK
1884 #undef FNDELAY
1885 #undef O_NDELAY
1886 #endif
1887
1888 #if defined(O_NONBLOCK) /* POSIX */
1889         if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
1890         {
1891                 msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m");
1892                 exit(1);
1893                 /*NOTREACHED*/
1894         }
1895 #elif defined(FNDELAY)
1896         if (fcntl(fd, F_SETFL, FNDELAY) < 0)
1897         {
1898                 msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
1899                 exit(1);
1900                 /*NOTREACHED*/
1901         }
1902 #elif defined(O_NDELAY) /* generally the same as FNDELAY */
1903         if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
1904         {
1905                 msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m");
1906                 exit(1);
1907                 /*NOTREACHED*/
1908         }
1909 #elif defined(FIONBIO)
1910         if (
1911 # if defined(VMS)
1912                 (ioctl(fd,FIONBIO,&1) < 0)
1913 # elif defined(SYS_WINNT)
1914                 (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR)
1915 # else
1916                 (ioctl(fd,FIONBIO,&on) < 0)
1917 # endif
1918            )
1919         {
1920                 msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
1921                 exit(1);
1922                 /*NOTREACHED*/
1923         }
1924 #elif defined(FIOSNBIO)
1925         if (ioctl(fd,FIOSNBIO,&on) < 0)
1926         {
1927                 msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m");
1928                 exit(1);
1929                 /*NOTREACHED*/
1930         }
1931 #else
1932 # include "Bletch: Need non-blocking I/O!"
1933 #endif
1934
1935 #ifdef HAVE_SIGNALED_IO
1936         init_socket_sig(fd);
1937 #endif /* not HAVE_SIGNALED_IO */
1938
1939         UNBLOCKIO();
1940 }
1941
1942
1943 /*
1944  * sendpkt - send a packet to the specified destination
1945  */
1946 static int
1947 sendpkt(
1948         struct sockaddr_in *dest,
1949         struct pkt *pkt,
1950         int len
1951         )
1952 {
1953         int cc;
1954         static int horriblecnt = 0;
1955 #ifdef SYS_WINNT
1956         DWORD err;
1957 #endif /* SYS_WINNT */
1958
1959         total_xmit++;   /* count it */
1960
1961         if (horrible) {
1962             if (++horriblecnt > HORRIBLEOK) {
1963                 if (debug > 3)
1964                         printf("dropping send (%s)\n", ntoa(dest));
1965                 if (horriblecnt >= HORRIBLEOK+horrible)
1966                     horriblecnt = 0;
1967                 return 0;
1968             }
1969         }
1970
1971
1972         cc = sendto(fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest,
1973             sizeof(struct sockaddr_in));
1974 #ifndef SYS_WINNT
1975         if (cc == -1) {
1976                 if (errno != EWOULDBLOCK && errno != ENOBUFS)
1977 #else
1978         if (cc == SOCKET_ERROR) {
1979                 err = WSAGetLastError();
1980                 if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
1981 #endif /* SYS_WINNT */
1982                         msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
1983                 return -1;
1984         }
1985         return 0;
1986 }
1987
1988
1989 /*
1990  * input_handler - receive packets asynchronously
1991  */
1992 void
1993 input_handler(l_fp *xts)
1994 {
1995         register int n;
1996         register struct recvbuf *rb;
1997         struct timeval tvzero;
1998         int fromlen;
1999         fd_set fds;
2000         l_fp ts;
2001         ts = *xts; /* we ignore xts, but make the compiler happy */
2002
2003         /*
2004          * Do a poll to see if we have data
2005          */
2006         for (;;) {
2007                 fds = fdmask;
2008                 tvzero.tv_sec = tvzero.tv_usec = 0;
2009                 n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
2010
2011                 /*
2012                  * If nothing to do, just return.  If an error occurred,
2013                  * complain and return.  If we've got some, freeze a
2014                  * timestamp.
2015                  */
2016                 if (n == 0)
2017                         return;
2018                 else if (n == -1) {
2019                         if (errno != EINTR) {
2020                                 msyslog(LOG_ERR, "select() error: %m");
2021                         }
2022                         return;
2023                 }
2024                 get_systime(&ts);
2025
2026                 /*
2027                  * Get a buffer and read the frame.  If we
2028                  * haven't got a buffer, or this is received
2029                  * on the wild card socket, just dump the packet.
2030                  */
2031                 if (initializing || free_recvbuffs == 0) {
2032                         char buf[100];
2033
2034 #ifndef SYS_WINNT
2035                         (void) read(fd, buf, sizeof buf);
2036 #else
2037                         /* NT's _read does not operate on nonblocking sockets
2038                          * either recvfrom or ReadFile() has to be used here.
2039                          * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
2040                          * just to be different use recvfrom() here
2041                          */
2042                         recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
2043 #endif /* SYS_WINNT */
2044                         continue;
2045                 }
2046
2047                 rb = get_free_recv_buffer();
2048
2049                 fromlen = sizeof(struct sockaddr_in);
2050                 rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt,
2051                     sizeof(rb->recv_pkt), 0,
2052                     (struct sockaddr *)&rb->srcadr, &fromlen);
2053                 if (rb->recv_length == -1) {
2054                         freerecvbuf(rb);
2055                         continue;
2056                 }
2057
2058                 /*
2059                  * Got one.  Mark how and when it got here,
2060                  * put it on the full list.
2061                  */
2062                 rb->recv_time = ts;
2063                 add_full_recv_buffer(rb);
2064                 total_recv++;   /* count it */
2065         }
2066 }
2067
2068
2069 /* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
2070 /*
2071  * printserver - print detail information for a server
2072  */
2073 static void
2074 printserver(
2075         register struct server *pp,
2076         FILE *fp
2077         )
2078 {
2079         register int i;
2080         char junk[5];
2081         char *str;
2082
2083         if (!debug) {
2084             (void) fprintf(fp,
2085                 "%-15s %d/%d %03o v%d s%d offset %9s delay %s disp %s\n",
2086                 ntoa(&pp->srcadr),
2087                 pp->xmtcnt,pp->rcvcnt,pp->reach,
2088                 pp->version,pp->stratum,
2089                 lfptoa(&pp->offset, 6), ufptoa(pp->delay, 5),
2090                 ufptoa(pp->dispersion, 4));
2091             return;
2092         }
2093
2094         (void) fprintf(fp, "server %s, port %d\n",
2095                            ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port));
2096
2097         (void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
2098                            pp->stratum, pp->precision,
2099                            pp->leap & 0x2 ? '1' : '0',
2100                            pp->leap & 0x1 ? '1' : '0',
2101                            pp->trust);
2102
2103         if (pp->stratum == 1) {
2104                 junk[4] = 0;
2105                 memmove(junk, (char *)&pp->refid, 4);
2106                 str = junk;
2107         } else {
2108                 str = numtoa(pp->refid);
2109         }
2110         (void) fprintf(fp,
2111                            "refid [%s], delay %s, dispersion %s\n",
2112                            str, fptoa((s_fp)pp->delay, 5),
2113                            ufptoa(pp->dispersion, 5));
2114
2115         (void) fprintf(fp, "transmitted %d, received %d, reachable %03o\n",
2116             pp->xmtcnt, pp->rcvcnt, pp->reach);
2117
2118         (void) fprintf(fp, "reference time:    %s\n",
2119                            prettydate(&pp->reftime));
2120         (void) fprintf(fp, "originate timestamp: %s\n",
2121                            prettydate(&pp->org));
2122         (void) fprintf(fp, "transmit timestamp:  %s\n",
2123                            prettydate(&pp->xmt));
2124
2125         (void) fprintf(fp, "filter delay: ");
2126         for (i = 0; i < NTP_SHIFT; i++) {
2127                 (void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
2128                 if (i == (NTP_SHIFT>>1)-1)
2129                         (void) fprintf(fp, "\n        ");
2130         }
2131         (void) fprintf(fp, "\n");
2132
2133         (void) fprintf(fp, "filter offset:");
2134         for (i = 0; i < PEER_SHIFT; i++) {
2135                 (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
2136                 if (i == (PEER_SHIFT>>1)-1)
2137                         (void) fprintf(fp, "\n        ");
2138         }
2139         (void) fprintf(fp, "\n");
2140
2141         (void) fprintf(fp, "delay %s, dispersion %s\n",
2142                            fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
2143
2144         (void) fprintf(fp, "offset %s\n\n",
2145                            lfptoa(&pp->offset, 6));
2146 }
2147
2148 #if !defined(HAVE_VSPRINTF)
2149 int
2150 vsprintf(
2151         char *str,
2152         const char *fmt,
2153         va_list ap
2154         )
2155 {
2156         FILE f;
2157         int len;
2158
2159         f._flag = _IOWRT+_IOSTRG;
2160         f._ptr = str;
2161         f._cnt = 32767;
2162         len = _doprnt(fmt, ap, &f);
2163         *f._ptr = 0;
2164         return (len);
2165 }
2166 #endif