main.c revision 1.12 1 /* $NetBSD: main.c,v 1.12 2015/04/07 17:34:19 christos Exp $ */
2
3 #include <config.h>
4
5 #include <event2/util.h>
6 #include <event2/event.h>
7
8 #include "ntp_workimpl.h"
9 #ifdef WORK_THREAD
10 # include <event2/thread.h>
11 #endif
12
13 #include "main.h"
14 #include "ntp_libopts.h"
15 #include "kod_management.h"
16 #include "networking.h"
17 #include "utilities.h"
18 #include "log.h"
19 #include "libntp.h"
20
21
22 int shutting_down;
23 int time_derived;
24 int time_adjusted;
25 int n_pending_dns = 0;
26 int n_pending_ntp = 0;
27 int ai_fam_pref = AF_UNSPEC;
28 int ntpver = 4;
29 double steplimit = -1;
30 SOCKET sock4 = -1; /* Socket for IPv4 */
31 SOCKET sock6 = -1; /* Socket for IPv6 */
32 /*
33 ** BCAST *must* listen on port 123 (by default), so we can only
34 ** use the UCST sockets (above) if they too are using port 123
35 */
36 SOCKET bsock4 = -1; /* Broadcast Socket for IPv4 */
37 SOCKET bsock6 = -1; /* Broadcast Socket for IPv6 */
38 struct event_base *base;
39 struct event *ev_sock4;
40 struct event *ev_sock6;
41 struct event *ev_worker_timeout;
42 struct event *ev_xmt_timer;
43
44 struct dns_ctx {
45 const char * name;
46 int flags;
47 #define CTX_BCST 0x0001
48 #define CTX_UCST 0x0002
49 #define CTX_xCST 0x0003
50 #define CTX_CONC 0x0004
51 #define CTX_unused 0xfffd
52 int key_id;
53 struct timeval timeout;
54 struct key * key;
55 };
56
57 typedef struct sent_pkt_tag sent_pkt;
58 struct sent_pkt_tag {
59 sent_pkt * link;
60 struct dns_ctx * dctx;
61 sockaddr_u addr;
62 time_t stime;
63 int done;
64 struct pkt x_pkt;
65 };
66
67 typedef struct xmt_ctx_tag xmt_ctx;
68 struct xmt_ctx_tag {
69 xmt_ctx * link;
70 SOCKET sock;
71 time_t sched;
72 sent_pkt * spkt;
73 };
74
75 struct timeval gap;
76 xmt_ctx * xmt_q;
77 struct key * keys = NULL;
78 int response_timeout;
79 struct timeval response_tv;
80 struct timeval start_tv;
81 /* check the timeout at least once per second */
82 struct timeval wakeup_tv = { 0, 888888 };
83
84 sent_pkt * fam_listheads[2];
85 #define v4_pkts_list (fam_listheads[0])
86 #define v6_pkts_list (fam_listheads[1])
87
88 static union {
89 struct pkt pkt;
90 char buf[LEN_PKT_NOMAC + NTP_MAXEXTEN + MAX_MAC_LEN];
91 } rbuf;
92
93 #define r_pkt rbuf.pkt
94
95 #ifdef HAVE_DROPROOT
96 int droproot; /* intres imports these */
97 int root_dropped;
98 #endif
99 u_long current_time; /* libntp/authkeys.c */
100
101 void open_sockets(void);
102 void handle_lookup(const char *name, int flags);
103 void sntp_addremove_fd(int fd, int is_pipe, int remove_it);
104 void worker_timeout(evutil_socket_t, short, void *);
105 void worker_resp_cb(evutil_socket_t, short, void *);
106 void sntp_name_resolved(int, int, void *, const char *, const char *,
107 const struct addrinfo *,
108 const struct addrinfo *);
109 void queue_xmt(SOCKET sock, struct dns_ctx *dctx, sent_pkt *spkt,
110 u_int xmt_delay);
111 void xmt_timer_cb(evutil_socket_t, short, void *ptr);
112 void xmt(xmt_ctx *xctx);
113 int check_kod(const struct addrinfo *ai);
114 void timeout_query(sent_pkt *);
115 void timeout_queries(void);
116 void sock_cb(evutil_socket_t, short, void *);
117 void check_exit_conditions(void);
118 void sntp_libevent_log_cb(int, const char *);
119 void set_li_vn_mode(struct pkt *spkt, char leap, char version, char mode);
120 int set_time(double offset);
121 void dec_pending_ntp(const char *, sockaddr_u *);
122 int libevent_version_ok(void);
123 int gettimeofday_cached(struct event_base *b, struct timeval *tv);
124
125
126 /*
127 * The actual main function.
128 */
129 int
130 sntp_main (
131 int argc,
132 char **argv,
133 const char *sntpVersion
134 )
135 {
136 int i;
137 int exitcode;
138 int optct;
139 struct event_config * evcfg;
140
141 /* Initialize logging system - sets up progname */
142 sntp_init_logging(argv[0]);
143
144 if (!libevent_version_ok())
145 exit(EX_SOFTWARE);
146
147 init_lib();
148 init_auth();
149
150 optct = ntpOptionProcess(&sntpOptions, argc, argv);
151 argc -= optct;
152 argv += optct;
153
154
155 debug = OPT_VALUE_SET_DEBUG_LEVEL;
156
157 TRACE(2, ("init_lib() done, %s%s\n",
158 (ipv4_works)
159 ? "ipv4_works "
160 : "",
161 (ipv6_works)
162 ? "ipv6_works "
163 : ""));
164 ntpver = OPT_VALUE_NTPVERSION;
165 steplimit = OPT_VALUE_STEPLIMIT / 1e3;
166 gap.tv_usec = max(0, OPT_VALUE_GAP * 1000);
167 gap.tv_usec = min(gap.tv_usec, 999999);
168
169 if (HAVE_OPT(LOGFILE))
170 open_logfile(OPT_ARG(LOGFILE));
171
172 msyslog(LOG_INFO, "%s", sntpVersion);
173
174 if (0 == argc && !HAVE_OPT(BROADCAST) && !HAVE_OPT(CONCURRENT)) {
175 printf("%s: Must supply at least one of -b hostname, -c hostname, or hostname.\n",
176 progname);
177 exit(EX_USAGE);
178 }
179
180
181 /*
182 ** Eventually, we probably want:
183 ** - separate bcst and ucst timeouts (why?)
184 ** - multiple --timeout values in the commandline
185 */
186
187 response_timeout = OPT_VALUE_TIMEOUT;
188 response_tv.tv_sec = response_timeout;
189 response_tv.tv_usec = 0;
190
191 /* IPv6 available? */
192 if (isc_net_probeipv6() != ISC_R_SUCCESS) {
193 ai_fam_pref = AF_INET;
194 TRACE(1, ("No ipv6 support available, forcing ipv4\n"));
195 } else {
196 /* Check for options -4 and -6 */
197 if (HAVE_OPT(IPV4))
198 ai_fam_pref = AF_INET;
199 else if (HAVE_OPT(IPV6))
200 ai_fam_pref = AF_INET6;
201 }
202
203 /* TODO: Parse config file if declared */
204
205 /*
206 ** Init the KOD system.
207 ** For embedded systems with no writable filesystem,
208 ** -K /dev/null can be used to disable KoD storage.
209 */
210 kod_init_kod_db(OPT_ARG(KOD), FALSE);
211
212 // HMS: Should we use arg-defalt for this too?
213 if (HAVE_OPT(KEYFILE))
214 auth_init(OPT_ARG(KEYFILE), &keys);
215
216 /*
217 ** Considering employing a variable that prevents functions of doing
218 ** anything until everything is initialized properly
219 **
220 ** HMS: What exactly does the above mean?
221 */
222 event_set_log_callback(&sntp_libevent_log_cb);
223 if (debug > 0)
224 event_enable_debug_mode();
225 #ifdef WORK_THREAD
226 evthread_use_pthreads();
227 /* we use libevent from main thread only, locks should be academic */
228 if (debug > 0)
229 evthread_enable_lock_debuging();
230 #endif
231 evcfg = event_config_new();
232 if (NULL == evcfg) {
233 printf("%s: event_config_new() failed!\n", progname);
234 return -1;
235 }
236 #ifndef HAVE_SOCKETPAIR
237 event_config_require_features(evcfg, EV_FEATURE_FDS);
238 #endif
239 /* all libevent calls are from main thread */
240 /* event_config_set_flag(evcfg, EVENT_BASE_FLAG_NOLOCK); */
241 base = event_base_new_with_config(evcfg);
242 event_config_free(evcfg);
243 if (NULL == base) {
244 printf("%s: event_base_new() failed!\n", progname);
245 return -1;
246 }
247
248 /* wire into intres resolver */
249 worker_per_query = TRUE;
250 addremove_io_fd = &sntp_addremove_fd;
251
252 open_sockets();
253
254 if (HAVE_OPT(BROADCAST)) {
255 int cn = STACKCT_OPT( BROADCAST );
256 const char ** cp = STACKLST_OPT( BROADCAST );
257
258 while (cn-- > 0) {
259 handle_lookup(*cp, CTX_BCST);
260 cp++;
261 }
262 }
263
264 if (HAVE_OPT(CONCURRENT)) {
265 int cn = STACKCT_OPT( CONCURRENT );
266 const char ** cp = STACKLST_OPT( CONCURRENT );
267
268 while (cn-- > 0) {
269 handle_lookup(*cp, CTX_UCST | CTX_CONC);
270 cp++;
271 }
272 }
273
274 for (i = 0; i < argc; ++i)
275 handle_lookup(argv[i], CTX_UCST);
276
277 gettimeofday_cached(base, &start_tv);
278 event_base_dispatch(base);
279 event_base_free(base);
280
281 if (!time_adjusted &&
282 (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW)))
283 exitcode = 1;
284 else
285 exitcode = 0;
286
287 return exitcode;
288 }
289
290
291 /*
292 ** open sockets and make them non-blocking
293 */
294 void
295 open_sockets(
296 void
297 )
298 {
299 sockaddr_u name;
300
301 if (-1 == sock4) {
302 sock4 = socket(PF_INET, SOCK_DGRAM, 0);
303 if (-1 == sock4) {
304 /* error getting a socket */
305 msyslog(LOG_ERR, "open_sockets: socket(PF_INET) failed: %m");
306 exit(1);
307 }
308 /* Make it non-blocking */
309 make_socket_nonblocking(sock4);
310
311 /* Let's try using a wildcard... */
312 ZERO(name);
313 AF(&name) = AF_INET;
314 SET_ADDR4N(&name, INADDR_ANY);
315 SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0));
316
317 if (-1 == bind(sock4, &name.sa,
318 SOCKLEN(&name))) {
319 msyslog(LOG_ERR, "open_sockets: bind(sock4) failed: %m");
320 exit(1);
321 }
322
323 /* Register an NTP callback for recv/timeout */
324 ev_sock4 = event_new(base, sock4,
325 EV_TIMEOUT | EV_READ | EV_PERSIST,
326 &sock_cb, NULL);
327 if (NULL == ev_sock4) {
328 msyslog(LOG_ERR,
329 "open_sockets: event_new(base, sock4) failed!");
330 } else {
331 event_add(ev_sock4, &wakeup_tv);
332 }
333 }
334
335 /* We may not always have IPv6... */
336 if (-1 == sock6 && ipv6_works) {
337 sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
338 if (-1 == sock6 && ipv6_works) {
339 /* error getting a socket */
340 msyslog(LOG_ERR, "open_sockets: socket(PF_INET6) failed: %m");
341 exit(1);
342 }
343 /* Make it non-blocking */
344 make_socket_nonblocking(sock6);
345
346 /* Let's try using a wildcard... */
347 ZERO(name);
348 AF(&name) = AF_INET6;
349 SET_ADDR6N(&name, in6addr_any);
350 SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0));
351
352 if (-1 == bind(sock6, &name.sa,
353 SOCKLEN(&name))) {
354 msyslog(LOG_ERR, "open_sockets: bind(sock6) failed: %m");
355 exit(1);
356 }
357 /* Register an NTP callback for recv/timeout */
358 ev_sock6 = event_new(base, sock6,
359 EV_TIMEOUT | EV_READ | EV_PERSIST,
360 &sock_cb, NULL);
361 if (NULL == ev_sock6) {
362 msyslog(LOG_ERR,
363 "open_sockets: event_new(base, sock6) failed!");
364 } else {
365 event_add(ev_sock6, &wakeup_tv);
366 }
367 }
368
369 return;
370 }
371
372
373 /*
374 ** handle_lookup
375 */
376 void
377 handle_lookup(
378 const char *name,
379 int flags
380 )
381 {
382 struct addrinfo hints; /* Local copy is OK */
383 struct dns_ctx *ctx;
384 long l;
385 char * name_copy;
386 size_t name_sz;
387 size_t octets;
388
389 TRACE(1, ("handle_lookup(%s,%#x)\n", name, flags));
390
391 ZERO(hints);
392 hints.ai_family = ai_fam_pref;
393 hints.ai_flags = AI_CANONNAME | Z_AI_NUMERICSERV;
394 /*
395 ** Unless we specify a socktype, we'll get at least two
396 ** entries for each address: one for TCP and one for
397 ** UDP. That's not what we want.
398 */
399 hints.ai_socktype = SOCK_DGRAM;
400 hints.ai_protocol = IPPROTO_UDP;
401
402 name_sz = 1 + strlen(name);
403 octets = sizeof(*ctx) + name_sz; // Space for a ctx and the name
404 ctx = emalloc_zero(octets); // ctx at ctx[0]
405 name_copy = (char *)(ctx + 1); // Put the name at ctx[1]
406 memcpy(name_copy, name, name_sz); // copy the name to ctx[1]
407 ctx->name = name_copy; // point to it...
408 ctx->flags = flags;
409 ctx->timeout = response_tv;
410
411 /* The following should arguably be passed in... */
412 if (ENABLED_OPT(AUTHENTICATION) &&
413 atoint(OPT_ARG(AUTHENTICATION), &l)) {
414 ctx->key_id = l;
415 get_key(ctx->key_id, &ctx->key);
416 } else {
417 ctx->key_id = -1;
418 ctx->key = NULL;
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 (pkt_key != NULL) {
1138 x_pkt->exten[0] = htonl(key_id);
1139 mac_size = 20; /* max room for MAC */
1140 mac_size = make_mac((char *)x_pkt, pkt_len, mac_size,
1141 pkt_key, (char *)&x_pkt->exten[1]);
1142 if (mac_size > 0)
1143 pkt_len += mac_size + 4;
1144 }
1145 return pkt_len;
1146 }
1147
1148
1149 int
1150 handle_pkt(
1151 int rpktl,
1152 struct pkt * rpkt,
1153 sockaddr_u * host,
1154 const char * hostname
1155 )
1156 {
1157 char disptxt[32];
1158 const char * addrtxt;
1159 struct timeval tv_dst;
1160 int cnt;
1161 int sw_case;
1162 int digits;
1163 int stratum;
1164 char * ref;
1165 char * ts_str;
1166 const char * leaptxt;
1167 double offset;
1168 double precision;
1169 double synch_distance;
1170 char * p_SNTP_PRETEND_TIME;
1171 time_t pretend_time;
1172 #if SIZEOF_TIME_T == 8
1173 long long ll;
1174 #else
1175 long l;
1176 #endif
1177
1178 ts_str = NULL;
1179
1180 if (rpktl > 0)
1181 sw_case = 1;
1182 else
1183 sw_case = rpktl;
1184
1185 switch (sw_case) {
1186
1187 case SERVER_UNUSEABLE:
1188 return -1;
1189 break;
1190
1191 case PACKET_UNUSEABLE:
1192 break;
1193
1194 case SERVER_AUTH_FAIL:
1195 break;
1196
1197 case KOD_DEMOBILIZE:
1198 /* Received a DENY or RESTR KOD packet */
1199 addrtxt = stoa(host);
1200 ref = (char *)&rpkt->refid;
1201 add_entry(addrtxt, ref);
1202 msyslog(LOG_WARNING, "KOD code %c%c%c%c from %s %s",
1203 ref[0], ref[1], ref[2], ref[3], addrtxt, hostname);
1204 break;
1205
1206 case KOD_RATE:
1207 /*
1208 ** Hmm...
1209 ** We should probably call add_entry() with an
1210 ** expiration timestamp of several seconds in the future,
1211 ** and back-off even more if we get more RATE responses.
1212 */
1213 break;
1214
1215 case 1:
1216 TRACE(3, ("handle_pkt: %d bytes from %s %s\n",
1217 rpktl, stoa(host), hostname));
1218
1219 gettimeofday_cached(base, &tv_dst);
1220
1221 p_SNTP_PRETEND_TIME = getenv("SNTP_PRETEND_TIME");
1222 if (p_SNTP_PRETEND_TIME) {
1223 pretend_time = 0;
1224 #if SIZEOF_TIME_T == 4
1225 if (1 == sscanf(p_SNTP_PRETEND_TIME, "%ld", &l))
1226 pretend_time = (time_t)l;
1227 #elif SIZEOF_TIME_T == 8
1228 if (1 == sscanf(p_SNTP_PRETEND_TIME, "%lld", &ll))
1229 pretend_time = (time_t)ll;
1230 #else
1231 # include "GRONK: unexpected value for SIZEOF_TIME_T"
1232 #endif
1233 if (0 != pretend_time)
1234 tv_dst.tv_sec = pretend_time;
1235 }
1236
1237 offset_calculation(rpkt, rpktl, &tv_dst, &offset,
1238 &precision, &synch_distance);
1239 time_derived = TRUE;
1240
1241 for (digits = 0; (precision *= 10.) < 1.; ++digits)
1242 /* empty */ ;
1243 if (digits > 6)
1244 digits = 6;
1245
1246 ts_str = tv_to_str(&tv_dst);
1247 stratum = rpkt->stratum;
1248 if (0 == stratum)
1249 stratum = 16;
1250
1251 if (synch_distance > 0.) {
1252 cnt = snprintf(disptxt, sizeof(disptxt),
1253 " +/- %f", synch_distance);
1254 if ((size_t)cnt >= sizeof(disptxt))
1255 snprintf(disptxt, sizeof(disptxt),
1256 "ERROR %d >= %d", cnt,
1257 (int)sizeof(disptxt));
1258 } else {
1259 disptxt[0] = '\0';
1260 }
1261
1262 switch (PKT_LEAP(rpkt->li_vn_mode)) {
1263 case LEAP_NOWARNING:
1264 leaptxt = "no-leap";
1265 break;
1266 case LEAP_ADDSECOND:
1267 leaptxt = "add-leap";
1268 break;
1269 case LEAP_DELSECOND:
1270 leaptxt = "del-leap";
1271 break;
1272 case LEAP_NOTINSYNC:
1273 leaptxt = "unsync";
1274 break;
1275 default:
1276 leaptxt = "LEAP-ERROR";
1277 break;
1278 }
1279
1280 msyslog(LOG_INFO, "%s %+.*f%s %s s%d %s%s", ts_str,
1281 digits, offset, disptxt,
1282 hostnameaddr(hostname, host), stratum,
1283 leaptxt,
1284 (time_adjusted)
1285 ? " [excess]"
1286 : "");
1287 free(ts_str);
1288
1289 if (p_SNTP_PRETEND_TIME)
1290 return 0;
1291
1292 if (!time_adjusted &&
1293 (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW)))
1294 return set_time(offset);
1295
1296 return EX_OK;
1297 }
1298
1299 return 1;
1300 }
1301
1302
1303 void
1304 offset_calculation(
1305 struct pkt *rpkt,
1306 int rpktl,
1307 struct timeval *tv_dst,
1308 double *offset,
1309 double *precision,
1310 double *synch_distance
1311 )
1312 {
1313 l_fp p_rec, p_xmt, p_ref, p_org, tmp, dst;
1314 u_fp p_rdly, p_rdsp;
1315 double t21, t34, delta;
1316
1317 /* Convert timestamps from network to host byte order */
1318 p_rdly = NTOHS_FP(rpkt->rootdelay);
1319 p_rdsp = NTOHS_FP(rpkt->rootdisp);
1320 NTOHL_FP(&rpkt->reftime, &p_ref);
1321 NTOHL_FP(&rpkt->org, &p_org);
1322 NTOHL_FP(&rpkt->rec, &p_rec);
1323 NTOHL_FP(&rpkt->xmt, &p_xmt);
1324
1325 *precision = LOGTOD(rpkt->precision);
1326
1327 TRACE(3, ("offset_calculation: LOGTOD(rpkt->precision): %f\n", *precision));
1328
1329 /* Compute offset etc. */
1330 tmp = p_rec;
1331 L_SUB(&tmp, &p_org);
1332 LFPTOD(&tmp, t21);
1333 TVTOTS(tv_dst, &dst);
1334 dst.l_ui += JAN_1970;
1335 tmp = p_xmt;
1336 L_SUB(&tmp, &dst);
1337 LFPTOD(&tmp, t34);
1338 *offset = (t21 + t34) / 2.;
1339 delta = t21 - t34;
1340
1341 // synch_distance is:
1342 // (peer->delay + peer->rootdelay) / 2 + peer->disp
1343 // + peer->rootdisp + clock_phi * (current_time - peer->update)
1344 // + peer->jitter;
1345 //
1346 // and peer->delay = fabs(peer->offset - p_offset) * 2;
1347 // and peer->offset needs history, so we're left with
1348 // p_offset = (t21 + t34) / 2.;
1349 // peer->disp = 0; (we have no history to augment this)
1350 // clock_phi = 15e-6;
1351 // peer->jitter = LOGTOD(sys_precision); (we have no history to augment this)
1352 // and ntp_proto.c:set_sys_tick_precision() should get us sys_precision.
1353 //
1354 // so our answer seems to be:
1355 //
1356 // (fabs(t21 + t34) + peer->rootdelay) / 3.
1357 // + 0 (peer->disp)
1358 // + peer->rootdisp
1359 // + 15e-6 (clock_phi)
1360 // + LOGTOD(sys_precision)
1361
1362 INSIST( FPTOD(p_rdly) >= 0. );
1363 #if 1
1364 *synch_distance = (fabs(t21 + t34) + FPTOD(p_rdly)) / 3.
1365 + 0.
1366 + FPTOD(p_rdsp)
1367 + 15e-6
1368 + 0. /* LOGTOD(sys_precision) when we can get it */
1369 ;
1370 INSIST( *synch_distance >= 0. );
1371 #else
1372 *synch_distance = (FPTOD(p_rdly) + FPTOD(p_rdsp))/2.0;
1373 #endif
1374
1375 #ifdef DEBUG
1376 if (debug > 3) {
1377 printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
1378 printf("sntp rootdisp: %f\n", FPTOD(p_rdsp));
1379 printf("sntp syncdist: %f\n", *synch_distance);
1380
1381 pkt_output(rpkt, rpktl, stdout);
1382
1383 printf("sntp offset_calculation: rpkt->reftime:\n");
1384 l_fp_output(&p_ref, stdout);
1385 printf("sntp offset_calculation: rpkt->org:\n");
1386 l_fp_output(&p_org, stdout);
1387 printf("sntp offset_calculation: rpkt->rec:\n");
1388 l_fp_output(&p_rec, stdout);
1389 printf("sntp offset_calculation: rpkt->xmt:\n");
1390 l_fp_output(&p_xmt, stdout);
1391 }
1392 #endif
1393
1394 TRACE(3, ("sntp offset_calculation:\trec - org t21: %.6f\n"
1395 "\txmt - dst t34: %.6f\tdelta: %.6f\toffset: %.6f\n",
1396 t21, t34, delta, *offset));
1397
1398 return;
1399 }
1400
1401
1402
1403 /* Compute the 8 bits for li_vn_mode */
1404 void
1405 set_li_vn_mode (
1406 struct pkt *spkt,
1407 char leap,
1408 char version,
1409 char mode
1410 )
1411 {
1412 if (leap > 3) {
1413 msyslog(LOG_DEBUG, "set_li_vn_mode: leap > 3, using max. 3");
1414 leap = 3;
1415 }
1416
1417 if ((unsigned char)version > 7) {
1418 msyslog(LOG_DEBUG, "set_li_vn_mode: version < 0 or > 7, using 4");
1419 version = 4;
1420 }
1421
1422 if (mode > 7) {
1423 msyslog(LOG_DEBUG, "set_li_vn_mode: mode > 7, using client mode 3");
1424 mode = 3;
1425 }
1426
1427 spkt->li_vn_mode = leap << 6;
1428 spkt->li_vn_mode |= version << 3;
1429 spkt->li_vn_mode |= mode;
1430 }
1431
1432
1433 /*
1434 ** set_time applies 'offset' to the local clock.
1435 */
1436 int
1437 set_time(
1438 double offset
1439 )
1440 {
1441 int rc;
1442
1443 if (time_adjusted)
1444 return EX_OK;
1445
1446 /*
1447 ** If we can step but we cannot slew, then step.
1448 ** If we can step or slew and and |offset| > steplimit, then step.
1449 */
1450 if (ENABLED_OPT(STEP) &&
1451 ( !ENABLED_OPT(SLEW)
1452 || (ENABLED_OPT(SLEW) && (fabs(offset) > steplimit))
1453 )) {
1454 rc = step_systime(offset);
1455
1456 /* If there was a problem, can we rely on errno? */
1457 if (1 == rc)
1458 time_adjusted = TRUE;
1459 return (time_adjusted)
1460 ? EX_OK
1461 : 1;
1462 /*
1463 ** In case of error, what should we use?
1464 ** EX_UNAVAILABLE?
1465 ** EX_OSERR?
1466 ** EX_NOPERM?
1467 */
1468 }
1469
1470 if (ENABLED_OPT(SLEW)) {
1471 rc = adj_systime(offset);
1472
1473 /* If there was a problem, can we rely on errno? */
1474 if (1 == rc)
1475 time_adjusted = TRUE;
1476 return (time_adjusted)
1477 ? EX_OK
1478 : 1;
1479 /*
1480 ** In case of error, what should we use?
1481 ** EX_UNAVAILABLE?
1482 ** EX_OSERR?
1483 ** EX_NOPERM?
1484 */
1485 }
1486
1487 return EX_SOFTWARE;
1488 }
1489
1490
1491 int
1492 libevent_version_ok(void)
1493 {
1494 ev_uint32_t v_compile_maj;
1495 ev_uint32_t v_run_maj;
1496
1497 v_compile_maj = LIBEVENT_VERSION_NUMBER & 0xffff0000;
1498 v_run_maj = event_get_version_number() & 0xffff0000;
1499 if (v_compile_maj != v_run_maj) {
1500 fprintf(stderr,
1501 "Incompatible libevent versions: have %s, built with %s\n",
1502 event_get_version(),
1503 LIBEVENT_VERSION);
1504 return 0;
1505 }
1506 return 1;
1507 }
1508
1509 /*
1510 * gettimeofday_cached()
1511 *
1512 * Clones the event_base_gettimeofday_cached() interface but ensures the
1513 * times are always on the gettimeofday() 1970 scale. Older libevent 2
1514 * sometimes used gettimeofday(), sometimes the since-system-start
1515 * clock_gettime(CLOCK_MONOTONIC), depending on the platform.
1516 *
1517 * It is not cleanly possible to tell which timescale older libevent is
1518 * using.
1519 *
1520 * The strategy involves 1 hour thresholds chosen to be far longer than
1521 * the duration of a round of libevent callbacks, which share a cached
1522 * start-of-round time. First compare the last cached time with the
1523 * current gettimeofday() time. If they are within one hour, libevent
1524 * is using the proper timescale so leave the offset 0. Otherwise,
1525 * compare libevent's cached time and the current time on the monotonic
1526 * scale. If they are within an hour, libevent is using the monotonic
1527 * scale so calculate the offset to add to such times to bring them to
1528 * gettimeofday()'s scale.
1529 */
1530 int
1531 gettimeofday_cached(
1532 struct event_base * b,
1533 struct timeval * caller_tv
1534 )
1535 {
1536 #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1537 static struct event_base * cached_b;
1538 static struct timeval cached;
1539 static struct timeval adj_cached;
1540 static struct timeval offset;
1541 static int offset_ready;
1542 struct timeval latest;
1543 struct timeval systemt;
1544 struct timespec ts;
1545 struct timeval mono;
1546 struct timeval diff;
1547 int cgt_rc;
1548 int gtod_rc;
1549
1550 event_base_gettimeofday_cached(b, &latest);
1551 if (b == cached_b &&
1552 !memcmp(&latest, &cached, sizeof(latest))) {
1553 *caller_tv = adj_cached;
1554 return 0;
1555 }
1556 cached = latest;
1557 cached_b = b;
1558 if (!offset_ready) {
1559 cgt_rc = clock_gettime(CLOCK_MONOTONIC, &ts);
1560 gtod_rc = gettimeofday(&systemt, NULL);
1561 if (0 != gtod_rc) {
1562 msyslog(LOG_ERR,
1563 "%s: gettimeofday() error %m",
1564 progname);
1565 exit(1);
1566 }
1567 diff = sub_tval(systemt, latest);
1568 if (debug > 1)
1569 printf("system minus cached %+ld.%06ld\n",
1570 (long)diff.tv_sec, (long)diff.tv_usec);
1571 if (0 != cgt_rc || labs((long)diff.tv_sec) < 3600) {
1572 /*
1573 * Either use_monotonic == 0, or this libevent
1574 * has been repaired. Leave offset at zero.
1575 */
1576 } else {
1577 mono.tv_sec = ts.tv_sec;
1578 mono.tv_usec = ts.tv_nsec / 1000;
1579 diff = sub_tval(latest, mono);
1580 if (debug > 1)
1581 printf("cached minus monotonic %+ld.%06ld\n",
1582 (long)diff.tv_sec, (long)diff.tv_usec);
1583 if (labs((long)diff.tv_sec) < 3600) {
1584 /* older libevent2 using monotonic */
1585 offset = sub_tval(systemt, mono);
1586 TRACE(1, ("%s: Offsetting libevent CLOCK_MONOTONIC times by %+ld.%06ld\n",
1587 "gettimeofday_cached",
1588 (long)offset.tv_sec,
1589 (long)offset.tv_usec));
1590 }
1591 }
1592 offset_ready = TRUE;
1593 }
1594 adj_cached = add_tval(cached, offset);
1595 *caller_tv = adj_cached;
1596
1597 return 0;
1598 #else
1599 return event_base_gettimeofday_cached(b, caller_tv);
1600 #endif
1601 }
1602
1603