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