]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/ntp/sntp/main.c
Fix multiple vulnerabilities in ntp. [SA-18:02.ntp]
[FreeBSD/releng/10.3.git] / contrib / ntp / sntp / main.c
1 #include <config.h>
2
3 #include <event2/util.h>
4 #include <event2/event.h>
5
6 #include "ntp_workimpl.h"
7 #ifdef WORK_THREAD
8 # include <event2/thread.h>
9 #endif
10
11 #include "main.h"
12 #include "ntp_libopts.h"
13 #include "kod_management.h"
14 #include "networking.h"
15 #include "utilities.h"
16 #include "log.h"
17 #include "libntp.h"
18
19
20 int shutting_down;
21 int time_derived;
22 int time_adjusted;
23 int n_pending_dns = 0;
24 int n_pending_ntp = 0;
25 int ai_fam_pref = AF_UNSPEC;
26 int ntpver = 4;
27 double steplimit = -1;
28 SOCKET sock4 = -1;              /* Socket for IPv4 */
29 SOCKET sock6 = -1;              /* Socket for IPv6 */
30 /*
31 ** BCAST *must* listen on port 123 (by default), so we can only
32 ** use the UCST sockets (above) if they too are using port 123
33 */
34 SOCKET bsock4 = -1;             /* Broadcast Socket for IPv4 */
35 SOCKET bsock6 = -1;             /* Broadcast Socket for IPv6 */
36 struct event_base *base;
37 struct event *ev_sock4;
38 struct event *ev_sock6;
39 struct event *ev_worker_timeout;
40 struct event *ev_xmt_timer;
41
42 struct dns_ctx {
43         const char *    name;
44         int             flags;
45 #define CTX_BCST        0x0001
46 #define CTX_UCST        0x0002
47 #define CTX_xCST        0x0003
48 #define CTX_CONC        0x0004
49 #define CTX_unused      0xfffd
50         int             key_id;
51         struct timeval  timeout;
52         struct key *    key;
53 };
54
55 typedef struct sent_pkt_tag sent_pkt;
56 struct sent_pkt_tag {
57         sent_pkt *              link;
58         struct dns_ctx *        dctx;
59         sockaddr_u              addr;
60         time_t                  stime;
61         int                     done;
62         struct pkt              x_pkt;
63 };
64
65 typedef struct xmt_ctx_tag xmt_ctx;
66 struct xmt_ctx_tag {
67         xmt_ctx *               link;
68         SOCKET                  sock;
69         time_t                  sched;
70         sent_pkt *              spkt;
71 };
72
73 struct timeval  gap;
74 xmt_ctx *       xmt_q;
75 struct key *    keys = NULL;
76 int             response_timeout;
77 struct timeval  response_tv;
78 struct timeval  start_tv;
79 /* check the timeout at least once per second */
80 struct timeval  wakeup_tv = { 0, 888888 };
81
82 sent_pkt *      fam_listheads[2];
83 #define v4_pkts_list    (fam_listheads[0])
84 #define v6_pkts_list    (fam_listheads[1])
85
86 static union {
87         struct pkt pkt;
88         char   buf[LEN_PKT_NOMAC + NTP_MAXEXTEN + MAX_MAC_LEN];
89 } rbuf;
90
91 #define r_pkt  rbuf.pkt
92
93 #ifdef HAVE_DROPROOT
94 int droproot;                   /* intres imports these */
95 int root_dropped;
96 #endif
97 u_long current_time;            /* libntp/authkeys.c */
98
99 void open_sockets(void);
100 void handle_lookup(const char *name, int flags);
101 void sntp_addremove_fd(int fd, int is_pipe, int remove_it);
102 void worker_timeout(evutil_socket_t, short, void *);
103 void worker_resp_cb(evutil_socket_t, short, void *);
104 void sntp_name_resolved(int, int, void *, const char *, const char *,
105                         const struct addrinfo *,
106                         const struct addrinfo *);
107 void queue_xmt(SOCKET sock, struct dns_ctx *dctx, sent_pkt *spkt,
108                u_int xmt_delay);
109 void xmt_timer_cb(evutil_socket_t, short, void *ptr);
110 void xmt(xmt_ctx *xctx);
111 int  check_kod(const struct addrinfo *ai);
112 void timeout_query(sent_pkt *);
113 void timeout_queries(void);
114 void sock_cb(evutil_socket_t, short, void *);
115 void check_exit_conditions(void);
116 void sntp_libevent_log_cb(int, const char *);
117 void set_li_vn_mode(struct pkt *spkt, char leap, char version, char mode);
118 int  set_time(double offset);
119 void dec_pending_ntp(const char *, sockaddr_u *);
120 int  libevent_version_ok(void);
121 int  gettimeofday_cached(struct event_base *b, struct timeval *tv);
122
123
124 /*
125  * The actual main function.
126  */
127 int
128 sntp_main (
129         int argc,
130         char **argv,
131         const char *sntpVersion
132         )
133 {
134         int                     i;
135         int                     exitcode;
136         int                     optct;
137         struct event_config *   evcfg;
138
139         /* Initialize logging system - sets up progname */
140         sntp_init_logging(argv[0]);
141
142         if (!libevent_version_ok())
143                 exit(EX_SOFTWARE);
144
145         init_lib();
146         init_auth();
147
148         optct = ntpOptionProcess(&sntpOptions, argc, argv);
149         argc -= optct;
150         argv += optct;
151
152
153         debug = OPT_VALUE_SET_DEBUG_LEVEL;
154
155         TRACE(2, ("init_lib() done, %s%s\n",
156                   (ipv4_works)
157                       ? "ipv4_works "
158                       : "",
159                   (ipv6_works)
160                       ? "ipv6_works "
161                       : ""));
162         ntpver = OPT_VALUE_NTPVERSION;
163         steplimit = OPT_VALUE_STEPLIMIT / 1e3;
164         gap.tv_usec = max(0, OPT_VALUE_GAP * 1000);
165         gap.tv_usec = min(gap.tv_usec, 999999);
166
167         if (HAVE_OPT(LOGFILE))
168                 open_logfile(OPT_ARG(LOGFILE));
169
170         msyslog(LOG_INFO, "%s", sntpVersion);
171
172         if (0 == argc && !HAVE_OPT(BROADCAST) && !HAVE_OPT(CONCURRENT)) {
173                 printf("%s: Must supply at least one of -b hostname, -c hostname, or hostname.\n",
174                        progname);
175                 exit(EX_USAGE);
176         }
177
178
179         /*
180         ** Eventually, we probably want:
181         ** - separate bcst and ucst timeouts (why?)
182         ** - multiple --timeout values in the commandline
183         */
184
185         response_timeout = OPT_VALUE_TIMEOUT;
186         response_tv.tv_sec = response_timeout;
187         response_tv.tv_usec = 0;
188
189         /* IPv6 available? */
190         if (isc_net_probeipv6() != ISC_R_SUCCESS) {
191                 ai_fam_pref = AF_INET;
192                 TRACE(1, ("No ipv6 support available, forcing ipv4\n"));
193         } else {
194                 /* Check for options -4 and -6 */
195                 if (HAVE_OPT(IPV4))
196                         ai_fam_pref = AF_INET;
197                 else if (HAVE_OPT(IPV6))
198                         ai_fam_pref = AF_INET6;
199         }
200
201         /* TODO: Parse config file if declared */
202
203         /*
204         ** Init the KOD system.
205         ** For embedded systems with no writable filesystem,
206         ** -K /dev/null can be used to disable KoD storage.
207         */
208         kod_init_kod_db(OPT_ARG(KOD), FALSE);
209
210         /* HMS: Check and see what happens if KEYFILE doesn't exist */
211         auth_init(OPT_ARG(KEYFILE), &keys);
212
213         /*
214         ** Considering employing a variable that prevents functions of doing
215         ** anything until everything is initialized properly
216         **
217         ** HMS: What exactly does the above mean?
218         */
219         event_set_log_callback(&sntp_libevent_log_cb);
220         if (debug > 0)
221                 event_enable_debug_mode();
222 #ifdef WORK_THREAD
223         evthread_use_pthreads();
224         /* we use libevent from main thread only, locks should be academic */
225         if (debug > 0)
226                 evthread_enable_lock_debuging();
227 #endif
228         evcfg = event_config_new();
229         if (NULL == evcfg) {
230                 printf("%s: event_config_new() failed!\n", progname);
231                 return -1;
232         }
233 #ifndef HAVE_SOCKETPAIR
234         event_config_require_features(evcfg, EV_FEATURE_FDS);
235 #endif
236         /* all libevent calls are from main thread */
237         /* event_config_set_flag(evcfg, EVENT_BASE_FLAG_NOLOCK); */
238         base = event_base_new_with_config(evcfg);
239         event_config_free(evcfg);
240         if (NULL == base) {
241                 printf("%s: event_base_new() failed!\n", progname);
242                 return -1;
243         }
244
245         /* wire into intres resolver */
246         worker_per_query = TRUE;
247         addremove_io_fd = &sntp_addremove_fd;
248
249         open_sockets();
250
251         if (HAVE_OPT(BROADCAST)) {
252                 int             cn = STACKCT_OPT(  BROADCAST );
253                 const char **   cp = STACKLST_OPT( BROADCAST );
254
255                 while (cn-- > 0) {
256                         handle_lookup(*cp, CTX_BCST);
257                         cp++;
258                 }
259         }
260
261         if (HAVE_OPT(CONCURRENT)) {
262                 int             cn = STACKCT_OPT( CONCURRENT );
263                 const char **   cp = STACKLST_OPT( CONCURRENT );
264
265                 while (cn-- > 0) {
266                         handle_lookup(*cp, CTX_UCST | CTX_CONC);
267                         cp++;
268                 }
269         }
270
271         for (i = 0; i < argc; ++i)
272                 handle_lookup(argv[i], CTX_UCST);
273
274         gettimeofday_cached(base, &start_tv);
275         event_base_dispatch(base);
276         event_base_free(base);
277
278         if (!time_adjusted &&
279             (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW)))
280                 exitcode = 1;
281         else
282                 exitcode = 0;
283
284         return exitcode;
285 }
286
287
288 /*
289 ** open sockets and make them non-blocking
290 */
291 void
292 open_sockets(
293         void
294         )
295 {
296         sockaddr_u      name;
297
298         if (-1 == sock4) {
299                 sock4 = socket(PF_INET, SOCK_DGRAM, 0);
300                 if (-1 == sock4) {
301                         /* error getting a socket */
302                         msyslog(LOG_ERR, "open_sockets: socket(PF_INET) failed: %m");
303                         exit(1);
304                 }
305                 /* Make it non-blocking */
306                 make_socket_nonblocking(sock4);
307
308                 /* Let's try using a wildcard... */
309                 ZERO(name);
310                 AF(&name) = AF_INET;
311                 SET_ADDR4N(&name, INADDR_ANY);
312                 SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0));
313
314                 if (-1 == bind(sock4, &name.sa,
315                                SOCKLEN(&name))) {
316                         msyslog(LOG_ERR, "open_sockets: bind(sock4) failed: %m");
317                         exit(1);
318                 }
319
320                 /* Register an NTP callback for recv/timeout */
321                 ev_sock4 = event_new(base, sock4,
322                                      EV_TIMEOUT | EV_READ | EV_PERSIST,
323                                      &sock_cb, NULL);
324                 if (NULL == ev_sock4) {
325                         msyslog(LOG_ERR,
326                                 "open_sockets: event_new(base, sock4) failed!");
327                 } else {
328                         event_add(ev_sock4, &wakeup_tv);
329                 }
330         }
331
332         /* We may not always have IPv6... */
333         if (-1 == sock6 && ipv6_works) {
334                 sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
335                 if (-1 == sock6 && ipv6_works) {
336                         /* error getting a socket */
337                         msyslog(LOG_ERR, "open_sockets: socket(PF_INET6) failed: %m");
338                         exit(1);
339                 }
340                 /* Make it non-blocking */
341                 make_socket_nonblocking(sock6);
342
343                 /* Let's try using a wildcard... */
344                 ZERO(name);
345                 AF(&name) = AF_INET6;
346                 SET_ADDR6N(&name, in6addr_any);
347                 SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0));
348
349                 if (-1 == bind(sock6, &name.sa,
350                                SOCKLEN(&name))) {
351                         msyslog(LOG_ERR, "open_sockets: bind(sock6) failed: %m");
352                         exit(1);
353                 }
354                 /* Register an NTP callback for recv/timeout */
355                 ev_sock6 = event_new(base, sock6,
356                                      EV_TIMEOUT | EV_READ | EV_PERSIST,
357                                      &sock_cb, NULL);
358                 if (NULL == ev_sock6) {
359                         msyslog(LOG_ERR,
360                                 "open_sockets: event_new(base, sock6) failed!");
361                 } else {
362                         event_add(ev_sock6, &wakeup_tv);
363                 }
364         }
365         
366         return;
367 }
368
369
370 /*
371 ** handle_lookup
372 */
373 void
374 handle_lookup(
375         const char *name,
376         int flags
377         )
378 {
379         struct addrinfo hints;  /* Local copy is OK */
380         struct dns_ctx *ctx;
381         char *          name_copy;
382         size_t          name_sz;
383         size_t          octets;
384
385         TRACE(1, ("handle_lookup(%s,%#x)\n", name, flags));
386
387         ZERO(hints);
388         hints.ai_family = ai_fam_pref;
389         hints.ai_flags = AI_CANONNAME | Z_AI_NUMERICSERV;
390         /*
391         ** Unless we specify a socktype, we'll get at least two
392         ** entries for each address: one for TCP and one for
393         ** UDP. That's not what we want.
394         */
395         hints.ai_socktype = SOCK_DGRAM;
396         hints.ai_protocol = IPPROTO_UDP;
397
398         name_sz = 1 + strlen(name);
399         octets = sizeof(*ctx) + name_sz;        // Space for a ctx and the name
400         ctx = emalloc_zero(octets);             // ctx at ctx[0]
401         name_copy = (char *)(ctx + 1);          // Put the name at ctx[1]
402         memcpy(name_copy, name, name_sz);       // copy the name to ctx[1]
403         ctx->name = name_copy;                  // point to it...
404         ctx->flags = flags;
405         ctx->timeout = response_tv;
406         ctx->key = NULL;
407
408         /* The following should arguably be passed in... */
409         if (ENABLED_OPT(AUTHENTICATION)) {
410                 ctx->key_id = OPT_VALUE_AUTHENTICATION;
411                 get_key(ctx->key_id, &ctx->key);
412                 if (NULL == ctx->key) {
413                         fprintf(stderr, "%s: Authentication with keyID %d requested, but no matching keyID found in <%s>!\n",
414                                 progname, ctx->key_id, OPT_ARG(KEYFILE));
415                         exit(1);
416                 }
417         } else {
418                 ctx->key_id = -1;
419         }
420
421         ++n_pending_dns;
422         getaddrinfo_sometime(name, "123", &hints, 0,
423                              &sntp_name_resolved, ctx);
424 }
425
426
427 /*
428 ** DNS Callback:
429 ** - For each IP:
430 ** - - open a socket
431 ** - - increment n_pending_ntp
432 ** - - send a request if this is a Unicast callback
433 ** - - queue wait for response
434 ** - decrement n_pending_dns
435 */
436 void
437 sntp_name_resolved(
438         int                     rescode,
439         int                     gai_errno,
440         void *                  context,
441         const char *            name,
442         const char *            service,
443         const struct addrinfo * hints,
444         const struct addrinfo * addr
445         )
446 {
447         struct dns_ctx *        dctx;
448         sent_pkt *              spkt;
449         const struct addrinfo * ai;
450         SOCKET                  sock;
451         u_int                   xmt_delay_v4;
452         u_int                   xmt_delay_v6;
453         u_int                   xmt_delay;
454         size_t                  octets;
455
456         xmt_delay_v4 = 0;
457         xmt_delay_v6 = 0;
458         dctx = context;
459         if (rescode) {
460 #ifdef EAI_SYSTEM
461                 if (EAI_SYSTEM == rescode) {
462                         errno = gai_errno;
463                         mfprintf(stderr, "%s lookup error %m\n",
464                                  dctx->name);
465                 } else
466 #endif
467                         fprintf(stderr, "%s lookup error %s\n",
468                                 dctx->name, gai_strerror(rescode));
469         } else {
470                 TRACE(3, ("%s [%s]\n", dctx->name,
471                           (addr->ai_canonname != NULL)
472                               ? addr->ai_canonname
473                               : ""));
474
475                 for (ai = addr; ai != NULL; ai = ai->ai_next) {
476
477                         if (check_kod(ai))
478                                 continue;
479
480                         switch (ai->ai_family) {
481
482                         case AF_INET:
483                                 sock = sock4;
484                                 xmt_delay = xmt_delay_v4;
485                                 xmt_delay_v4++;
486                                 break;
487
488                         case AF_INET6:
489                                 if (!ipv6_works)
490                                         continue;
491
492                                 sock = sock6;
493                                 xmt_delay = xmt_delay_v6;
494                                 xmt_delay_v6++;
495                                 break;
496
497                         default:
498                                 msyslog(LOG_ERR, "sntp_name_resolved: unexpected ai_family: %d",
499                                         ai->ai_family);
500                                 exit(1);
501                                 break;
502                         }
503
504                         /*
505                         ** We're waiting for a response for either unicast
506                         ** or broadcast, so...
507                         */
508                         ++n_pending_ntp;
509
510                         /* If this is for a unicast IP, queue a request */
511                         if (dctx->flags & CTX_UCST) {
512                                 spkt = emalloc_zero(sizeof(*spkt));
513                                 spkt->dctx = dctx;
514                                 octets = min(ai->ai_addrlen, sizeof(spkt->addr));
515                                 memcpy(&spkt->addr, ai->ai_addr, octets);
516                                 queue_xmt(sock, dctx, spkt, xmt_delay);
517                         }
518                 }
519         }
520         /* n_pending_dns really should be >0 here... */
521         --n_pending_dns;
522         check_exit_conditions();
523 }
524
525
526 /*
527 ** queue_xmt
528 */
529 void
530 queue_xmt(
531         SOCKET                  sock,
532         struct dns_ctx *        dctx,
533         sent_pkt *              spkt,
534         u_int                   xmt_delay
535         )
536 {
537         sockaddr_u *    dest;
538         sent_pkt **     pkt_listp;
539         sent_pkt *      match;
540         xmt_ctx *       xctx;
541         struct timeval  start_cb;
542         struct timeval  delay;
543
544         dest = &spkt->addr;
545         if (IS_IPV6(dest))
546                 pkt_listp = &v6_pkts_list;
547         else
548                 pkt_listp = &v4_pkts_list;
549
550         /* reject attempts to add address already listed */
551         for (match = *pkt_listp; match != NULL; match = match->link) {
552                 if (ADDR_PORT_EQ(&spkt->addr, &match->addr)) {
553                         if (strcasecmp(spkt->dctx->name,
554                                        match->dctx->name))
555                                 printf("%s %s duplicate address from %s ignored.\n",
556                                        sptoa(&match->addr),
557                                        match->dctx->name,
558                                        spkt->dctx->name);
559                         else
560                                 printf("%s %s, duplicate address ignored.\n",
561                                        sptoa(&match->addr),
562                                        match->dctx->name);
563                         dec_pending_ntp(spkt->dctx->name, &spkt->addr);
564                         free(spkt);
565                         return;
566                 }
567         }
568
569         LINK_SLIST(*pkt_listp, spkt, link);     
570
571         xctx = emalloc_zero(sizeof(*xctx));
572         xctx->sock = sock;
573         xctx->spkt = spkt;
574         gettimeofday_cached(base, &start_cb);
575         xctx->sched = start_cb.tv_sec + (2 * xmt_delay);
576
577         LINK_SORT_SLIST(xmt_q, xctx, (xctx->sched < L_S_S_CUR()->sched),
578                         link, xmt_ctx);
579         if (xmt_q == xctx) {
580                 /*
581                  * The new entry is the first scheduled.  The timer is
582                  * either not active or is set for the second xmt
583                  * context in xmt_q.
584                  */
585                 if (NULL == ev_xmt_timer)
586                         ev_xmt_timer = event_new(base, INVALID_SOCKET,
587                                                  EV_TIMEOUT,
588                                                  &xmt_timer_cb, NULL);
589                 if (NULL == ev_xmt_timer) {
590                         msyslog(LOG_ERR,
591                                 "queue_xmt: event_new(base, -1, EV_TIMEOUT) failed!");
592                         exit(1);
593                 }
594                 ZERO(delay);
595                 if (xctx->sched > start_cb.tv_sec)
596                         delay.tv_sec = xctx->sched - start_cb.tv_sec;
597                 event_add(ev_xmt_timer, &delay);
598                 TRACE(2, ("queue_xmt: xmt timer for %u usec\n",
599                           (u_int)delay.tv_usec));
600         }
601 }
602
603
604 /*
605 ** xmt_timer_cb
606 */
607 void
608 xmt_timer_cb(
609         evutil_socket_t fd,
610         short           what,
611         void *          ctx
612         )
613 {
614         struct timeval  start_cb;
615         struct timeval  delay;
616         xmt_ctx *       x;
617
618         UNUSED_ARG(fd);
619         UNUSED_ARG(ctx);
620         DEBUG_INSIST(EV_TIMEOUT == what);
621
622         if (NULL == xmt_q || shutting_down)
623                 return;
624         gettimeofday_cached(base, &start_cb);
625         if (xmt_q->sched <= start_cb.tv_sec) {
626                 UNLINK_HEAD_SLIST(x, xmt_q, link);
627                 TRACE(2, ("xmt_timer_cb: at .%6.6u -> %s\n",
628                           (u_int)start_cb.tv_usec, stoa(&x->spkt->addr)));
629                 xmt(x);
630                 free(x);
631                 if (NULL == xmt_q)
632                         return;
633         }
634         if (xmt_q->sched <= start_cb.tv_sec) {
635                 event_add(ev_xmt_timer, &gap);
636                 TRACE(2, ("xmt_timer_cb: at .%6.6u gap %6.6u\n",
637                           (u_int)start_cb.tv_usec,
638                           (u_int)gap.tv_usec));
639         } else {
640                 delay.tv_sec = xmt_q->sched - start_cb.tv_sec;
641                 delay.tv_usec = 0;
642                 event_add(ev_xmt_timer, &delay);
643                 TRACE(2, ("xmt_timer_cb: at .%6.6u next %ld seconds\n",
644                           (u_int)start_cb.tv_usec,
645                           (long)delay.tv_sec));
646         }
647 }
648
649
650 /*
651 ** xmt()
652 */
653 void
654 xmt(
655         xmt_ctx *       xctx
656         )
657 {
658         SOCKET          sock = xctx->sock;
659         struct dns_ctx *dctx = xctx->spkt->dctx;
660         sent_pkt *      spkt = xctx->spkt;
661         sockaddr_u *    dst = &spkt->addr;
662         struct timeval  tv_xmt;
663         struct pkt      x_pkt;
664         size_t          pkt_len;
665         int             sent;
666
667         if (0 != gettimeofday(&tv_xmt, NULL)) {
668                 msyslog(LOG_ERR,
669                         "xmt: gettimeofday() failed: %m");
670                 exit(1);
671         }
672         tv_xmt.tv_sec += JAN_1970;
673
674         pkt_len = generate_pkt(&x_pkt, &tv_xmt, dctx->key_id,
675                                dctx->key);
676
677         sent = sendpkt(sock, dst, &x_pkt, pkt_len);
678         if (sent) {
679                 /* Save the packet we sent... */
680                 memcpy(&spkt->x_pkt, &x_pkt, min(sizeof(spkt->x_pkt),
681                        pkt_len));
682                 spkt->stime = tv_xmt.tv_sec - JAN_1970;
683
684                 TRACE(2, ("xmt: %lx.%6.6u %s %s\n", (u_long)tv_xmt.tv_sec,
685                           (u_int)tv_xmt.tv_usec, dctx->name, stoa(dst)));
686         } else {
687                 dec_pending_ntp(dctx->name, dst);
688         }
689
690         return;
691 }
692
693
694 /*
695  * timeout_queries() -- give up on unrequited NTP queries
696  */
697 void
698 timeout_queries(void)
699 {
700         struct timeval  start_cb;
701         u_int           idx;
702         sent_pkt *      head;
703         sent_pkt *      spkt;
704         sent_pkt *      spkt_next;
705         long            age;
706         int didsomething = 0;
707
708         TRACE(3, ("timeout_queries: called to check %u items\n",
709                   (unsigned)COUNTOF(fam_listheads)));
710
711         gettimeofday_cached(base, &start_cb);
712         for (idx = 0; idx < COUNTOF(fam_listheads); idx++) {
713                 head = fam_listheads[idx];
714                 for (spkt = head; spkt != NULL; spkt = spkt_next) {
715                         char xcst;
716
717                         didsomething = 1;
718                         switch (spkt->dctx->flags & CTX_xCST) {
719                             case CTX_BCST:
720                                 xcst = 'B';
721                                 break;
722
723                             case CTX_UCST:
724                                 xcst = 'U';
725                                 break;
726
727                             default:
728                                 INSIST(!"spkt->dctx->flags neither UCST nor BCST");
729                                 break;
730                         }
731
732                         spkt_next = spkt->link;
733                         if (0 == spkt->stime || spkt->done)
734                                 continue;
735                         age = start_cb.tv_sec - spkt->stime;
736                         TRACE(3, ("%s %s %cCST age %ld\n",
737                                   stoa(&spkt->addr),
738                                   spkt->dctx->name, xcst, age));
739                         if (age > response_timeout)
740                                 timeout_query(spkt);
741                 }
742         }
743         // Do we care about didsomething?
744         TRACE(3, ("timeout_queries: didsomething is %d, age is %ld\n",
745                   didsomething, (long) (start_cb.tv_sec - start_tv.tv_sec)));
746         if (start_cb.tv_sec - start_tv.tv_sec > response_timeout) {
747                 TRACE(3, ("timeout_queries: bail!\n"));
748                 event_base_loopexit(base, NULL);
749                 shutting_down = TRUE;
750         }
751 }
752
753
754 void dec_pending_ntp(
755         const char *    name,
756         sockaddr_u *    server
757         )
758 {
759         if (n_pending_ntp > 0) {
760                 --n_pending_ntp;
761                 check_exit_conditions();
762         } else {
763                 INSIST(0 == n_pending_ntp);
764                 TRACE(1, ("n_pending_ntp was zero before decrement for %s\n",
765                           hostnameaddr(name, server)));
766         }
767 }
768
769
770 void timeout_query(
771         sent_pkt *      spkt
772         )
773 {
774         sockaddr_u *    server;
775         char            xcst;
776
777
778         switch (spkt->dctx->flags & CTX_xCST) {
779             case CTX_BCST:
780                 xcst = 'B';
781                 break;
782
783             case CTX_UCST:
784                 xcst = 'U';
785                 break;
786
787             default:
788                 INSIST(!"spkt->dctx->flags neither UCST nor BCST");
789                 break;
790         }
791         spkt->done = TRUE;
792         server = &spkt->addr;
793         msyslog(LOG_INFO, "%s no %cCST response after %d seconds",
794                 hostnameaddr(spkt->dctx->name, server), xcst,
795                 response_timeout);
796         dec_pending_ntp(spkt->dctx->name, server);
797         return;
798 }
799
800
801 /*
802 ** check_kod
803 */
804 int
805 check_kod(
806         const struct addrinfo * ai
807         )
808 {
809         char *hostname;
810         struct kod_entry *reason;
811
812         /* Is there a KoD on file for this address? */
813         hostname = addrinfo_to_str(ai);
814         TRACE(2, ("check_kod: checking <%s>\n", hostname));
815         if (search_entry(hostname, &reason)) {
816                 printf("prior KoD for %s, skipping.\n",
817                         hostname);
818                 free(reason);
819                 free(hostname);
820
821                 return 1;
822         }
823         free(hostname);
824
825         return 0;
826 }
827
828
829 /*
830 ** Socket readable/timeout Callback:
831 ** Read in the packet
832 ** Unicast:
833 ** - close socket
834 ** - decrement n_pending_ntp
835 ** - If packet is good, set the time and "exit"
836 ** Broadcast:
837 ** - If packet is good, set the time and "exit"
838 */
839 void
840 sock_cb(
841         evutil_socket_t fd,
842         short what,
843         void *ptr
844         )
845 {
846         sockaddr_u      sender;
847         sockaddr_u *    psau;
848         sent_pkt **     p_pktlist;
849         sent_pkt *      spkt;
850         int             rpktl;
851         int             rc;
852
853         INSIST(sock4 == fd || sock6 == fd);
854
855         TRACE(3, ("sock_cb: event on sock%s:%s%s%s%s\n",
856                   (fd == sock6)
857                       ? "6"
858                       : "4",
859                   (what & EV_TIMEOUT) ? " timeout" : "",
860                   (what & EV_READ)    ? " read" : "",
861                   (what & EV_WRITE)   ? " write" : "",
862                   (what & EV_SIGNAL)  ? " signal" : ""));
863
864         if (!(EV_READ & what)) {
865                 if (EV_TIMEOUT & what)
866                         timeout_queries();
867
868                 return;
869         }
870
871         /* Read in the packet */
872         rpktl = recvdata(fd, &sender, &rbuf, sizeof(rbuf));
873         if (rpktl < 0) {
874                 msyslog(LOG_DEBUG, "recvfrom error %m");
875                 return;
876         }
877
878         if (sock6 == fd)
879                 p_pktlist = &v6_pkts_list;
880         else
881                 p_pktlist = &v4_pkts_list;
882
883         for (spkt = *p_pktlist; spkt != NULL; spkt = spkt->link) {
884                 psau = &spkt->addr;
885                 if (SOCK_EQ(&sender, psau))
886                         break;
887         }
888         if (NULL == spkt) {
889                 msyslog(LOG_WARNING,
890                         "Packet from unexpected source %s dropped",
891                         sptoa(&sender));
892                 return;
893         }
894
895         TRACE(1, ("sock_cb: %s %s\n", spkt->dctx->name,
896                   sptoa(&sender)));
897
898         rpktl = process_pkt(&r_pkt, &sender, rpktl, MODE_SERVER,
899                             &spkt->x_pkt, "sock_cb");
900
901         TRACE(2, ("sock_cb: process_pkt returned %d\n", rpktl));
902
903         /* If this is a Unicast packet, one down ... */
904         if (!spkt->done && (CTX_UCST & spkt->dctx->flags)) {
905                 dec_pending_ntp(spkt->dctx->name, &spkt->addr);
906                 spkt->done = TRUE;
907         }
908
909
910         /* If the packet is good, set the time and we're all done */
911         rc = handle_pkt(rpktl, &r_pkt, &spkt->addr, spkt->dctx->name);
912         if (0 != rc)
913                 TRACE(1, ("sock_cb: handle_pkt() returned %d\n", rc));
914         check_exit_conditions();
915 }
916
917
918 /*
919  * check_exit_conditions()
920  *
921  * If sntp has a reply, ask the event loop to stop after this round of
922  * callbacks, unless --wait was used.
923  */
924 void
925 check_exit_conditions(void)
926 {
927         if ((0 == n_pending_ntp && 0 == n_pending_dns) ||
928             (time_derived && !HAVE_OPT(WAIT))) {
929                 event_base_loopexit(base, NULL);
930                 shutting_down = TRUE;
931         } else {
932                 TRACE(2, ("%d NTP and %d name queries pending\n",
933                           n_pending_ntp, n_pending_dns));
934         }
935 }
936
937
938 /*
939  * sntp_addremove_fd() is invoked by the intres blocking worker code
940  * to read from a pipe, or to stop same.
941  */
942 void sntp_addremove_fd(
943         int     fd,
944         int     is_pipe,
945         int     remove_it
946         )
947 {
948         u_int           idx;
949         blocking_child *c;
950         struct event *  ev;
951
952 #ifdef HAVE_SOCKETPAIR
953         if (is_pipe) {
954                 /* sntp only asks for EV_FEATURE_FDS without HAVE_SOCKETPAIR */
955                 msyslog(LOG_ERR, "fatal: pipes not supported on systems with socketpair()");
956                 exit(1);
957         }
958 #endif
959
960         c = NULL;
961         for (idx = 0; idx < blocking_children_alloc; idx++) {
962                 c = blocking_children[idx];
963                 if (NULL == c)
964                         continue;
965                 if (fd == c->resp_read_pipe)
966                         break;
967         }
968         if (idx == blocking_children_alloc)
969                 return;
970
971         if (remove_it) {
972                 ev = c->resp_read_ctx;
973                 c->resp_read_ctx = NULL;
974                 event_del(ev);
975                 event_free(ev);
976
977                 return;
978         }
979
980         ev = event_new(base, fd, EV_READ | EV_PERSIST,
981                        &worker_resp_cb, c);
982         if (NULL == ev) {
983                 msyslog(LOG_ERR,
984                         "sntp_addremove_fd: event_new(base, fd) failed!");
985                 return;
986         }
987         c->resp_read_ctx = ev;
988         event_add(ev, NULL);
989 }
990
991
992 /* called by forked intres child to close open descriptors */
993 #ifdef WORK_FORK
994 void
995 kill_asyncio(
996         int     startfd
997         )
998 {
999         if (INVALID_SOCKET != sock4) {
1000                 closesocket(sock4);
1001                 sock4 = INVALID_SOCKET;
1002         }
1003         if (INVALID_SOCKET != sock6) {
1004                 closesocket(sock6);
1005                 sock6 = INVALID_SOCKET;
1006         }
1007         if (INVALID_SOCKET != bsock4) {
1008                 closesocket(sock4);
1009                 sock4 = INVALID_SOCKET;
1010         }
1011         if (INVALID_SOCKET != bsock6) {
1012                 closesocket(sock6);
1013                 sock6 = INVALID_SOCKET;
1014         }
1015 }
1016 #endif
1017
1018
1019 /*
1020  * worker_resp_cb() is invoked when resp_read_pipe is readable.
1021  */
1022 void
1023 worker_resp_cb(
1024         evutil_socket_t fd,
1025         short           what,
1026         void *          ctx     /* blocking_child * */
1027         )
1028 {
1029         blocking_child *        c;
1030
1031         DEBUG_INSIST(EV_READ & what);
1032         c = ctx;
1033         DEBUG_INSIST(fd == c->resp_read_pipe);
1034         process_blocking_resp(c);
1035 }
1036
1037
1038 /*
1039  * intres_timeout_req(s) is invoked in the parent to schedule an idle
1040  * timeout to fire in s seconds, if not reset earlier by a call to
1041  * intres_timeout_req(0), which clears any pending timeout.  When the
1042  * timeout expires, worker_idle_timer_fired() is invoked (again, in the
1043  * parent).
1044  *
1045  * sntp and ntpd each provide implementations adapted to their timers.
1046  */
1047 void
1048 intres_timeout_req(
1049         u_int   seconds         /* 0 cancels */
1050         )
1051 {
1052         struct timeval  tv_to;
1053
1054         if (NULL == ev_worker_timeout) {
1055                 ev_worker_timeout = event_new(base, -1,
1056                                               EV_TIMEOUT | EV_PERSIST,
1057                                               &worker_timeout, NULL);
1058                 DEBUG_INSIST(NULL != ev_worker_timeout);
1059         } else {
1060                 event_del(ev_worker_timeout);
1061         }
1062         if (0 == seconds)
1063                 return;
1064         tv_to.tv_sec = seconds;
1065         tv_to.tv_usec = 0;
1066         event_add(ev_worker_timeout, &tv_to);
1067 }
1068
1069
1070 void
1071 worker_timeout(
1072         evutil_socket_t fd,
1073         short           what,
1074         void *          ctx
1075         )
1076 {
1077         UNUSED_ARG(fd);
1078         UNUSED_ARG(ctx);
1079
1080         DEBUG_REQUIRE(EV_TIMEOUT & what);
1081         worker_idle_timer_fired();
1082 }
1083
1084
1085 void
1086 sntp_libevent_log_cb(
1087         int             severity,
1088         const char *    msg
1089         )
1090 {
1091         int             level;
1092
1093         switch (severity) {
1094
1095         default:
1096         case _EVENT_LOG_DEBUG:
1097                 level = LOG_DEBUG;
1098                 break;
1099
1100         case _EVENT_LOG_MSG:
1101                 level = LOG_NOTICE;
1102                 break;
1103
1104         case _EVENT_LOG_WARN:
1105                 level = LOG_WARNING;
1106                 break;
1107
1108         case _EVENT_LOG_ERR:
1109                 level = LOG_ERR;
1110                 break;
1111         }
1112
1113         msyslog(level, "%s", msg);
1114 }
1115
1116
1117 int
1118 generate_pkt (
1119         struct pkt *x_pkt,
1120         const struct timeval *tv_xmt,
1121         int key_id,
1122         struct key *pkt_key
1123         )
1124 {
1125         l_fp    xmt_fp;
1126         int     pkt_len;
1127         int     mac_size;
1128
1129         pkt_len = LEN_PKT_NOMAC;
1130         ZERO(*x_pkt);
1131         TVTOTS(tv_xmt, &xmt_fp);
1132         HTONL_FP(&xmt_fp, &x_pkt->xmt);
1133         x_pkt->stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
1134         x_pkt->ppoll = 8;
1135         /* FIXME! Modus broadcast + adr. check -> bdr. pkt */
1136         set_li_vn_mode(x_pkt, LEAP_NOTINSYNC, ntpver, 3);
1137         if (debug > 0) {
1138                 printf("generate_pkt: key_id %d, key pointer %p\n", key_id, pkt_key);
1139         }
1140         if (pkt_key != NULL) {
1141                 x_pkt->exten[0] = htonl(key_id);
1142                 mac_size = make_mac(x_pkt, pkt_len, MAX_MDG_LEN,
1143                                     pkt_key, (char *)&x_pkt->exten[1]);
1144                 if (mac_size > 0)
1145                         pkt_len += mac_size + KEY_MAC_LEN;
1146 #ifdef DEBUG
1147                 if (debug > 0) {
1148                         printf("generate_pkt: mac_size is %d\n", mac_size);
1149                 }
1150 #endif
1151
1152         }
1153         return pkt_len;
1154 }
1155
1156
1157 int
1158 handle_pkt(
1159         int             rpktl,
1160         struct pkt *    rpkt,
1161         sockaddr_u *    host,
1162         const char *    hostname
1163         )
1164 {
1165         char            disptxt[32];
1166         const char *    addrtxt;
1167         struct timeval  tv_dst;
1168         int             cnt;
1169         int             sw_case;
1170         int             digits;
1171         int             stratum;
1172         char *          ref;
1173         char *          ts_str;
1174         const char *    leaptxt;
1175         double          offset;
1176         double          precision;
1177         double          synch_distance;
1178         char *          p_SNTP_PRETEND_TIME;
1179         time_t          pretend_time;
1180 #if SIZEOF_TIME_T == 8
1181         long long       ll;
1182 #else
1183         long            l;
1184 #endif
1185
1186         ts_str = NULL;
1187
1188         if (rpktl > 0)
1189                 sw_case = 1;
1190         else
1191                 sw_case = rpktl;
1192
1193         switch (sw_case) {
1194
1195         case SERVER_UNUSEABLE:
1196                 return -1;
1197                 break;
1198
1199         case PACKET_UNUSEABLE:
1200                 break;
1201
1202         case SERVER_AUTH_FAIL:
1203                 break;
1204
1205         case KOD_DEMOBILIZE:
1206                 /* Received a DENY or RESTR KOD packet */
1207                 addrtxt = stoa(host);
1208                 ref = (char *)&rpkt->refid;
1209                 add_entry(addrtxt, ref);
1210                 msyslog(LOG_WARNING, "KOD code %c%c%c%c from %s %s",
1211                         ref[0], ref[1], ref[2], ref[3], addrtxt, hostname);
1212                 break;
1213
1214         case KOD_RATE:
1215                 /*
1216                 ** Hmm...
1217                 ** We should probably call add_entry() with an
1218                 ** expiration timestamp of several seconds in the future,
1219                 ** and back-off even more if we get more RATE responses.
1220                 */
1221                 break;
1222
1223         case 1:
1224                 TRACE(3, ("handle_pkt: %d bytes from %s %s\n",
1225                           rpktl, stoa(host), hostname));
1226
1227                 gettimeofday_cached(base, &tv_dst);
1228
1229                 p_SNTP_PRETEND_TIME = getenv("SNTP_PRETEND_TIME");
1230                 if (p_SNTP_PRETEND_TIME) {
1231                         pretend_time = 0;
1232 #if SIZEOF_TIME_T == 4
1233                         if (1 == sscanf(p_SNTP_PRETEND_TIME, "%ld", &l))
1234                                 pretend_time = (time_t)l;
1235 #elif SIZEOF_TIME_T == 8
1236                         if (1 == sscanf(p_SNTP_PRETEND_TIME, "%lld", &ll))
1237                                 pretend_time = (time_t)ll;
1238 #else
1239 # include "GRONK: unexpected value for SIZEOF_TIME_T"
1240 #endif
1241                         if (0 != pretend_time)
1242                                 tv_dst.tv_sec = pretend_time;
1243                 }
1244
1245                 offset_calculation(rpkt, rpktl, &tv_dst, &offset,
1246                                    &precision, &synch_distance);
1247                 time_derived = TRUE;
1248
1249                 for (digits = 0; (precision *= 10.) < 1.; ++digits)
1250                         /* empty */ ;
1251                 if (digits > 6)
1252                         digits = 6;
1253
1254                 ts_str = tv_to_str(&tv_dst);
1255                 stratum = rpkt->stratum;
1256                 if (0 == stratum)
1257                                 stratum = 16;
1258
1259                 if (synch_distance > 0.) {
1260                         cnt = snprintf(disptxt, sizeof(disptxt),
1261                                        " +/- %f", synch_distance);
1262                         if ((size_t)cnt >= sizeof(disptxt))
1263                                 snprintf(disptxt, sizeof(disptxt),
1264                                          "ERROR %d >= %d", cnt,
1265                                          (int)sizeof(disptxt));
1266                 } else {
1267                         disptxt[0] = '\0';
1268                 }
1269
1270                 switch (PKT_LEAP(rpkt->li_vn_mode)) {
1271                     case LEAP_NOWARNING:
1272                         leaptxt = "no-leap";
1273                         break;
1274                     case LEAP_ADDSECOND:
1275                         leaptxt = "add-leap";
1276                         break;
1277                     case LEAP_DELSECOND:
1278                         leaptxt = "del-leap";
1279                         break;
1280                     case LEAP_NOTINSYNC:
1281                         leaptxt = "unsync";
1282                         break;
1283                     default:
1284                         leaptxt = "LEAP-ERROR";
1285                         break;
1286                 }
1287
1288                 msyslog(LOG_INFO, "%s %+.*f%s %s s%d %s%s", ts_str,
1289                         digits, offset, disptxt,
1290                         hostnameaddr(hostname, host), stratum,
1291                         leaptxt,
1292                         (time_adjusted)
1293                             ? " [excess]"
1294                             : "");
1295                 free(ts_str);
1296
1297                 if (p_SNTP_PRETEND_TIME)
1298                         return 0;
1299
1300                 if (!time_adjusted &&
1301                     (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW)))
1302                         return set_time(offset);
1303
1304                 return EX_OK;
1305         }
1306
1307         return 1;
1308 }
1309
1310
1311 void
1312 offset_calculation(
1313         struct pkt *rpkt,
1314         int rpktl,
1315         struct timeval *tv_dst,
1316         double *offset,
1317         double *precision,
1318         double *synch_distance
1319         )
1320 {
1321         l_fp p_rec, p_xmt, p_ref, p_org, tmp, dst;
1322         u_fp p_rdly, p_rdsp;
1323         double t21, t34, delta;
1324
1325         /* Convert timestamps from network to host byte order */
1326         p_rdly = NTOHS_FP(rpkt->rootdelay);
1327         p_rdsp = NTOHS_FP(rpkt->rootdisp);
1328         NTOHL_FP(&rpkt->reftime, &p_ref);
1329         NTOHL_FP(&rpkt->org, &p_org);
1330         NTOHL_FP(&rpkt->rec, &p_rec);
1331         NTOHL_FP(&rpkt->xmt, &p_xmt);
1332
1333         *precision = LOGTOD(rpkt->precision);
1334
1335         TRACE(3, ("offset_calculation: LOGTOD(rpkt->precision): %f\n", *precision));
1336
1337         /* Compute offset etc. */
1338         tmp = p_rec;
1339         L_SUB(&tmp, &p_org);
1340         LFPTOD(&tmp, t21);
1341         TVTOTS(tv_dst, &dst);
1342         dst.l_ui += JAN_1970;
1343         tmp = p_xmt;
1344         L_SUB(&tmp, &dst);
1345         LFPTOD(&tmp, t34);
1346         *offset = (t21 + t34) / 2.;
1347         delta = t21 - t34;
1348
1349         // synch_distance is:
1350         // (peer->delay + peer->rootdelay) / 2 + peer->disp
1351         // + peer->rootdisp + clock_phi * (current_time - peer->update)
1352         // + peer->jitter;
1353         //
1354         // and peer->delay = fabs(peer->offset - p_offset) * 2;
1355         // and peer->offset needs history, so we're left with
1356         // p_offset = (t21 + t34) / 2.;
1357         // peer->disp = 0; (we have no history to augment this)
1358         // clock_phi = 15e-6; 
1359         // peer->jitter = LOGTOD(sys_precision); (we have no history to augment this)
1360         // and ntp_proto.c:set_sys_tick_precision() should get us sys_precision.
1361         //
1362         // so our answer seems to be:
1363         //
1364         // (fabs(t21 + t34) + peer->rootdelay) / 3.
1365         // + 0 (peer->disp)
1366         // + peer->rootdisp
1367         // + 15e-6 (clock_phi)
1368         // + LOGTOD(sys_precision)
1369
1370         INSIST( FPTOD(p_rdly) >= 0. );
1371 #if 1
1372         *synch_distance = (fabs(t21 + t34) + FPTOD(p_rdly)) / 3.
1373                 + 0.
1374                 + FPTOD(p_rdsp)
1375                 + 15e-6
1376                 + 0.    /* LOGTOD(sys_precision) when we can get it */
1377                 ;
1378         INSIST( *synch_distance >= 0. );
1379 #else
1380         *synch_distance = (FPTOD(p_rdly) + FPTOD(p_rdsp))/2.0;
1381 #endif
1382
1383 #ifdef DEBUG
1384         if (debug > 3) {
1385                 printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
1386                 printf("sntp rootdisp: %f\n", FPTOD(p_rdsp));
1387                 printf("sntp syncdist: %f\n", *synch_distance);
1388
1389                 pkt_output(rpkt, rpktl, stdout);
1390
1391                 printf("sntp offset_calculation: rpkt->reftime:\n");
1392                 l_fp_output(&p_ref, stdout);
1393                 printf("sntp offset_calculation: rpkt->org:\n");
1394                 l_fp_output(&p_org, stdout);
1395                 printf("sntp offset_calculation: rpkt->rec:\n");
1396                 l_fp_output(&p_rec, stdout);
1397                 printf("sntp offset_calculation: rpkt->xmt:\n");
1398                 l_fp_output(&p_xmt, stdout);
1399         }
1400 #endif
1401
1402         TRACE(3, ("sntp offset_calculation:\trec - org t21: %.6f\n"
1403                   "\txmt - dst t34: %.6f\tdelta: %.6f\toffset: %.6f\n",
1404                   t21, t34, delta, *offset));
1405
1406         return;
1407 }
1408
1409
1410
1411 /* Compute the 8 bits for li_vn_mode */
1412 void
1413 set_li_vn_mode (
1414         struct pkt *spkt,
1415         char leap,
1416         char version,
1417         char mode
1418         )
1419 {
1420         if (leap > 3) {
1421                 msyslog(LOG_DEBUG, "set_li_vn_mode: leap > 3, using max. 3");
1422                 leap = 3;
1423         }
1424
1425         if ((unsigned char)version > 7) {
1426                 msyslog(LOG_DEBUG, "set_li_vn_mode: version < 0 or > 7, using 4");
1427                 version = 4;
1428         }
1429
1430         if (mode > 7) {
1431                 msyslog(LOG_DEBUG, "set_li_vn_mode: mode > 7, using client mode 3");
1432                 mode = 3;
1433         }
1434
1435         spkt->li_vn_mode  = leap << 6;
1436         spkt->li_vn_mode |= version << 3;
1437         spkt->li_vn_mode |= mode;
1438 }
1439
1440
1441 /*
1442 ** set_time applies 'offset' to the local clock.
1443 */
1444 int
1445 set_time(
1446         double offset
1447         )
1448 {
1449         int rc;
1450
1451         if (time_adjusted)
1452                 return EX_OK;
1453
1454         /*
1455         ** If we can step but we cannot slew, then step.
1456         ** If we can step or slew and and |offset| > steplimit, then step.
1457         */
1458         if (ENABLED_OPT(STEP) &&
1459             (   !ENABLED_OPT(SLEW)
1460              || (ENABLED_OPT(SLEW) && (fabs(offset) > steplimit))
1461             )) {
1462                 rc = step_systime(offset);
1463
1464                 /* If there was a problem, can we rely on errno? */
1465                 if (1 == rc)
1466                         time_adjusted = TRUE;
1467                 return (time_adjusted)
1468                            ? EX_OK 
1469                            : 1;
1470                 /*
1471                 ** In case of error, what should we use?
1472                 ** EX_UNAVAILABLE?
1473                 ** EX_OSERR?
1474                 ** EX_NOPERM?
1475                 */
1476         }
1477
1478         if (ENABLED_OPT(SLEW)) {
1479                 rc = adj_systime(offset);
1480
1481                 /* If there was a problem, can we rely on errno? */
1482                 if (1 == rc)
1483                         time_adjusted = TRUE;
1484                 return (time_adjusted)
1485                            ? EX_OK 
1486                            : 1;
1487                 /*
1488                 ** In case of error, what should we use?
1489                 ** EX_UNAVAILABLE?
1490                 ** EX_OSERR?
1491                 ** EX_NOPERM?
1492                 */
1493         }
1494
1495         return EX_SOFTWARE;
1496 }
1497
1498
1499 int
1500 libevent_version_ok(void)
1501 {
1502         ev_uint32_t v_compile_maj;
1503         ev_uint32_t v_run_maj;
1504
1505         v_compile_maj = LIBEVENT_VERSION_NUMBER & 0xffff0000;
1506         v_run_maj = event_get_version_number() & 0xffff0000;
1507         if (v_compile_maj != v_run_maj) {
1508                 fprintf(stderr,
1509                         "Incompatible libevent versions: have %s, built with %s\n",
1510                         event_get_version(),
1511                         LIBEVENT_VERSION);
1512                 return 0;
1513         }
1514         return 1;
1515 }
1516
1517 /*
1518  * gettimeofday_cached()
1519  *
1520  * Clones the event_base_gettimeofday_cached() interface but ensures the
1521  * times are always on the gettimeofday() 1970 scale.  Older libevent 2
1522  * sometimes used gettimeofday(), sometimes the since-system-start
1523  * clock_gettime(CLOCK_MONOTONIC), depending on the platform.
1524  *
1525  * It is not cleanly possible to tell which timescale older libevent is
1526  * using.
1527  *
1528  * The strategy involves 1 hour thresholds chosen to be far longer than
1529  * the duration of a round of libevent callbacks, which share a cached
1530  * start-of-round time.  First compare the last cached time with the
1531  * current gettimeofday() time.  If they are within one hour, libevent
1532  * is using the proper timescale so leave the offset 0.  Otherwise,
1533  * compare libevent's cached time and the current time on the monotonic
1534  * scale.  If they are within an hour, libevent is using the monotonic
1535  * scale so calculate the offset to add to such times to bring them to
1536  * gettimeofday()'s scale.
1537  */
1538 int
1539 gettimeofday_cached(
1540         struct event_base *     b,
1541         struct timeval *        caller_tv
1542         )
1543 {
1544 #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1545         static struct event_base *      cached_b;
1546         static struct timeval           cached;
1547         static struct timeval           adj_cached;
1548         static struct timeval           offset;
1549         static int                      offset_ready;
1550         struct timeval                  latest;
1551         struct timeval                  systemt;
1552         struct timespec                 ts;
1553         struct timeval                  mono;
1554         struct timeval                  diff;
1555         int                             cgt_rc;
1556         int                             gtod_rc;
1557
1558         event_base_gettimeofday_cached(b, &latest);
1559         if (b == cached_b &&
1560             !memcmp(&latest, &cached, sizeof(latest))) {
1561                 *caller_tv = adj_cached;
1562                 return 0;
1563         }
1564         cached = latest;
1565         cached_b = b;
1566         if (!offset_ready) {
1567                 cgt_rc = clock_gettime(CLOCK_MONOTONIC, &ts);
1568                 gtod_rc = gettimeofday(&systemt, NULL);
1569                 if (0 != gtod_rc) {
1570                         msyslog(LOG_ERR,
1571                                 "%s: gettimeofday() error %m",
1572                                 progname);
1573                         exit(1);
1574                 }
1575                 diff = sub_tval(systemt, latest);
1576                 if (debug > 1)
1577                         printf("system minus cached %+ld.%06ld\n",
1578                                (long)diff.tv_sec, (long)diff.tv_usec);
1579                 if (0 != cgt_rc || labs((long)diff.tv_sec) < 3600) {
1580                         /*
1581                          * Either use_monotonic == 0, or this libevent
1582                          * has been repaired.  Leave offset at zero.
1583                          */
1584                 } else {
1585                         mono.tv_sec = ts.tv_sec;
1586                         mono.tv_usec = ts.tv_nsec / 1000;
1587                         diff = sub_tval(latest, mono);
1588                         if (debug > 1)
1589                                 printf("cached minus monotonic %+ld.%06ld\n",
1590                                        (long)diff.tv_sec, (long)diff.tv_usec);
1591                         if (labs((long)diff.tv_sec) < 3600) {
1592                                 /* older libevent2 using monotonic */
1593                                 offset = sub_tval(systemt, mono);
1594                                 TRACE(1, ("%s: Offsetting libevent CLOCK_MONOTONIC times  by %+ld.%06ld\n",
1595                                          "gettimeofday_cached",
1596                                          (long)offset.tv_sec,
1597                                          (long)offset.tv_usec));
1598                         }
1599                 }
1600                 offset_ready = TRUE;
1601         }
1602         adj_cached = add_tval(cached, offset);
1603         *caller_tv = adj_cached;
1604
1605         return 0;
1606 #else
1607         return event_base_gettimeofday_cached(b, caller_tv);
1608 #endif
1609 }
1610