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