1285612Sdelphij#include <config.h> 2132451Sroberto 3285612Sdelphij#include <event2/util.h> 4285612Sdelphij#include <event2/event.h> 5132451Sroberto 6285612Sdelphij#include "ntp_workimpl.h" 7285612Sdelphij#ifdef WORK_THREAD 8285612Sdelphij# include <event2/thread.h> 9285612Sdelphij#endif 10132451Sroberto 11285612Sdelphij#include "main.h" 12285612Sdelphij#include "ntp_libopts.h" 13285612Sdelphij#include "kod_management.h" 14285612Sdelphij#include "networking.h" 15285612Sdelphij#include "utilities.h" 16285612Sdelphij#include "log.h" 17285612Sdelphij#include "libntp.h" 18132451Sroberto 19132451Sroberto 20285612Sdelphijint shutting_down; 21285612Sdelphijint time_derived; 22285612Sdelphijint time_adjusted; 23285612Sdelphijint n_pending_dns = 0; 24285612Sdelphijint n_pending_ntp = 0; 25285612Sdelphijint ai_fam_pref = AF_UNSPEC; 26285612Sdelphijint ntpver = 4; 27285612Sdelphijdouble steplimit = -1; 28285612SdelphijSOCKET sock4 = -1; /* Socket for IPv4 */ 29285612SdelphijSOCKET sock6 = -1; /* Socket for IPv6 */ 30285612Sdelphij/* 31285612Sdelphij** BCAST *must* listen on port 123 (by default), so we can only 32285612Sdelphij** use the UCST sockets (above) if they too are using port 123 33285612Sdelphij*/ 34285612SdelphijSOCKET bsock4 = -1; /* Broadcast Socket for IPv4 */ 35285612SdelphijSOCKET bsock6 = -1; /* Broadcast Socket for IPv6 */ 36285612Sdelphijstruct event_base *base; 37285612Sdelphijstruct event *ev_sock4; 38285612Sdelphijstruct event *ev_sock6; 39285612Sdelphijstruct event *ev_worker_timeout; 40285612Sdelphijstruct event *ev_xmt_timer; 41132451Sroberto 42285612Sdelphijstruct dns_ctx { 43285612Sdelphij const char * name; 44285612Sdelphij int flags; 45285612Sdelphij#define CTX_BCST 0x0001 46285612Sdelphij#define CTX_UCST 0x0002 47285612Sdelphij#define CTX_xCST 0x0003 48285612Sdelphij#define CTX_CONC 0x0004 49285612Sdelphij#define CTX_unused 0xfffd 50285612Sdelphij int key_id; 51285612Sdelphij struct timeval timeout; 52285612Sdelphij struct key * key; 53285612Sdelphij}; 54132451Sroberto 55285612Sdelphijtypedef struct sent_pkt_tag sent_pkt; 56285612Sdelphijstruct sent_pkt_tag { 57285612Sdelphij sent_pkt * link; 58285612Sdelphij struct dns_ctx * dctx; 59285612Sdelphij sockaddr_u addr; 60285612Sdelphij time_t stime; 61285612Sdelphij int done; 62285612Sdelphij struct pkt x_pkt; 63285612Sdelphij}; 64132451Sroberto 65285612Sdelphijtypedef struct xmt_ctx_tag xmt_ctx; 66285612Sdelphijstruct xmt_ctx_tag { 67285612Sdelphij xmt_ctx * link; 68285612Sdelphij SOCKET sock; 69285612Sdelphij time_t sched; 70285612Sdelphij sent_pkt * spkt; 71285612Sdelphij}; 72132451Sroberto 73285612Sdelphijstruct timeval gap; 74285612Sdelphijxmt_ctx * xmt_q; 75285612Sdelphijstruct key * keys = NULL; 76285612Sdelphijint response_timeout; 77285612Sdelphijstruct timeval response_tv; 78285612Sdelphijstruct timeval start_tv; 79285612Sdelphij/* check the timeout at least once per second */ 80285612Sdelphijstruct timeval wakeup_tv = { 0, 888888 }; 81132451Sroberto 82285612Sdelphijsent_pkt * fam_listheads[2]; 83285612Sdelphij#define v4_pkts_list (fam_listheads[0]) 84285612Sdelphij#define v6_pkts_list (fam_listheads[1]) 85132451Sroberto 86285612Sdelphijstatic union { 87285612Sdelphij struct pkt pkt; 88285612Sdelphij char buf[LEN_PKT_NOMAC + NTP_MAXEXTEN + MAX_MAC_LEN]; 89285612Sdelphij} rbuf; 90132451Sroberto 91285612Sdelphij#define r_pkt rbuf.pkt 92132451Sroberto 93285612Sdelphij#ifdef HAVE_DROPROOT 94285612Sdelphijint droproot; /* intres imports these */ 95285612Sdelphijint root_dropped; 96285612Sdelphij#endif 97285612Sdelphiju_long current_time; /* libntp/authkeys.c */ 98132451Sroberto 99285612Sdelphijvoid open_sockets(void); 100285612Sdelphijvoid handle_lookup(const char *name, int flags); 101285612Sdelphijvoid sntp_addremove_fd(int fd, int is_pipe, int remove_it); 102285612Sdelphijvoid worker_timeout(evutil_socket_t, short, void *); 103285612Sdelphijvoid worker_resp_cb(evutil_socket_t, short, void *); 104285612Sdelphijvoid sntp_name_resolved(int, int, void *, const char *, const char *, 105285612Sdelphij const struct addrinfo *, 106285612Sdelphij const struct addrinfo *); 107285612Sdelphijvoid queue_xmt(SOCKET sock, struct dns_ctx *dctx, sent_pkt *spkt, 108285612Sdelphij u_int xmt_delay); 109285612Sdelphijvoid xmt_timer_cb(evutil_socket_t, short, void *ptr); 110285612Sdelphijvoid xmt(xmt_ctx *xctx); 111285612Sdelphijint check_kod(const struct addrinfo *ai); 112285612Sdelphijvoid timeout_query(sent_pkt *); 113285612Sdelphijvoid timeout_queries(void); 114285612Sdelphijvoid sock_cb(evutil_socket_t, short, void *); 115285612Sdelphijvoid check_exit_conditions(void); 116285612Sdelphijvoid sntp_libevent_log_cb(int, const char *); 117285612Sdelphijvoid set_li_vn_mode(struct pkt *spkt, char leap, char version, char mode); 118285612Sdelphijint set_time(double offset); 119285612Sdelphijvoid dec_pending_ntp(const char *, sockaddr_u *); 120285612Sdelphijint libevent_version_ok(void); 121285612Sdelphijint gettimeofday_cached(struct event_base *b, struct timeval *tv); 122132451Sroberto 123132451Sroberto 124285612Sdelphij/* 125285612Sdelphij * The actual main function. 126285612Sdelphij */ 127285612Sdelphijint 128285612Sdelphijsntp_main ( 129285612Sdelphij int argc, 130285612Sdelphij char **argv, 131285612Sdelphij const char *sntpVersion 132285612Sdelphij ) 133285612Sdelphij{ 134285612Sdelphij int i; 135285612Sdelphij int exitcode; 136285612Sdelphij int optct; 137285612Sdelphij struct event_config * evcfg; 138132451Sroberto 139285612Sdelphij /* Initialize logging system - sets up progname */ 140285612Sdelphij sntp_init_logging(argv[0]); 141132451Sroberto 142285612Sdelphij if (!libevent_version_ok()) 143285612Sdelphij exit(EX_SOFTWARE); 144132451Sroberto 145285612Sdelphij init_lib(); 146285612Sdelphij init_auth(); 147132451Sroberto 148285612Sdelphij optct = ntpOptionProcess(&sntpOptions, argc, argv); 149285612Sdelphij argc -= optct; 150285612Sdelphij argv += optct; 151132451Sroberto 152132451Sroberto 153285612Sdelphij debug = OPT_VALUE_SET_DEBUG_LEVEL; 154132451Sroberto 155285612Sdelphij TRACE(2, ("init_lib() done, %s%s\n", 156285612Sdelphij (ipv4_works) 157285612Sdelphij ? "ipv4_works " 158285612Sdelphij : "", 159285612Sdelphij (ipv6_works) 160285612Sdelphij ? "ipv6_works " 161285612Sdelphij : "")); 162285612Sdelphij ntpver = OPT_VALUE_NTPVERSION; 163285612Sdelphij steplimit = OPT_VALUE_STEPLIMIT / 1e3; 164285612Sdelphij gap.tv_usec = max(0, OPT_VALUE_GAP * 1000); 165285612Sdelphij gap.tv_usec = min(gap.tv_usec, 999999); 166132451Sroberto 167285612Sdelphij if (HAVE_OPT(LOGFILE)) 168285612Sdelphij open_logfile(OPT_ARG(LOGFILE)); 169132451Sroberto 170285612Sdelphij msyslog(LOG_INFO, "%s", sntpVersion); 171132451Sroberto 172285612Sdelphij if (0 == argc && !HAVE_OPT(BROADCAST) && !HAVE_OPT(CONCURRENT)) { 173285612Sdelphij printf("%s: Must supply at least one of -b hostname, -c hostname, or hostname.\n", 174285612Sdelphij progname); 175285612Sdelphij exit(EX_USAGE); 176285612Sdelphij } 177132451Sroberto 178132451Sroberto 179285612Sdelphij /* 180285612Sdelphij ** Eventually, we probably want: 181285612Sdelphij ** - separate bcst and ucst timeouts (why?) 182285612Sdelphij ** - multiple --timeout values in the commandline 183285612Sdelphij */ 184132451Sroberto 185285612Sdelphij response_timeout = OPT_VALUE_TIMEOUT; 186285612Sdelphij response_tv.tv_sec = response_timeout; 187285612Sdelphij response_tv.tv_usec = 0; 188132451Sroberto 189285612Sdelphij /* IPv6 available? */ 190285612Sdelphij if (isc_net_probeipv6() != ISC_R_SUCCESS) { 191285612Sdelphij ai_fam_pref = AF_INET; 192285612Sdelphij TRACE(1, ("No ipv6 support available, forcing ipv4\n")); 193285612Sdelphij } else { 194285612Sdelphij /* Check for options -4 and -6 */ 195285612Sdelphij if (HAVE_OPT(IPV4)) 196285612Sdelphij ai_fam_pref = AF_INET; 197285612Sdelphij else if (HAVE_OPT(IPV6)) 198285612Sdelphij ai_fam_pref = AF_INET6; 199285612Sdelphij } 200132451Sroberto 201285612Sdelphij /* TODO: Parse config file if declared */ 202132451Sroberto 203285612Sdelphij /* 204285612Sdelphij ** Init the KOD system. 205285612Sdelphij ** For embedded systems with no writable filesystem, 206285612Sdelphij ** -K /dev/null can be used to disable KoD storage. 207285612Sdelphij */ 208285612Sdelphij kod_init_kod_db(OPT_ARG(KOD), FALSE); 209132451Sroberto 210330567Sgordon /* HMS: Check and see what happens if KEYFILE doesn't exist */ 211330567Sgordon auth_init(OPT_ARG(KEYFILE), &keys); 212132451Sroberto 213285612Sdelphij /* 214285612Sdelphij ** Considering employing a variable that prevents functions of doing 215285612Sdelphij ** anything until everything is initialized properly 216285612Sdelphij ** 217285612Sdelphij ** HMS: What exactly does the above mean? 218285612Sdelphij */ 219285612Sdelphij event_set_log_callback(&sntp_libevent_log_cb); 220285612Sdelphij if (debug > 0) 221285612Sdelphij event_enable_debug_mode(); 222285612Sdelphij#ifdef WORK_THREAD 223285612Sdelphij evthread_use_pthreads(); 224285612Sdelphij /* we use libevent from main thread only, locks should be academic */ 225285612Sdelphij if (debug > 0) 226285612Sdelphij evthread_enable_lock_debuging(); 227285612Sdelphij#endif 228285612Sdelphij evcfg = event_config_new(); 229285612Sdelphij if (NULL == evcfg) { 230285612Sdelphij printf("%s: event_config_new() failed!\n", progname); 231285612Sdelphij return -1; 232285612Sdelphij } 233285612Sdelphij#ifndef HAVE_SOCKETPAIR 234285612Sdelphij event_config_require_features(evcfg, EV_FEATURE_FDS); 235285612Sdelphij#endif 236285612Sdelphij /* all libevent calls are from main thread */ 237285612Sdelphij /* event_config_set_flag(evcfg, EVENT_BASE_FLAG_NOLOCK); */ 238285612Sdelphij base = event_base_new_with_config(evcfg); 239285612Sdelphij event_config_free(evcfg); 240285612Sdelphij if (NULL == base) { 241285612Sdelphij printf("%s: event_base_new() failed!\n", progname); 242285612Sdelphij return -1; 243285612Sdelphij } 244132451Sroberto 245285612Sdelphij /* wire into intres resolver */ 246285612Sdelphij worker_per_query = TRUE; 247285612Sdelphij addremove_io_fd = &sntp_addremove_fd; 248132451Sroberto 249285612Sdelphij open_sockets(); 250132451Sroberto 251285612Sdelphij if (HAVE_OPT(BROADCAST)) { 252285612Sdelphij int cn = STACKCT_OPT( BROADCAST ); 253285612Sdelphij const char ** cp = STACKLST_OPT( BROADCAST ); 254132451Sroberto 255285612Sdelphij while (cn-- > 0) { 256285612Sdelphij handle_lookup(*cp, CTX_BCST); 257285612Sdelphij cp++; 258285612Sdelphij } 259285612Sdelphij } 260132451Sroberto 261285612Sdelphij if (HAVE_OPT(CONCURRENT)) { 262285612Sdelphij int cn = STACKCT_OPT( CONCURRENT ); 263285612Sdelphij const char ** cp = STACKLST_OPT( CONCURRENT ); 264132451Sroberto 265285612Sdelphij while (cn-- > 0) { 266285612Sdelphij handle_lookup(*cp, CTX_UCST | CTX_CONC); 267285612Sdelphij cp++; 268285612Sdelphij } 269285612Sdelphij } 270132451Sroberto 271285612Sdelphij for (i = 0; i < argc; ++i) 272285612Sdelphij handle_lookup(argv[i], CTX_UCST); 273132451Sroberto 274285612Sdelphij gettimeofday_cached(base, &start_tv); 275285612Sdelphij event_base_dispatch(base); 276285612Sdelphij event_base_free(base); 277132451Sroberto 278285612Sdelphij if (!time_adjusted && 279285612Sdelphij (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW))) 280285612Sdelphij exitcode = 1; 281285612Sdelphij else 282285612Sdelphij exitcode = 0; 283132451Sroberto 284285612Sdelphij return exitcode; 285285612Sdelphij} 286132451Sroberto 287132451Sroberto 288285612Sdelphij/* 289285612Sdelphij** open sockets and make them non-blocking 290285612Sdelphij*/ 291285612Sdelphijvoid 292285612Sdelphijopen_sockets( 293285612Sdelphij void 294285612Sdelphij ) 295285612Sdelphij{ 296285612Sdelphij sockaddr_u name; 297132451Sroberto 298285612Sdelphij if (-1 == sock4) { 299285612Sdelphij sock4 = socket(PF_INET, SOCK_DGRAM, 0); 300285612Sdelphij if (-1 == sock4) { 301285612Sdelphij /* error getting a socket */ 302285612Sdelphij msyslog(LOG_ERR, "open_sockets: socket(PF_INET) failed: %m"); 303285612Sdelphij exit(1); 304285612Sdelphij } 305285612Sdelphij /* Make it non-blocking */ 306285612Sdelphij make_socket_nonblocking(sock4); 307132451Sroberto 308285612Sdelphij /* Let's try using a wildcard... */ 309285612Sdelphij ZERO(name); 310285612Sdelphij AF(&name) = AF_INET; 311285612Sdelphij SET_ADDR4N(&name, INADDR_ANY); 312285612Sdelphij SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0)); 313132451Sroberto 314285612Sdelphij if (-1 == bind(sock4, &name.sa, 315285612Sdelphij SOCKLEN(&name))) { 316285612Sdelphij msyslog(LOG_ERR, "open_sockets: bind(sock4) failed: %m"); 317285612Sdelphij exit(1); 318285612Sdelphij } 319132451Sroberto 320285612Sdelphij /* Register an NTP callback for recv/timeout */ 321285612Sdelphij ev_sock4 = event_new(base, sock4, 322285612Sdelphij EV_TIMEOUT | EV_READ | EV_PERSIST, 323285612Sdelphij &sock_cb, NULL); 324285612Sdelphij if (NULL == ev_sock4) { 325285612Sdelphij msyslog(LOG_ERR, 326285612Sdelphij "open_sockets: event_new(base, sock4) failed!"); 327285612Sdelphij } else { 328285612Sdelphij event_add(ev_sock4, &wakeup_tv); 329285612Sdelphij } 330285612Sdelphij } 331132451Sroberto 332285612Sdelphij /* We may not always have IPv6... */ 333285612Sdelphij if (-1 == sock6 && ipv6_works) { 334285612Sdelphij sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 335285612Sdelphij if (-1 == sock6 && ipv6_works) { 336285612Sdelphij /* error getting a socket */ 337285612Sdelphij msyslog(LOG_ERR, "open_sockets: socket(PF_INET6) failed: %m"); 338285612Sdelphij exit(1); 339285612Sdelphij } 340285612Sdelphij /* Make it non-blocking */ 341285612Sdelphij make_socket_nonblocking(sock6); 342132451Sroberto 343285612Sdelphij /* Let's try using a wildcard... */ 344285612Sdelphij ZERO(name); 345285612Sdelphij AF(&name) = AF_INET6; 346285612Sdelphij SET_ADDR6N(&name, in6addr_any); 347285612Sdelphij SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0)); 348132451Sroberto 349285612Sdelphij if (-1 == bind(sock6, &name.sa, 350285612Sdelphij SOCKLEN(&name))) { 351285612Sdelphij msyslog(LOG_ERR, "open_sockets: bind(sock6) failed: %m"); 352285612Sdelphij exit(1); 353285612Sdelphij } 354285612Sdelphij /* Register an NTP callback for recv/timeout */ 355285612Sdelphij ev_sock6 = event_new(base, sock6, 356285612Sdelphij EV_TIMEOUT | EV_READ | EV_PERSIST, 357285612Sdelphij &sock_cb, NULL); 358285612Sdelphij if (NULL == ev_sock6) { 359285612Sdelphij msyslog(LOG_ERR, 360285612Sdelphij "open_sockets: event_new(base, sock6) failed!"); 361285612Sdelphij } else { 362285612Sdelphij event_add(ev_sock6, &wakeup_tv); 363285612Sdelphij } 364285612Sdelphij } 365285612Sdelphij 366285612Sdelphij return; 367285612Sdelphij} 368132451Sroberto 369132451Sroberto 370285612Sdelphij/* 371285612Sdelphij** handle_lookup 372285612Sdelphij*/ 373285612Sdelphijvoid 374285612Sdelphijhandle_lookup( 375285612Sdelphij const char *name, 376285612Sdelphij int flags 377285612Sdelphij ) 378285612Sdelphij{ 379285612Sdelphij struct addrinfo hints; /* Local copy is OK */ 380285612Sdelphij struct dns_ctx *ctx; 381285612Sdelphij char * name_copy; 382285612Sdelphij size_t name_sz; 383285612Sdelphij size_t octets; 384132451Sroberto 385285612Sdelphij TRACE(1, ("handle_lookup(%s,%#x)\n", name, flags)); 386132451Sroberto 387285612Sdelphij ZERO(hints); 388285612Sdelphij hints.ai_family = ai_fam_pref; 389285612Sdelphij hints.ai_flags = AI_CANONNAME | Z_AI_NUMERICSERV; 390285612Sdelphij /* 391285612Sdelphij ** Unless we specify a socktype, we'll get at least two 392285612Sdelphij ** entries for each address: one for TCP and one for 393285612Sdelphij ** UDP. That's not what we want. 394285612Sdelphij */ 395285612Sdelphij hints.ai_socktype = SOCK_DGRAM; 396285612Sdelphij hints.ai_protocol = IPPROTO_UDP; 397132451Sroberto 398285612Sdelphij name_sz = 1 + strlen(name); 399285612Sdelphij octets = sizeof(*ctx) + name_sz; // Space for a ctx and the name 400285612Sdelphij ctx = emalloc_zero(octets); // ctx at ctx[0] 401285612Sdelphij name_copy = (char *)(ctx + 1); // Put the name at ctx[1] 402285612Sdelphij memcpy(name_copy, name, name_sz); // copy the name to ctx[1] 403285612Sdelphij ctx->name = name_copy; // point to it... 404285612Sdelphij ctx->flags = flags; 405285612Sdelphij ctx->timeout = response_tv; 406330567Sgordon ctx->key = NULL; 407132451Sroberto 408285612Sdelphij /* The following should arguably be passed in... */ 409330567Sgordon if (ENABLED_OPT(AUTHENTICATION)) { 410330567Sgordon ctx->key_id = OPT_VALUE_AUTHENTICATION; 411285612Sdelphij get_key(ctx->key_id, &ctx->key); 412330567Sgordon if (NULL == ctx->key) { 413330567Sgordon fprintf(stderr, "%s: Authentication with keyID %d requested, but no matching keyID found in <%s>!\n", 414330567Sgordon progname, ctx->key_id, OPT_ARG(KEYFILE)); 415330567Sgordon exit(1); 416330567Sgordon } 417285612Sdelphij } else { 418285612Sdelphij ctx->key_id = -1; 419285612Sdelphij } 420132451Sroberto 421285612Sdelphij ++n_pending_dns; 422285612Sdelphij getaddrinfo_sometime(name, "123", &hints, 0, 423285612Sdelphij &sntp_name_resolved, ctx); 424132451Sroberto} 425132451Sroberto 426132451Sroberto 427285612Sdelphij/* 428285612Sdelphij** DNS Callback: 429285612Sdelphij** - For each IP: 430285612Sdelphij** - - open a socket 431285612Sdelphij** - - increment n_pending_ntp 432285612Sdelphij** - - send a request if this is a Unicast callback 433285612Sdelphij** - - queue wait for response 434285612Sdelphij** - decrement n_pending_dns 435285612Sdelphij*/ 436285612Sdelphijvoid 437285612Sdelphijsntp_name_resolved( 438285612Sdelphij int rescode, 439285612Sdelphij int gai_errno, 440285612Sdelphij void * context, 441285612Sdelphij const char * name, 442285612Sdelphij const char * service, 443285612Sdelphij const struct addrinfo * hints, 444285612Sdelphij const struct addrinfo * addr 445285612Sdelphij ) 446285612Sdelphij{ 447285612Sdelphij struct dns_ctx * dctx; 448285612Sdelphij sent_pkt * spkt; 449285612Sdelphij const struct addrinfo * ai; 450285612Sdelphij SOCKET sock; 451285612Sdelphij u_int xmt_delay_v4; 452285612Sdelphij u_int xmt_delay_v6; 453285612Sdelphij u_int xmt_delay; 454285612Sdelphij size_t octets; 455132451Sroberto 456285612Sdelphij xmt_delay_v4 = 0; 457285612Sdelphij xmt_delay_v6 = 0; 458285612Sdelphij dctx = context; 459285612Sdelphij if (rescode) { 460285612Sdelphij#ifdef EAI_SYSTEM 461285612Sdelphij if (EAI_SYSTEM == rescode) { 462285612Sdelphij errno = gai_errno; 463285612Sdelphij mfprintf(stderr, "%s lookup error %m\n", 464285612Sdelphij dctx->name); 465285612Sdelphij } else 466285612Sdelphij#endif 467285612Sdelphij fprintf(stderr, "%s lookup error %s\n", 468285612Sdelphij dctx->name, gai_strerror(rescode)); 469285612Sdelphij } else { 470285612Sdelphij TRACE(3, ("%s [%s]\n", dctx->name, 471285612Sdelphij (addr->ai_canonname != NULL) 472285612Sdelphij ? addr->ai_canonname 473285612Sdelphij : "")); 474132451Sroberto 475285612Sdelphij for (ai = addr; ai != NULL; ai = ai->ai_next) { 476132451Sroberto 477285612Sdelphij if (check_kod(ai)) 478285612Sdelphij continue; 479132451Sroberto 480285612Sdelphij switch (ai->ai_family) { 481132451Sroberto 482285612Sdelphij case AF_INET: 483285612Sdelphij sock = sock4; 484285612Sdelphij xmt_delay = xmt_delay_v4; 485285612Sdelphij xmt_delay_v4++; 486285612Sdelphij break; 487132451Sroberto 488285612Sdelphij case AF_INET6: 489285612Sdelphij if (!ipv6_works) 490285612Sdelphij continue; 491132451Sroberto 492285612Sdelphij sock = sock6; 493285612Sdelphij xmt_delay = xmt_delay_v6; 494285612Sdelphij xmt_delay_v6++; 495285612Sdelphij break; 496132451Sroberto 497285612Sdelphij default: 498285612Sdelphij msyslog(LOG_ERR, "sntp_name_resolved: unexpected ai_family: %d", 499285612Sdelphij ai->ai_family); 500285612Sdelphij exit(1); 501285612Sdelphij break; 502285612Sdelphij } 503132451Sroberto 504285612Sdelphij /* 505285612Sdelphij ** We're waiting for a response for either unicast 506285612Sdelphij ** or broadcast, so... 507285612Sdelphij */ 508285612Sdelphij ++n_pending_ntp; 509132451Sroberto 510285612Sdelphij /* If this is for a unicast IP, queue a request */ 511285612Sdelphij if (dctx->flags & CTX_UCST) { 512285612Sdelphij spkt = emalloc_zero(sizeof(*spkt)); 513285612Sdelphij spkt->dctx = dctx; 514285612Sdelphij octets = min(ai->ai_addrlen, sizeof(spkt->addr)); 515285612Sdelphij memcpy(&spkt->addr, ai->ai_addr, octets); 516285612Sdelphij queue_xmt(sock, dctx, spkt, xmt_delay); 517285612Sdelphij } 518285612Sdelphij } 519285612Sdelphij } 520285612Sdelphij /* n_pending_dns really should be >0 here... */ 521285612Sdelphij --n_pending_dns; 522285612Sdelphij check_exit_conditions(); 523132451Sroberto} 524132451Sroberto 525132451Sroberto 526285612Sdelphij/* 527285612Sdelphij** queue_xmt 528285612Sdelphij*/ 529285612Sdelphijvoid 530285612Sdelphijqueue_xmt( 531285612Sdelphij SOCKET sock, 532285612Sdelphij struct dns_ctx * dctx, 533285612Sdelphij sent_pkt * spkt, 534285612Sdelphij u_int xmt_delay 535285612Sdelphij ) 536285612Sdelphij{ 537285612Sdelphij sockaddr_u * dest; 538285612Sdelphij sent_pkt ** pkt_listp; 539285612Sdelphij sent_pkt * match; 540285612Sdelphij xmt_ctx * xctx; 541285612Sdelphij struct timeval start_cb; 542285612Sdelphij struct timeval delay; 543132451Sroberto 544285612Sdelphij dest = &spkt->addr; 545285612Sdelphij if (IS_IPV6(dest)) 546285612Sdelphij pkt_listp = &v6_pkts_list; 547285612Sdelphij else 548285612Sdelphij pkt_listp = &v4_pkts_list; 549132451Sroberto 550285612Sdelphij /* reject attempts to add address already listed */ 551285612Sdelphij for (match = *pkt_listp; match != NULL; match = match->link) { 552285612Sdelphij if (ADDR_PORT_EQ(&spkt->addr, &match->addr)) { 553285612Sdelphij if (strcasecmp(spkt->dctx->name, 554285612Sdelphij match->dctx->name)) 555285612Sdelphij printf("%s %s duplicate address from %s ignored.\n", 556285612Sdelphij sptoa(&match->addr), 557285612Sdelphij match->dctx->name, 558285612Sdelphij spkt->dctx->name); 559285612Sdelphij else 560285612Sdelphij printf("%s %s, duplicate address ignored.\n", 561285612Sdelphij sptoa(&match->addr), 562285612Sdelphij match->dctx->name); 563285612Sdelphij dec_pending_ntp(spkt->dctx->name, &spkt->addr); 564285612Sdelphij free(spkt); 565285612Sdelphij return; 566285612Sdelphij } 567285612Sdelphij } 568132451Sroberto 569285612Sdelphij LINK_SLIST(*pkt_listp, spkt, link); 570132451Sroberto 571285612Sdelphij xctx = emalloc_zero(sizeof(*xctx)); 572285612Sdelphij xctx->sock = sock; 573285612Sdelphij xctx->spkt = spkt; 574285612Sdelphij gettimeofday_cached(base, &start_cb); 575285612Sdelphij xctx->sched = start_cb.tv_sec + (2 * xmt_delay); 576132451Sroberto 577285612Sdelphij LINK_SORT_SLIST(xmt_q, xctx, (xctx->sched < L_S_S_CUR()->sched), 578285612Sdelphij link, xmt_ctx); 579285612Sdelphij if (xmt_q == xctx) { 580285612Sdelphij /* 581285612Sdelphij * The new entry is the first scheduled. The timer is 582285612Sdelphij * either not active or is set for the second xmt 583285612Sdelphij * context in xmt_q. 584285612Sdelphij */ 585285612Sdelphij if (NULL == ev_xmt_timer) 586285612Sdelphij ev_xmt_timer = event_new(base, INVALID_SOCKET, 587285612Sdelphij EV_TIMEOUT, 588285612Sdelphij &xmt_timer_cb, NULL); 589285612Sdelphij if (NULL == ev_xmt_timer) { 590285612Sdelphij msyslog(LOG_ERR, 591285612Sdelphij "queue_xmt: event_new(base, -1, EV_TIMEOUT) failed!"); 592285612Sdelphij exit(1); 593285612Sdelphij } 594285612Sdelphij ZERO(delay); 595285612Sdelphij if (xctx->sched > start_cb.tv_sec) 596285612Sdelphij delay.tv_sec = xctx->sched - start_cb.tv_sec; 597285612Sdelphij event_add(ev_xmt_timer, &delay); 598285612Sdelphij TRACE(2, ("queue_xmt: xmt timer for %u usec\n", 599285612Sdelphij (u_int)delay.tv_usec)); 600285612Sdelphij } 601132451Sroberto} 602132451Sroberto 603132451Sroberto 604285612Sdelphij/* 605285612Sdelphij** xmt_timer_cb 606285612Sdelphij*/ 607285612Sdelphijvoid 608285612Sdelphijxmt_timer_cb( 609285612Sdelphij evutil_socket_t fd, 610285612Sdelphij short what, 611285612Sdelphij void * ctx 612285612Sdelphij ) 613285612Sdelphij{ 614285612Sdelphij struct timeval start_cb; 615285612Sdelphij struct timeval delay; 616285612Sdelphij xmt_ctx * x; 617132451Sroberto 618285612Sdelphij UNUSED_ARG(fd); 619285612Sdelphij UNUSED_ARG(ctx); 620285612Sdelphij DEBUG_INSIST(EV_TIMEOUT == what); 621132451Sroberto 622285612Sdelphij if (NULL == xmt_q || shutting_down) 623285612Sdelphij return; 624285612Sdelphij gettimeofday_cached(base, &start_cb); 625285612Sdelphij if (xmt_q->sched <= start_cb.tv_sec) { 626285612Sdelphij UNLINK_HEAD_SLIST(x, xmt_q, link); 627285612Sdelphij TRACE(2, ("xmt_timer_cb: at .%6.6u -> %s\n", 628285612Sdelphij (u_int)start_cb.tv_usec, stoa(&x->spkt->addr))); 629285612Sdelphij xmt(x); 630285612Sdelphij free(x); 631285612Sdelphij if (NULL == xmt_q) 632285612Sdelphij return; 633285612Sdelphij } 634285612Sdelphij if (xmt_q->sched <= start_cb.tv_sec) { 635285612Sdelphij event_add(ev_xmt_timer, &gap); 636285612Sdelphij TRACE(2, ("xmt_timer_cb: at .%6.6u gap %6.6u\n", 637285612Sdelphij (u_int)start_cb.tv_usec, 638285612Sdelphij (u_int)gap.tv_usec)); 639285612Sdelphij } else { 640285612Sdelphij delay.tv_sec = xmt_q->sched - start_cb.tv_sec; 641285612Sdelphij delay.tv_usec = 0; 642285612Sdelphij event_add(ev_xmt_timer, &delay); 643285612Sdelphij TRACE(2, ("xmt_timer_cb: at .%6.6u next %ld seconds\n", 644285612Sdelphij (u_int)start_cb.tv_usec, 645285612Sdelphij (long)delay.tv_sec)); 646285612Sdelphij } 647132451Sroberto} 648132451Sroberto 649132451Sroberto 650285612Sdelphij/* 651285612Sdelphij** xmt() 652285612Sdelphij*/ 653285612Sdelphijvoid 654285612Sdelphijxmt( 655285612Sdelphij xmt_ctx * xctx 656285612Sdelphij ) 657285612Sdelphij{ 658285612Sdelphij SOCKET sock = xctx->sock; 659285612Sdelphij struct dns_ctx *dctx = xctx->spkt->dctx; 660285612Sdelphij sent_pkt * spkt = xctx->spkt; 661285612Sdelphij sockaddr_u * dst = &spkt->addr; 662285612Sdelphij struct timeval tv_xmt; 663285612Sdelphij struct pkt x_pkt; 664285612Sdelphij size_t pkt_len; 665285612Sdelphij int sent; 666132451Sroberto 667285612Sdelphij if (0 != gettimeofday(&tv_xmt, NULL)) { 668285612Sdelphij msyslog(LOG_ERR, 669285612Sdelphij "xmt: gettimeofday() failed: %m"); 670285612Sdelphij exit(1); 671285612Sdelphij } 672285612Sdelphij tv_xmt.tv_sec += JAN_1970; 673132451Sroberto 674285612Sdelphij pkt_len = generate_pkt(&x_pkt, &tv_xmt, dctx->key_id, 675285612Sdelphij dctx->key); 676132451Sroberto 677285612Sdelphij sent = sendpkt(sock, dst, &x_pkt, pkt_len); 678285612Sdelphij if (sent) { 679285612Sdelphij /* Save the packet we sent... */ 680285612Sdelphij memcpy(&spkt->x_pkt, &x_pkt, min(sizeof(spkt->x_pkt), 681285612Sdelphij pkt_len)); 682285612Sdelphij spkt->stime = tv_xmt.tv_sec - JAN_1970; 683132451Sroberto 684285612Sdelphij TRACE(2, ("xmt: %lx.%6.6u %s %s\n", (u_long)tv_xmt.tv_sec, 685285612Sdelphij (u_int)tv_xmt.tv_usec, dctx->name, stoa(dst))); 686285612Sdelphij } else { 687285612Sdelphij dec_pending_ntp(dctx->name, dst); 688285612Sdelphij } 689132451Sroberto 690285612Sdelphij return; 691285612Sdelphij} 692132451Sroberto 693132451Sroberto 694285612Sdelphij/* 695285612Sdelphij * timeout_queries() -- give up on unrequited NTP queries 696285612Sdelphij */ 697285612Sdelphijvoid 698285612Sdelphijtimeout_queries(void) 699285612Sdelphij{ 700285612Sdelphij struct timeval start_cb; 701285612Sdelphij u_int idx; 702285612Sdelphij sent_pkt * head; 703285612Sdelphij sent_pkt * spkt; 704285612Sdelphij sent_pkt * spkt_next; 705285612Sdelphij long age; 706285612Sdelphij int didsomething = 0; 707132451Sroberto 708285612Sdelphij TRACE(3, ("timeout_queries: called to check %u items\n", 709285612Sdelphij (unsigned)COUNTOF(fam_listheads))); 710132451Sroberto 711285612Sdelphij gettimeofday_cached(base, &start_cb); 712285612Sdelphij for (idx = 0; idx < COUNTOF(fam_listheads); idx++) { 713285612Sdelphij head = fam_listheads[idx]; 714285612Sdelphij for (spkt = head; spkt != NULL; spkt = spkt_next) { 715285612Sdelphij char xcst; 716132451Sroberto 717285612Sdelphij didsomething = 1; 718285612Sdelphij switch (spkt->dctx->flags & CTX_xCST) { 719285612Sdelphij case CTX_BCST: 720285612Sdelphij xcst = 'B'; 721285612Sdelphij break; 722132451Sroberto 723285612Sdelphij case CTX_UCST: 724285612Sdelphij xcst = 'U'; 725285612Sdelphij break; 726132451Sroberto 727285612Sdelphij default: 728285612Sdelphij INSIST(!"spkt->dctx->flags neither UCST nor BCST"); 729285612Sdelphij break; 730285612Sdelphij } 731132451Sroberto 732285612Sdelphij spkt_next = spkt->link; 733285612Sdelphij if (0 == spkt->stime || spkt->done) 734285612Sdelphij continue; 735285612Sdelphij age = start_cb.tv_sec - spkt->stime; 736285612Sdelphij TRACE(3, ("%s %s %cCST age %ld\n", 737285612Sdelphij stoa(&spkt->addr), 738285612Sdelphij spkt->dctx->name, xcst, age)); 739285612Sdelphij if (age > response_timeout) 740285612Sdelphij timeout_query(spkt); 741285612Sdelphij } 742285612Sdelphij } 743285612Sdelphij // Do we care about didsomething? 744285612Sdelphij TRACE(3, ("timeout_queries: didsomething is %d, age is %ld\n", 745285612Sdelphij didsomething, (long) (start_cb.tv_sec - start_tv.tv_sec))); 746285612Sdelphij if (start_cb.tv_sec - start_tv.tv_sec > response_timeout) { 747285612Sdelphij TRACE(3, ("timeout_queries: bail!\n")); 748285612Sdelphij event_base_loopexit(base, NULL); 749285612Sdelphij shutting_down = TRUE; 750285612Sdelphij } 751132451Sroberto} 752132451Sroberto 753132451Sroberto 754285612Sdelphijvoid dec_pending_ntp( 755285612Sdelphij const char * name, 756285612Sdelphij sockaddr_u * server 757285612Sdelphij ) 758285612Sdelphij{ 759285612Sdelphij if (n_pending_ntp > 0) { 760285612Sdelphij --n_pending_ntp; 761285612Sdelphij check_exit_conditions(); 762285612Sdelphij } else { 763285612Sdelphij INSIST(0 == n_pending_ntp); 764285612Sdelphij TRACE(1, ("n_pending_ntp was zero before decrement for %s\n", 765285612Sdelphij hostnameaddr(name, server))); 766285612Sdelphij } 767285612Sdelphij} 768132451Sroberto 769132451Sroberto 770285612Sdelphijvoid timeout_query( 771285612Sdelphij sent_pkt * spkt 772285612Sdelphij ) 773285612Sdelphij{ 774285612Sdelphij sockaddr_u * server; 775285612Sdelphij char xcst; 776132451Sroberto 777132451Sroberto 778285612Sdelphij switch (spkt->dctx->flags & CTX_xCST) { 779285612Sdelphij case CTX_BCST: 780285612Sdelphij xcst = 'B'; 781285612Sdelphij break; 782132451Sroberto 783285612Sdelphij case CTX_UCST: 784285612Sdelphij xcst = 'U'; 785285612Sdelphij break; 786132451Sroberto 787285612Sdelphij default: 788285612Sdelphij INSIST(!"spkt->dctx->flags neither UCST nor BCST"); 789285612Sdelphij break; 790285612Sdelphij } 791285612Sdelphij spkt->done = TRUE; 792285612Sdelphij server = &spkt->addr; 793285612Sdelphij msyslog(LOG_INFO, "%s no %cCST response after %d seconds", 794285612Sdelphij hostnameaddr(spkt->dctx->name, server), xcst, 795285612Sdelphij response_timeout); 796285612Sdelphij dec_pending_ntp(spkt->dctx->name, server); 797285612Sdelphij return; 798285612Sdelphij} 799132451Sroberto 800132451Sroberto 801285612Sdelphij/* 802285612Sdelphij** check_kod 803285612Sdelphij*/ 804285612Sdelphijint 805285612Sdelphijcheck_kod( 806285612Sdelphij const struct addrinfo * ai 807285612Sdelphij ) 808285612Sdelphij{ 809285612Sdelphij char *hostname; 810285612Sdelphij struct kod_entry *reason; 811132451Sroberto 812285612Sdelphij /* Is there a KoD on file for this address? */ 813285612Sdelphij hostname = addrinfo_to_str(ai); 814285612Sdelphij TRACE(2, ("check_kod: checking <%s>\n", hostname)); 815285612Sdelphij if (search_entry(hostname, &reason)) { 816285612Sdelphij printf("prior KoD for %s, skipping.\n", 817285612Sdelphij hostname); 818285612Sdelphij free(reason); 819285612Sdelphij free(hostname); 820132451Sroberto 821285612Sdelphij return 1; 822285612Sdelphij } 823285612Sdelphij free(hostname); 824132451Sroberto 825285612Sdelphij return 0; 826132451Sroberto} 827132451Sroberto 828132451Sroberto 829285612Sdelphij/* 830285612Sdelphij** Socket readable/timeout Callback: 831285612Sdelphij** Read in the packet 832285612Sdelphij** Unicast: 833285612Sdelphij** - close socket 834285612Sdelphij** - decrement n_pending_ntp 835285612Sdelphij** - If packet is good, set the time and "exit" 836285612Sdelphij** Broadcast: 837285612Sdelphij** - If packet is good, set the time and "exit" 838285612Sdelphij*/ 839285612Sdelphijvoid 840285612Sdelphijsock_cb( 841285612Sdelphij evutil_socket_t fd, 842285612Sdelphij short what, 843285612Sdelphij void *ptr 844285612Sdelphij ) 845285612Sdelphij{ 846285612Sdelphij sockaddr_u sender; 847285612Sdelphij sockaddr_u * psau; 848285612Sdelphij sent_pkt ** p_pktlist; 849285612Sdelphij sent_pkt * spkt; 850285612Sdelphij int rpktl; 851285612Sdelphij int rc; 852132451Sroberto 853285612Sdelphij INSIST(sock4 == fd || sock6 == fd); 854132451Sroberto 855285612Sdelphij TRACE(3, ("sock_cb: event on sock%s:%s%s%s%s\n", 856285612Sdelphij (fd == sock6) 857285612Sdelphij ? "6" 858285612Sdelphij : "4", 859285612Sdelphij (what & EV_TIMEOUT) ? " timeout" : "", 860285612Sdelphij (what & EV_READ) ? " read" : "", 861285612Sdelphij (what & EV_WRITE) ? " write" : "", 862285612Sdelphij (what & EV_SIGNAL) ? " signal" : "")); 863132451Sroberto 864285612Sdelphij if (!(EV_READ & what)) { 865285612Sdelphij if (EV_TIMEOUT & what) 866285612Sdelphij timeout_queries(); 867132451Sroberto 868285612Sdelphij return; 869285612Sdelphij } 870132451Sroberto 871285612Sdelphij /* Read in the packet */ 872285612Sdelphij rpktl = recvdata(fd, &sender, &rbuf, sizeof(rbuf)); 873285612Sdelphij if (rpktl < 0) { 874285612Sdelphij msyslog(LOG_DEBUG, "recvfrom error %m"); 875285612Sdelphij return; 876285612Sdelphij } 877132451Sroberto 878285612Sdelphij if (sock6 == fd) 879285612Sdelphij p_pktlist = &v6_pkts_list; 880285612Sdelphij else 881285612Sdelphij p_pktlist = &v4_pkts_list; 882132451Sroberto 883285612Sdelphij for (spkt = *p_pktlist; spkt != NULL; spkt = spkt->link) { 884285612Sdelphij psau = &spkt->addr; 885285612Sdelphij if (SOCK_EQ(&sender, psau)) 886285612Sdelphij break; 887285612Sdelphij } 888285612Sdelphij if (NULL == spkt) { 889285612Sdelphij msyslog(LOG_WARNING, 890285612Sdelphij "Packet from unexpected source %s dropped", 891285612Sdelphij sptoa(&sender)); 892285612Sdelphij return; 893285612Sdelphij } 894132451Sroberto 895285612Sdelphij TRACE(1, ("sock_cb: %s %s\n", spkt->dctx->name, 896285612Sdelphij sptoa(&sender))); 897132451Sroberto 898285612Sdelphij rpktl = process_pkt(&r_pkt, &sender, rpktl, MODE_SERVER, 899285612Sdelphij &spkt->x_pkt, "sock_cb"); 900132451Sroberto 901285612Sdelphij TRACE(2, ("sock_cb: process_pkt returned %d\n", rpktl)); 902132451Sroberto 903285612Sdelphij /* If this is a Unicast packet, one down ... */ 904285612Sdelphij if (!spkt->done && (CTX_UCST & spkt->dctx->flags)) { 905285612Sdelphij dec_pending_ntp(spkt->dctx->name, &spkt->addr); 906285612Sdelphij spkt->done = TRUE; 907285612Sdelphij } 908132451Sroberto 909132451Sroberto 910285612Sdelphij /* If the packet is good, set the time and we're all done */ 911285612Sdelphij rc = handle_pkt(rpktl, &r_pkt, &spkt->addr, spkt->dctx->name); 912285612Sdelphij if (0 != rc) 913285612Sdelphij TRACE(1, ("sock_cb: handle_pkt() returned %d\n", rc)); 914285612Sdelphij check_exit_conditions(); 915285612Sdelphij} 916132451Sroberto 917132451Sroberto 918285612Sdelphij/* 919285612Sdelphij * check_exit_conditions() 920285612Sdelphij * 921285612Sdelphij * If sntp has a reply, ask the event loop to stop after this round of 922285612Sdelphij * callbacks, unless --wait was used. 923285612Sdelphij */ 924285612Sdelphijvoid 925285612Sdelphijcheck_exit_conditions(void) 926285612Sdelphij{ 927285612Sdelphij if ((0 == n_pending_ntp && 0 == n_pending_dns) || 928285612Sdelphij (time_derived && !HAVE_OPT(WAIT))) { 929285612Sdelphij event_base_loopexit(base, NULL); 930285612Sdelphij shutting_down = TRUE; 931285612Sdelphij } else { 932285612Sdelphij TRACE(2, ("%d NTP and %d name queries pending\n", 933285612Sdelphij n_pending_ntp, n_pending_dns)); 934285612Sdelphij } 935285612Sdelphij} 936132451Sroberto 937132451Sroberto 938285612Sdelphij/* 939285612Sdelphij * sntp_addremove_fd() is invoked by the intres blocking worker code 940285612Sdelphij * to read from a pipe, or to stop same. 941285612Sdelphij */ 942285612Sdelphijvoid sntp_addremove_fd( 943285612Sdelphij int fd, 944285612Sdelphij int is_pipe, 945285612Sdelphij int remove_it 946285612Sdelphij ) 947285612Sdelphij{ 948285612Sdelphij u_int idx; 949285612Sdelphij blocking_child *c; 950285612Sdelphij struct event * ev; 951132451Sroberto 952285612Sdelphij#ifdef HAVE_SOCKETPAIR 953285612Sdelphij if (is_pipe) { 954285612Sdelphij /* sntp only asks for EV_FEATURE_FDS without HAVE_SOCKETPAIR */ 955285612Sdelphij msyslog(LOG_ERR, "fatal: pipes not supported on systems with socketpair()"); 956285612Sdelphij exit(1); 957285612Sdelphij } 958285612Sdelphij#endif 959132451Sroberto 960285612Sdelphij c = NULL; 961285612Sdelphij for (idx = 0; idx < blocking_children_alloc; idx++) { 962285612Sdelphij c = blocking_children[idx]; 963285612Sdelphij if (NULL == c) 964285612Sdelphij continue; 965285612Sdelphij if (fd == c->resp_read_pipe) 966285612Sdelphij break; 967285612Sdelphij } 968285612Sdelphij if (idx == blocking_children_alloc) 969285612Sdelphij return; 970132451Sroberto 971285612Sdelphij if (remove_it) { 972285612Sdelphij ev = c->resp_read_ctx; 973285612Sdelphij c->resp_read_ctx = NULL; 974285612Sdelphij event_del(ev); 975285612Sdelphij event_free(ev); 976132451Sroberto 977285612Sdelphij return; 978285612Sdelphij } 979132451Sroberto 980285612Sdelphij ev = event_new(base, fd, EV_READ | EV_PERSIST, 981285612Sdelphij &worker_resp_cb, c); 982285612Sdelphij if (NULL == ev) { 983285612Sdelphij msyslog(LOG_ERR, 984285612Sdelphij "sntp_addremove_fd: event_new(base, fd) failed!"); 985285612Sdelphij return; 986285612Sdelphij } 987285612Sdelphij c->resp_read_ctx = ev; 988285612Sdelphij event_add(ev, NULL); 989285612Sdelphij} 990132451Sroberto 991132451Sroberto 992285612Sdelphij/* called by forked intres child to close open descriptors */ 993285612Sdelphij#ifdef WORK_FORK 994285612Sdelphijvoid 995285612Sdelphijkill_asyncio( 996285612Sdelphij int startfd 997285612Sdelphij ) 998285612Sdelphij{ 999285612Sdelphij if (INVALID_SOCKET != sock4) { 1000285612Sdelphij closesocket(sock4); 1001285612Sdelphij sock4 = INVALID_SOCKET; 1002285612Sdelphij } 1003285612Sdelphij if (INVALID_SOCKET != sock6) { 1004285612Sdelphij closesocket(sock6); 1005285612Sdelphij sock6 = INVALID_SOCKET; 1006285612Sdelphij } 1007285612Sdelphij if (INVALID_SOCKET != bsock4) { 1008285612Sdelphij closesocket(sock4); 1009285612Sdelphij sock4 = INVALID_SOCKET; 1010285612Sdelphij } 1011285612Sdelphij if (INVALID_SOCKET != bsock6) { 1012285612Sdelphij closesocket(sock6); 1013285612Sdelphij sock6 = INVALID_SOCKET; 1014285612Sdelphij } 1015285612Sdelphij} 1016285612Sdelphij#endif 1017132451Sroberto 1018132451Sroberto 1019285612Sdelphij/* 1020285612Sdelphij * worker_resp_cb() is invoked when resp_read_pipe is readable. 1021285612Sdelphij */ 1022285612Sdelphijvoid 1023285612Sdelphijworker_resp_cb( 1024285612Sdelphij evutil_socket_t fd, 1025285612Sdelphij short what, 1026285612Sdelphij void * ctx /* blocking_child * */ 1027285612Sdelphij ) 1028285612Sdelphij{ 1029285612Sdelphij blocking_child * c; 1030132451Sroberto 1031285612Sdelphij DEBUG_INSIST(EV_READ & what); 1032285612Sdelphij c = ctx; 1033285612Sdelphij DEBUG_INSIST(fd == c->resp_read_pipe); 1034285612Sdelphij process_blocking_resp(c); 1035132451Sroberto} 1036132451Sroberto 1037132451Sroberto 1038285612Sdelphij/* 1039285612Sdelphij * intres_timeout_req(s) is invoked in the parent to schedule an idle 1040285612Sdelphij * timeout to fire in s seconds, if not reset earlier by a call to 1041285612Sdelphij * intres_timeout_req(0), which clears any pending timeout. When the 1042285612Sdelphij * timeout expires, worker_idle_timer_fired() is invoked (again, in the 1043285612Sdelphij * parent). 1044285612Sdelphij * 1045285612Sdelphij * sntp and ntpd each provide implementations adapted to their timers. 1046285612Sdelphij */ 1047285612Sdelphijvoid 1048285612Sdelphijintres_timeout_req( 1049285612Sdelphij u_int seconds /* 0 cancels */ 1050285612Sdelphij ) 1051285612Sdelphij{ 1052285612Sdelphij struct timeval tv_to; 1053132451Sroberto 1054285612Sdelphij if (NULL == ev_worker_timeout) { 1055285612Sdelphij ev_worker_timeout = event_new(base, -1, 1056285612Sdelphij EV_TIMEOUT | EV_PERSIST, 1057285612Sdelphij &worker_timeout, NULL); 1058285612Sdelphij DEBUG_INSIST(NULL != ev_worker_timeout); 1059285612Sdelphij } else { 1060285612Sdelphij event_del(ev_worker_timeout); 1061285612Sdelphij } 1062285612Sdelphij if (0 == seconds) 1063285612Sdelphij return; 1064285612Sdelphij tv_to.tv_sec = seconds; 1065285612Sdelphij tv_to.tv_usec = 0; 1066285612Sdelphij event_add(ev_worker_timeout, &tv_to); 1067285612Sdelphij} 1068132451Sroberto 1069132451Sroberto 1070285612Sdelphijvoid 1071285612Sdelphijworker_timeout( 1072285612Sdelphij evutil_socket_t fd, 1073285612Sdelphij short what, 1074285612Sdelphij void * ctx 1075285612Sdelphij ) 1076285612Sdelphij{ 1077285612Sdelphij UNUSED_ARG(fd); 1078285612Sdelphij UNUSED_ARG(ctx); 1079132451Sroberto 1080285612Sdelphij DEBUG_REQUIRE(EV_TIMEOUT & what); 1081285612Sdelphij worker_idle_timer_fired(); 1082132451Sroberto} 1083132451Sroberto 1084132451Sroberto 1085285612Sdelphijvoid 1086285612Sdelphijsntp_libevent_log_cb( 1087285612Sdelphij int severity, 1088285612Sdelphij const char * msg 1089285612Sdelphij ) 1090285612Sdelphij{ 1091285612Sdelphij int level; 1092132451Sroberto 1093285612Sdelphij switch (severity) { 1094132451Sroberto 1095285612Sdelphij default: 1096285612Sdelphij case _EVENT_LOG_DEBUG: 1097285612Sdelphij level = LOG_DEBUG; 1098285612Sdelphij break; 1099132451Sroberto 1100285612Sdelphij case _EVENT_LOG_MSG: 1101285612Sdelphij level = LOG_NOTICE; 1102285612Sdelphij break; 1103132451Sroberto 1104285612Sdelphij case _EVENT_LOG_WARN: 1105285612Sdelphij level = LOG_WARNING; 1106285612Sdelphij break; 1107132451Sroberto 1108285612Sdelphij case _EVENT_LOG_ERR: 1109285612Sdelphij level = LOG_ERR; 1110285612Sdelphij break; 1111285612Sdelphij } 1112132451Sroberto 1113285612Sdelphij msyslog(level, "%s", msg); 1114285612Sdelphij} 1115132451Sroberto 1116132451Sroberto 1117285612Sdelphijint 1118285612Sdelphijgenerate_pkt ( 1119285612Sdelphij struct pkt *x_pkt, 1120285612Sdelphij const struct timeval *tv_xmt, 1121285612Sdelphij int key_id, 1122285612Sdelphij struct key *pkt_key 1123285612Sdelphij ) 1124285612Sdelphij{ 1125285612Sdelphij l_fp xmt_fp; 1126285612Sdelphij int pkt_len; 1127285612Sdelphij int mac_size; 1128132451Sroberto 1129285612Sdelphij pkt_len = LEN_PKT_NOMAC; 1130285612Sdelphij ZERO(*x_pkt); 1131285612Sdelphij TVTOTS(tv_xmt, &xmt_fp); 1132285612Sdelphij HTONL_FP(&xmt_fp, &x_pkt->xmt); 1133285612Sdelphij x_pkt->stratum = STRATUM_TO_PKT(STRATUM_UNSPEC); 1134285612Sdelphij x_pkt->ppoll = 8; 1135285612Sdelphij /* FIXME! Modus broadcast + adr. check -> bdr. pkt */ 1136285612Sdelphij set_li_vn_mode(x_pkt, LEAP_NOTINSYNC, ntpver, 3); 1137330567Sgordon if (debug > 0) { 1138330567Sgordon printf("generate_pkt: key_id %d, key pointer %p\n", key_id, pkt_key); 1139330567Sgordon } 1140285612Sdelphij if (pkt_key != NULL) { 1141285612Sdelphij x_pkt->exten[0] = htonl(key_id); 1142330567Sgordon mac_size = make_mac(x_pkt, pkt_len, MAX_MDG_LEN, 1143285612Sdelphij pkt_key, (char *)&x_pkt->exten[1]); 1144285612Sdelphij if (mac_size > 0) 1145330567Sgordon pkt_len += mac_size + KEY_MAC_LEN; 1146330567Sgordon#ifdef DEBUG 1147330567Sgordon if (debug > 0) { 1148330567Sgordon printf("generate_pkt: mac_size is %d\n", mac_size); 1149330567Sgordon } 1150330567Sgordon#endif 1151330567Sgordon 1152285612Sdelphij } 1153285612Sdelphij return pkt_len; 1154285612Sdelphij} 1155132451Sroberto 1156132451Sroberto 1157285612Sdelphijint 1158285612Sdelphijhandle_pkt( 1159285612Sdelphij int rpktl, 1160285612Sdelphij struct pkt * rpkt, 1161285612Sdelphij sockaddr_u * host, 1162285612Sdelphij const char * hostname 1163285612Sdelphij ) 1164285612Sdelphij{ 1165285612Sdelphij char disptxt[32]; 1166285612Sdelphij const char * addrtxt; 1167285612Sdelphij struct timeval tv_dst; 1168285612Sdelphij int cnt; 1169285612Sdelphij int sw_case; 1170285612Sdelphij int digits; 1171285612Sdelphij int stratum; 1172285612Sdelphij char * ref; 1173285612Sdelphij char * ts_str; 1174285612Sdelphij const char * leaptxt; 1175285612Sdelphij double offset; 1176285612Sdelphij double precision; 1177285612Sdelphij double synch_distance; 1178285612Sdelphij char * p_SNTP_PRETEND_TIME; 1179285612Sdelphij time_t pretend_time; 1180285612Sdelphij#if SIZEOF_TIME_T == 8 1181285612Sdelphij long long ll; 1182285612Sdelphij#else 1183285612Sdelphij long l; 1184285612Sdelphij#endif 1185132451Sroberto 1186285612Sdelphij ts_str = NULL; 1187132451Sroberto 1188285612Sdelphij if (rpktl > 0) 1189285612Sdelphij sw_case = 1; 1190285612Sdelphij else 1191285612Sdelphij sw_case = rpktl; 1192132451Sroberto 1193285612Sdelphij switch (sw_case) { 1194132451Sroberto 1195285612Sdelphij case SERVER_UNUSEABLE: 1196285612Sdelphij return -1; 1197285612Sdelphij break; 1198132451Sroberto 1199285612Sdelphij case PACKET_UNUSEABLE: 1200285612Sdelphij break; 1201132451Sroberto 1202285612Sdelphij case SERVER_AUTH_FAIL: 1203285612Sdelphij break; 1204132451Sroberto 1205285612Sdelphij case KOD_DEMOBILIZE: 1206285612Sdelphij /* Received a DENY or RESTR KOD packet */ 1207285612Sdelphij addrtxt = stoa(host); 1208285612Sdelphij ref = (char *)&rpkt->refid; 1209285612Sdelphij add_entry(addrtxt, ref); 1210285612Sdelphij msyslog(LOG_WARNING, "KOD code %c%c%c%c from %s %s", 1211285612Sdelphij ref[0], ref[1], ref[2], ref[3], addrtxt, hostname); 1212285612Sdelphij break; 1213132451Sroberto 1214285612Sdelphij case KOD_RATE: 1215285612Sdelphij /* 1216285612Sdelphij ** Hmm... 1217285612Sdelphij ** We should probably call add_entry() with an 1218285612Sdelphij ** expiration timestamp of several seconds in the future, 1219285612Sdelphij ** and back-off even more if we get more RATE responses. 1220285612Sdelphij */ 1221285612Sdelphij break; 1222132451Sroberto 1223285612Sdelphij case 1: 1224285612Sdelphij TRACE(3, ("handle_pkt: %d bytes from %s %s\n", 1225285612Sdelphij rpktl, stoa(host), hostname)); 1226132451Sroberto 1227285612Sdelphij gettimeofday_cached(base, &tv_dst); 1228132451Sroberto 1229285612Sdelphij p_SNTP_PRETEND_TIME = getenv("SNTP_PRETEND_TIME"); 1230285612Sdelphij if (p_SNTP_PRETEND_TIME) { 1231285612Sdelphij pretend_time = 0; 1232285612Sdelphij#if SIZEOF_TIME_T == 4 1233285612Sdelphij if (1 == sscanf(p_SNTP_PRETEND_TIME, "%ld", &l)) 1234285612Sdelphij pretend_time = (time_t)l; 1235285612Sdelphij#elif SIZEOF_TIME_T == 8 1236285612Sdelphij if (1 == sscanf(p_SNTP_PRETEND_TIME, "%lld", &ll)) 1237285612Sdelphij pretend_time = (time_t)ll; 1238285612Sdelphij#else 1239285612Sdelphij# include "GRONK: unexpected value for SIZEOF_TIME_T" 1240285612Sdelphij#endif 1241285612Sdelphij if (0 != pretend_time) 1242285612Sdelphij tv_dst.tv_sec = pretend_time; 1243285612Sdelphij } 1244132451Sroberto 1245285612Sdelphij offset_calculation(rpkt, rpktl, &tv_dst, &offset, 1246285612Sdelphij &precision, &synch_distance); 1247285612Sdelphij time_derived = TRUE; 1248132451Sroberto 1249285612Sdelphij for (digits = 0; (precision *= 10.) < 1.; ++digits) 1250285612Sdelphij /* empty */ ; 1251285612Sdelphij if (digits > 6) 1252285612Sdelphij digits = 6; 1253132451Sroberto 1254285612Sdelphij ts_str = tv_to_str(&tv_dst); 1255285612Sdelphij stratum = rpkt->stratum; 1256285612Sdelphij if (0 == stratum) 1257285612Sdelphij stratum = 16; 1258132451Sroberto 1259285612Sdelphij if (synch_distance > 0.) { 1260285612Sdelphij cnt = snprintf(disptxt, sizeof(disptxt), 1261285612Sdelphij " +/- %f", synch_distance); 1262285612Sdelphij if ((size_t)cnt >= sizeof(disptxt)) 1263285612Sdelphij snprintf(disptxt, sizeof(disptxt), 1264285612Sdelphij "ERROR %d >= %d", cnt, 1265285612Sdelphij (int)sizeof(disptxt)); 1266285612Sdelphij } else { 1267285612Sdelphij disptxt[0] = '\0'; 1268285612Sdelphij } 1269132451Sroberto 1270285612Sdelphij switch (PKT_LEAP(rpkt->li_vn_mode)) { 1271285612Sdelphij case LEAP_NOWARNING: 1272285612Sdelphij leaptxt = "no-leap"; 1273285612Sdelphij break; 1274285612Sdelphij case LEAP_ADDSECOND: 1275285612Sdelphij leaptxt = "add-leap"; 1276285612Sdelphij break; 1277285612Sdelphij case LEAP_DELSECOND: 1278285612Sdelphij leaptxt = "del-leap"; 1279285612Sdelphij break; 1280285612Sdelphij case LEAP_NOTINSYNC: 1281285612Sdelphij leaptxt = "unsync"; 1282285612Sdelphij break; 1283285612Sdelphij default: 1284285612Sdelphij leaptxt = "LEAP-ERROR"; 1285285612Sdelphij break; 1286285612Sdelphij } 1287132451Sroberto 1288285612Sdelphij msyslog(LOG_INFO, "%s %+.*f%s %s s%d %s%s", ts_str, 1289285612Sdelphij digits, offset, disptxt, 1290285612Sdelphij hostnameaddr(hostname, host), stratum, 1291285612Sdelphij leaptxt, 1292285612Sdelphij (time_adjusted) 1293285612Sdelphij ? " [excess]" 1294285612Sdelphij : ""); 1295285612Sdelphij free(ts_str); 1296132451Sroberto 1297285612Sdelphij if (p_SNTP_PRETEND_TIME) 1298285612Sdelphij return 0; 1299132451Sroberto 1300285612Sdelphij if (!time_adjusted && 1301285612Sdelphij (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW))) 1302285612Sdelphij return set_time(offset); 1303132451Sroberto 1304285612Sdelphij return EX_OK; 1305285612Sdelphij } 1306132451Sroberto 1307285612Sdelphij return 1; 1308285612Sdelphij} 1309132451Sroberto 1310132451Sroberto 1311285612Sdelphijvoid 1312285612Sdelphijoffset_calculation( 1313285612Sdelphij struct pkt *rpkt, 1314285612Sdelphij int rpktl, 1315285612Sdelphij struct timeval *tv_dst, 1316285612Sdelphij double *offset, 1317285612Sdelphij double *precision, 1318285612Sdelphij double *synch_distance 1319285612Sdelphij ) 1320285612Sdelphij{ 1321285612Sdelphij l_fp p_rec, p_xmt, p_ref, p_org, tmp, dst; 1322285612Sdelphij u_fp p_rdly, p_rdsp; 1323285612Sdelphij double t21, t34, delta; 1324132451Sroberto 1325285612Sdelphij /* Convert timestamps from network to host byte order */ 1326285612Sdelphij p_rdly = NTOHS_FP(rpkt->rootdelay); 1327285612Sdelphij p_rdsp = NTOHS_FP(rpkt->rootdisp); 1328285612Sdelphij NTOHL_FP(&rpkt->reftime, &p_ref); 1329285612Sdelphij NTOHL_FP(&rpkt->org, &p_org); 1330285612Sdelphij NTOHL_FP(&rpkt->rec, &p_rec); 1331285612Sdelphij NTOHL_FP(&rpkt->xmt, &p_xmt); 1332132451Sroberto 1333285612Sdelphij *precision = LOGTOD(rpkt->precision); 1334132451Sroberto 1335285612Sdelphij TRACE(3, ("offset_calculation: LOGTOD(rpkt->precision): %f\n", *precision)); 1336132451Sroberto 1337285612Sdelphij /* Compute offset etc. */ 1338285612Sdelphij tmp = p_rec; 1339285612Sdelphij L_SUB(&tmp, &p_org); 1340285612Sdelphij LFPTOD(&tmp, t21); 1341285612Sdelphij TVTOTS(tv_dst, &dst); 1342285612Sdelphij dst.l_ui += JAN_1970; 1343285612Sdelphij tmp = p_xmt; 1344285612Sdelphij L_SUB(&tmp, &dst); 1345285612Sdelphij LFPTOD(&tmp, t34); 1346285612Sdelphij *offset = (t21 + t34) / 2.; 1347285612Sdelphij delta = t21 - t34; 1348132451Sroberto 1349285612Sdelphij // synch_distance is: 1350285612Sdelphij // (peer->delay + peer->rootdelay) / 2 + peer->disp 1351285612Sdelphij // + peer->rootdisp + clock_phi * (current_time - peer->update) 1352285612Sdelphij // + peer->jitter; 1353285612Sdelphij // 1354285612Sdelphij // and peer->delay = fabs(peer->offset - p_offset) * 2; 1355285612Sdelphij // and peer->offset needs history, so we're left with 1356285612Sdelphij // p_offset = (t21 + t34) / 2.; 1357285612Sdelphij // peer->disp = 0; (we have no history to augment this) 1358285612Sdelphij // clock_phi = 15e-6; 1359285612Sdelphij // peer->jitter = LOGTOD(sys_precision); (we have no history to augment this) 1360285612Sdelphij // and ntp_proto.c:set_sys_tick_precision() should get us sys_precision. 1361285612Sdelphij // 1362285612Sdelphij // so our answer seems to be: 1363285612Sdelphij // 1364285612Sdelphij // (fabs(t21 + t34) + peer->rootdelay) / 3. 1365285612Sdelphij // + 0 (peer->disp) 1366285612Sdelphij // + peer->rootdisp 1367285612Sdelphij // + 15e-6 (clock_phi) 1368285612Sdelphij // + LOGTOD(sys_precision) 1369132451Sroberto 1370285612Sdelphij INSIST( FPTOD(p_rdly) >= 0. ); 1371285612Sdelphij#if 1 1372285612Sdelphij *synch_distance = (fabs(t21 + t34) + FPTOD(p_rdly)) / 3. 1373285612Sdelphij + 0. 1374285612Sdelphij + FPTOD(p_rdsp) 1375285612Sdelphij + 15e-6 1376285612Sdelphij + 0. /* LOGTOD(sys_precision) when we can get it */ 1377285612Sdelphij ; 1378285612Sdelphij INSIST( *synch_distance >= 0. ); 1379285612Sdelphij#else 1380285612Sdelphij *synch_distance = (FPTOD(p_rdly) + FPTOD(p_rdsp))/2.0; 1381285612Sdelphij#endif 1382132451Sroberto 1383285612Sdelphij#ifdef DEBUG 1384285612Sdelphij if (debug > 3) { 1385285612Sdelphij printf("sntp rootdelay: %f\n", FPTOD(p_rdly)); 1386285612Sdelphij printf("sntp rootdisp: %f\n", FPTOD(p_rdsp)); 1387285612Sdelphij printf("sntp syncdist: %f\n", *synch_distance); 1388132451Sroberto 1389285612Sdelphij pkt_output(rpkt, rpktl, stdout); 1390132451Sroberto 1391285612Sdelphij printf("sntp offset_calculation: rpkt->reftime:\n"); 1392285612Sdelphij l_fp_output(&p_ref, stdout); 1393285612Sdelphij printf("sntp offset_calculation: rpkt->org:\n"); 1394285612Sdelphij l_fp_output(&p_org, stdout); 1395285612Sdelphij printf("sntp offset_calculation: rpkt->rec:\n"); 1396285612Sdelphij l_fp_output(&p_rec, stdout); 1397285612Sdelphij printf("sntp offset_calculation: rpkt->xmt:\n"); 1398285612Sdelphij l_fp_output(&p_xmt, stdout); 1399285612Sdelphij } 1400285612Sdelphij#endif 1401132451Sroberto 1402285612Sdelphij TRACE(3, ("sntp offset_calculation:\trec - org t21: %.6f\n" 1403285612Sdelphij "\txmt - dst t34: %.6f\tdelta: %.6f\toffset: %.6f\n", 1404285612Sdelphij t21, t34, delta, *offset)); 1405132451Sroberto 1406285612Sdelphij return; 1407285612Sdelphij} 1408132451Sroberto 1409132451Sroberto 1410132451Sroberto 1411285612Sdelphij/* Compute the 8 bits for li_vn_mode */ 1412285612Sdelphijvoid 1413285612Sdelphijset_li_vn_mode ( 1414285612Sdelphij struct pkt *spkt, 1415285612Sdelphij char leap, 1416285612Sdelphij char version, 1417285612Sdelphij char mode 1418285612Sdelphij ) 1419285612Sdelphij{ 1420285612Sdelphij if (leap > 3) { 1421285612Sdelphij msyslog(LOG_DEBUG, "set_li_vn_mode: leap > 3, using max. 3"); 1422285612Sdelphij leap = 3; 1423285612Sdelphij } 1424132451Sroberto 1425285612Sdelphij if ((unsigned char)version > 7) { 1426285612Sdelphij msyslog(LOG_DEBUG, "set_li_vn_mode: version < 0 or > 7, using 4"); 1427285612Sdelphij version = 4; 1428285612Sdelphij } 1429132451Sroberto 1430285612Sdelphij if (mode > 7) { 1431285612Sdelphij msyslog(LOG_DEBUG, "set_li_vn_mode: mode > 7, using client mode 3"); 1432285612Sdelphij mode = 3; 1433285612Sdelphij } 1434132451Sroberto 1435285612Sdelphij spkt->li_vn_mode = leap << 6; 1436285612Sdelphij spkt->li_vn_mode |= version << 3; 1437285612Sdelphij spkt->li_vn_mode |= mode; 1438132451Sroberto} 1439132451Sroberto 1440132451Sroberto 1441285612Sdelphij/* 1442285612Sdelphij** set_time applies 'offset' to the local clock. 1443285612Sdelphij*/ 1444285612Sdelphijint 1445285612Sdelphijset_time( 1446285612Sdelphij double offset 1447285612Sdelphij ) 1448285612Sdelphij{ 1449285612Sdelphij int rc; 1450132451Sroberto 1451285612Sdelphij if (time_adjusted) 1452285612Sdelphij return EX_OK; 1453132451Sroberto 1454285612Sdelphij /* 1455285612Sdelphij ** If we can step but we cannot slew, then step. 1456285612Sdelphij ** If we can step or slew and and |offset| > steplimit, then step. 1457285612Sdelphij */ 1458285612Sdelphij if (ENABLED_OPT(STEP) && 1459285612Sdelphij ( !ENABLED_OPT(SLEW) 1460285612Sdelphij || (ENABLED_OPT(SLEW) && (fabs(offset) > steplimit)) 1461285612Sdelphij )) { 1462285612Sdelphij rc = step_systime(offset); 1463132451Sroberto 1464285612Sdelphij /* If there was a problem, can we rely on errno? */ 1465285612Sdelphij if (1 == rc) 1466285612Sdelphij time_adjusted = TRUE; 1467285612Sdelphij return (time_adjusted) 1468285612Sdelphij ? EX_OK 1469285612Sdelphij : 1; 1470285612Sdelphij /* 1471285612Sdelphij ** In case of error, what should we use? 1472285612Sdelphij ** EX_UNAVAILABLE? 1473285612Sdelphij ** EX_OSERR? 1474285612Sdelphij ** EX_NOPERM? 1475285612Sdelphij */ 1476285612Sdelphij } 1477132451Sroberto 1478285612Sdelphij if (ENABLED_OPT(SLEW)) { 1479285612Sdelphij rc = adj_systime(offset); 1480132451Sroberto 1481285612Sdelphij /* If there was a problem, can we rely on errno? */ 1482285612Sdelphij if (1 == rc) 1483285612Sdelphij time_adjusted = TRUE; 1484285612Sdelphij return (time_adjusted) 1485285612Sdelphij ? EX_OK 1486285612Sdelphij : 1; 1487285612Sdelphij /* 1488285612Sdelphij ** In case of error, what should we use? 1489285612Sdelphij ** EX_UNAVAILABLE? 1490285612Sdelphij ** EX_OSERR? 1491285612Sdelphij ** EX_NOPERM? 1492285612Sdelphij */ 1493285612Sdelphij } 1494132451Sroberto 1495285612Sdelphij return EX_SOFTWARE; 1496285612Sdelphij} 1497132451Sroberto 1498132451Sroberto 1499285612Sdelphijint 1500285612Sdelphijlibevent_version_ok(void) 1501285612Sdelphij{ 1502285612Sdelphij ev_uint32_t v_compile_maj; 1503285612Sdelphij ev_uint32_t v_run_maj; 1504132451Sroberto 1505285612Sdelphij v_compile_maj = LIBEVENT_VERSION_NUMBER & 0xffff0000; 1506285612Sdelphij v_run_maj = event_get_version_number() & 0xffff0000; 1507285612Sdelphij if (v_compile_maj != v_run_maj) { 1508285612Sdelphij fprintf(stderr, 1509285612Sdelphij "Incompatible libevent versions: have %s, built with %s\n", 1510285612Sdelphij event_get_version(), 1511285612Sdelphij LIBEVENT_VERSION); 1512285612Sdelphij return 0; 1513285612Sdelphij } 1514285612Sdelphij return 1; 1515285612Sdelphij} 1516132451Sroberto 1517285612Sdelphij/* 1518285612Sdelphij * gettimeofday_cached() 1519285612Sdelphij * 1520285612Sdelphij * Clones the event_base_gettimeofday_cached() interface but ensures the 1521285612Sdelphij * times are always on the gettimeofday() 1970 scale. Older libevent 2 1522285612Sdelphij * sometimes used gettimeofday(), sometimes the since-system-start 1523285612Sdelphij * clock_gettime(CLOCK_MONOTONIC), depending on the platform. 1524285612Sdelphij * 1525285612Sdelphij * It is not cleanly possible to tell which timescale older libevent is 1526285612Sdelphij * using. 1527285612Sdelphij * 1528285612Sdelphij * The strategy involves 1 hour thresholds chosen to be far longer than 1529285612Sdelphij * the duration of a round of libevent callbacks, which share a cached 1530285612Sdelphij * start-of-round time. First compare the last cached time with the 1531285612Sdelphij * current gettimeofday() time. If they are within one hour, libevent 1532285612Sdelphij * is using the proper timescale so leave the offset 0. Otherwise, 1533285612Sdelphij * compare libevent's cached time and the current time on the monotonic 1534285612Sdelphij * scale. If they are within an hour, libevent is using the monotonic 1535285612Sdelphij * scale so calculate the offset to add to such times to bring them to 1536285612Sdelphij * gettimeofday()'s scale. 1537285612Sdelphij */ 1538285612Sdelphijint 1539285612Sdelphijgettimeofday_cached( 1540285612Sdelphij struct event_base * b, 1541285612Sdelphij struct timeval * caller_tv 1542285612Sdelphij ) 1543285612Sdelphij{ 1544285612Sdelphij#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 1545285612Sdelphij static struct event_base * cached_b; 1546285612Sdelphij static struct timeval cached; 1547285612Sdelphij static struct timeval adj_cached; 1548285612Sdelphij static struct timeval offset; 1549285612Sdelphij static int offset_ready; 1550285612Sdelphij struct timeval latest; 1551285612Sdelphij struct timeval systemt; 1552285612Sdelphij struct timespec ts; 1553285612Sdelphij struct timeval mono; 1554285612Sdelphij struct timeval diff; 1555285612Sdelphij int cgt_rc; 1556285612Sdelphij int gtod_rc; 1557132451Sroberto 1558285612Sdelphij event_base_gettimeofday_cached(b, &latest); 1559285612Sdelphij if (b == cached_b && 1560285612Sdelphij !memcmp(&latest, &cached, sizeof(latest))) { 1561285612Sdelphij *caller_tv = adj_cached; 1562285612Sdelphij return 0; 1563285612Sdelphij } 1564285612Sdelphij cached = latest; 1565285612Sdelphij cached_b = b; 1566285612Sdelphij if (!offset_ready) { 1567285612Sdelphij cgt_rc = clock_gettime(CLOCK_MONOTONIC, &ts); 1568285612Sdelphij gtod_rc = gettimeofday(&systemt, NULL); 1569285612Sdelphij if (0 != gtod_rc) { 1570285612Sdelphij msyslog(LOG_ERR, 1571285612Sdelphij "%s: gettimeofday() error %m", 1572285612Sdelphij progname); 1573285612Sdelphij exit(1); 1574285612Sdelphij } 1575285612Sdelphij diff = sub_tval(systemt, latest); 1576285612Sdelphij if (debug > 1) 1577285612Sdelphij printf("system minus cached %+ld.%06ld\n", 1578285612Sdelphij (long)diff.tv_sec, (long)diff.tv_usec); 1579285612Sdelphij if (0 != cgt_rc || labs((long)diff.tv_sec) < 3600) { 1580285612Sdelphij /* 1581285612Sdelphij * Either use_monotonic == 0, or this libevent 1582285612Sdelphij * has been repaired. Leave offset at zero. 1583285612Sdelphij */ 1584285612Sdelphij } else { 1585285612Sdelphij mono.tv_sec = ts.tv_sec; 1586285612Sdelphij mono.tv_usec = ts.tv_nsec / 1000; 1587285612Sdelphij diff = sub_tval(latest, mono); 1588285612Sdelphij if (debug > 1) 1589285612Sdelphij printf("cached minus monotonic %+ld.%06ld\n", 1590285612Sdelphij (long)diff.tv_sec, (long)diff.tv_usec); 1591285612Sdelphij if (labs((long)diff.tv_sec) < 3600) { 1592285612Sdelphij /* older libevent2 using monotonic */ 1593285612Sdelphij offset = sub_tval(systemt, mono); 1594285612Sdelphij TRACE(1, ("%s: Offsetting libevent CLOCK_MONOTONIC times by %+ld.%06ld\n", 1595285612Sdelphij "gettimeofday_cached", 1596285612Sdelphij (long)offset.tv_sec, 1597285612Sdelphij (long)offset.tv_usec)); 1598285612Sdelphij } 1599285612Sdelphij } 1600285612Sdelphij offset_ready = TRUE; 1601285612Sdelphij } 1602285612Sdelphij adj_cached = add_tval(cached, offset); 1603285612Sdelphij *caller_tv = adj_cached; 1604132451Sroberto 1605285612Sdelphij return 0; 1606285612Sdelphij#else 1607285612Sdelphij return event_base_gettimeofday_cached(b, caller_tv); 1608285612Sdelphij#endif 1609132451Sroberto} 1610132451Sroberto 1611