main.c revision 294554
1161748Scperciva#include <config.h> 2161748Scperciva 3161748Scperciva#include <event2/util.h> 4173441Scperciva#include <event2/event.h> 5161748Scperciva 6161748Scperciva#include "ntp_workimpl.h" 7161748Scperciva#ifdef WORK_THREAD 8161748Scperciva# include <event2/thread.h> 9161748Scperciva#endif 10161748Scperciva 11161748Scperciva#include "main.h" 12161748Scperciva#include "ntp_libopts.h" 13161748Scperciva#include "kod_management.h" 14161748Scperciva#include "networking.h" 15161748Scperciva#include "utilities.h" 16161748Scperciva#include "log.h" 17161748Scperciva#include "libntp.h" 18161748Scperciva 19161748Scperciva 20161748Scpercivaint shutting_down; 21161748Scpercivaint time_derived; 22161748Scpercivaint time_adjusted; 23161748Scpercivaint n_pending_dns = 0; 24161748Scpercivaint n_pending_ntp = 0; 25161748Scpercivaint ai_fam_pref = AF_UNSPEC; 26161748Scpercivaint ntpver = 4; 27161748Scpercivadouble steplimit = -1; 28161748ScpercivaSOCKET sock4 = -1; /* Socket for IPv4 */ 29161748ScpercivaSOCKET sock6 = -1; /* Socket for IPv6 */ 30161748Scperciva/* 31161748Scperciva** BCAST *must* listen on port 123 (by default), so we can only 32161748Scperciva** use the UCST sockets (above) if they too are using port 123 33161748Scperciva*/ 34161748ScpercivaSOCKET bsock4 = -1; /* Broadcast Socket for IPv4 */ 35161748ScpercivaSOCKET bsock6 = -1; /* Broadcast Socket for IPv6 */ 36161748Scpercivastruct event_base *base; 37161748Scpercivastruct event *ev_sock4; 38161748Scpercivastruct event *ev_sock6; 39161748Scpercivastruct event *ev_worker_timeout; 40161748Scpercivastruct event *ev_xmt_timer; 41161748Scperciva 42161748Scpercivastruct dns_ctx { 43161748Scperciva const char * name; 44161748Scperciva int flags; 45161748Scperciva#define CTX_BCST 0x0001 46161748Scperciva#define CTX_UCST 0x0002 47173564Scperciva#define CTX_xCST 0x0003 48161748Scperciva#define CTX_CONC 0x0004 49161748Scperciva#define CTX_unused 0xfffd 50161748Scperciva int key_id; 51161748Scperciva struct timeval timeout; 52161748Scperciva struct key * key; 53161748Scperciva}; 54161748Scperciva 55161748Scpercivatypedef struct sent_pkt_tag sent_pkt; 56173564Scpercivastruct sent_pkt_tag { 57173564Scperciva sent_pkt * link; 58161748Scperciva struct dns_ctx * dctx; 59181142Scperciva sockaddr_u addr; 60161748Scperciva time_t stime; 61161748Scperciva int done; 62161748Scperciva struct pkt x_pkt; 63161748Scperciva}; 64161748Scperciva 65161748Scpercivatypedef struct xmt_ctx_tag xmt_ctx; 66161748Scpercivastruct xmt_ctx_tag { 67161748Scperciva xmt_ctx * link; 68161748Scperciva SOCKET sock; 69161748Scperciva time_t sched; 70161748Scperciva sent_pkt * spkt; 71161748Scperciva}; 72161748Scperciva 73161748Scpercivastruct timeval gap; 74161748Scpercivaxmt_ctx * xmt_q; 75161748Scpercivastruct key * keys = NULL; 76161748Scpercivaint response_timeout; 77161748Scpercivastruct timeval response_tv; 78161748Scpercivastruct timeval start_tv; 79161748Scperciva/* check the timeout at least once per second */ 80161748Scpercivastruct timeval wakeup_tv = { 0, 888888 }; 81161748Scperciva 82161748Scpercivasent_pkt * fam_listheads[2]; 83161748Scperciva#define v4_pkts_list (fam_listheads[0]) 84161748Scperciva#define v6_pkts_list (fam_listheads[1]) 85161748Scperciva 86161748Scpercivastatic union { 87161748Scperciva struct pkt pkt; 88161748Scperciva char buf[LEN_PKT_NOMAC + NTP_MAXEXTEN + MAX_MAC_LEN]; 89161748Scperciva} rbuf; 90181142Scperciva 91196392Ssimon#define r_pkt rbuf.pkt 92161748Scperciva 93161748Scperciva#ifdef HAVE_DROPROOT 94161748Scpercivaint droproot; /* intres imports these */ 95161748Scpercivaint root_dropped; 96161748Scperciva#endif 97161748Scpercivau_long current_time; /* libntp/authkeys.c */ 98161748Scperciva 99161748Scpercivavoid open_sockets(void); 100161748Scpercivavoid handle_lookup(const char *name, int flags); 101161748Scpercivavoid sntp_addremove_fd(int fd, int is_pipe, int remove_it); 102161748Scpercivavoid worker_timeout(evutil_socket_t, short, void *); 103161748Scpercivavoid worker_resp_cb(evutil_socket_t, short, void *); 104161748Scpercivavoid sntp_name_resolved(int, int, void *, const char *, const char *, 105161748Scperciva const struct addrinfo *, 106161748Scperciva const struct addrinfo *); 107161748Scpercivavoid queue_xmt(SOCKET sock, struct dns_ctx *dctx, sent_pkt *spkt, 108161748Scperciva u_int xmt_delay); 109161748Scpercivavoid xmt_timer_cb(evutil_socket_t, short, void *ptr); 110161748Scpercivavoid xmt(xmt_ctx *xctx); 111161748Scpercivaint check_kod(const struct addrinfo *ai); 112161748Scpercivavoid timeout_query(sent_pkt *); 113161748Scpercivavoid timeout_queries(void); 114161748Scpercivavoid sock_cb(evutil_socket_t, short, void *); 115161748Scpercivavoid check_exit_conditions(void); 116161748Scpercivavoid sntp_libevent_log_cb(int, const char *); 117161748Scpercivavoid set_li_vn_mode(struct pkt *spkt, char leap, char version, char mode); 118161748Scpercivaint set_time(double offset); 119161748Scpercivavoid dec_pending_ntp(const char *, sockaddr_u *); 120161748Scpercivaint libevent_version_ok(void); 121161748Scpercivaint gettimeofday_cached(struct event_base *b, struct timeval *tv); 122161748Scperciva 123161748Scperciva 124161748Scperciva/* 125161748Scperciva * The actual main function. 126161748Scperciva */ 127161748Scpercivaint 128161748Scpercivasntp_main ( 129161748Scperciva int argc, 130161748Scperciva char **argv, 131161748Scperciva const char *sntpVersion 132161748Scperciva ) 133161748Scperciva{ 134161748Scperciva int i; 135161748Scperciva int exitcode; 136161748Scperciva int optct; 137161748Scperciva struct event_config * evcfg; 138161748Scperciva 139161748Scperciva /* Initialize logging system - sets up progname */ 140161748Scperciva sntp_init_logging(argv[0]); 141161748Scperciva 142161748Scperciva if (!libevent_version_ok()) 143161748Scperciva exit(EX_SOFTWARE); 144161748Scperciva 145161748Scperciva init_lib(); 146161748Scperciva init_auth(); 147161748Scperciva 148161748Scperciva optct = ntpOptionProcess(&sntpOptions, argc, argv); 149161748Scperciva argc -= optct; 150161748Scperciva argv += optct; 151161748Scperciva 152161748Scperciva 153161748Scperciva debug = OPT_VALUE_SET_DEBUG_LEVEL; 154161748Scperciva 155161748Scperciva TRACE(2, ("init_lib() done, %s%s\n", 156161748Scperciva (ipv4_works) 157161748Scperciva ? "ipv4_works " 158161748Scperciva : "", 159161748Scperciva (ipv6_works) 160161748Scperciva ? "ipv6_works " 161161748Scperciva : "")); 162161748Scperciva ntpver = OPT_VALUE_NTPVERSION; 163161748Scperciva steplimit = OPT_VALUE_STEPLIMIT / 1e3; 164161748Scperciva gap.tv_usec = max(0, OPT_VALUE_GAP * 1000); 165161748Scperciva gap.tv_usec = min(gap.tv_usec, 999999); 166161748Scperciva 167161748Scperciva if (HAVE_OPT(LOGFILE)) 168161748Scperciva open_logfile(OPT_ARG(LOGFILE)); 169161748Scperciva 170161748Scperciva msyslog(LOG_INFO, "%s", sntpVersion); 171161748Scperciva 172161748Scperciva if (0 == argc && !HAVE_OPT(BROADCAST) && !HAVE_OPT(CONCURRENT)) { 173161748Scperciva printf("%s: Must supply at least one of -b hostname, -c hostname, or hostname.\n", 174161748Scperciva progname); 175161748Scperciva exit(EX_USAGE); 176161748Scperciva } 177161748Scperciva 178161748Scperciva 179161748Scperciva /* 180161748Scperciva ** Eventually, we probably want: 181161748Scperciva ** - separate bcst and ucst timeouts (why?) 182161748Scperciva ** - multiple --timeout values in the commandline 183161748Scperciva */ 184161748Scperciva 185161748Scperciva response_timeout = OPT_VALUE_TIMEOUT; 186161748Scperciva response_tv.tv_sec = response_timeout; 187161748Scperciva response_tv.tv_usec = 0; 188161748Scperciva 189161748Scperciva /* IPv6 available? */ 190161748Scperciva if (isc_net_probeipv6() != ISC_R_SUCCESS) { 191161748Scperciva ai_fam_pref = AF_INET; 192161748Scperciva TRACE(1, ("No ipv6 support available, forcing ipv4\n")); 193161748Scperciva } else { 194161748Scperciva /* Check for options -4 and -6 */ 195161748Scperciva if (HAVE_OPT(IPV4)) 196161748Scperciva ai_fam_pref = AF_INET; 197161748Scperciva else if (HAVE_OPT(IPV6)) 198161748Scperciva ai_fam_pref = AF_INET6; 199161748Scperciva } 200161748Scperciva 201161748Scperciva /* TODO: Parse config file if declared */ 202161748Scperciva 203161748Scperciva /* 204161748Scperciva ** Init the KOD system. 205161748Scperciva ** For embedded systems with no writable filesystem, 206161748Scperciva ** -K /dev/null can be used to disable KoD storage. 207161748Scperciva */ 208161748Scperciva kod_init_kod_db(OPT_ARG(KOD), FALSE); 209161748Scperciva 210161748Scperciva // HMS: Should we use arg-defalt for this too? 211161748Scperciva if (HAVE_OPT(KEYFILE)) 212161748Scperciva auth_init(OPT_ARG(KEYFILE), &keys); 213161748Scperciva 214161748Scperciva /* 215161748Scperciva ** Considering employing a variable that prevents functions of doing 216161748Scperciva ** anything until everything is initialized properly 217161748Scperciva ** 218161748Scperciva ** HMS: What exactly does the above mean? 219161748Scperciva */ 220161748Scperciva event_set_log_callback(&sntp_libevent_log_cb); 221161748Scperciva if (debug > 0) 222161748Scperciva event_enable_debug_mode(); 223161748Scperciva#ifdef WORK_THREAD 224161748Scperciva evthread_use_pthreads(); 225161748Scperciva /* we use libevent from main thread only, locks should be academic */ 226161748Scperciva if (debug > 0) 227181142Scperciva evthread_enable_lock_debuging(); 228181142Scperciva#endif 229181142Scperciva evcfg = event_config_new(); 230181142Scperciva if (NULL == evcfg) { 231181142Scperciva printf("%s: event_config_new() failed!\n", progname); 232181142Scperciva return -1; 233181142Scperciva } 234161748Scperciva#ifndef HAVE_SOCKETPAIR 235161748Scperciva event_config_require_features(evcfg, EV_FEATURE_FDS); 236161748Scperciva#endif 237161748Scperciva /* all libevent calls are from main thread */ 238161748Scperciva /* event_config_set_flag(evcfg, EVENT_BASE_FLAG_NOLOCK); */ 239161748Scperciva base = event_base_new_with_config(evcfg); 240161748Scperciva event_config_free(evcfg); 241161748Scperciva if (NULL == base) { 242173564Scperciva printf("%s: event_base_new() failed!\n", progname); 243173564Scperciva return -1; 244173564Scperciva } 245173564Scperciva 246173564Scperciva /* wire into intres resolver */ 247173564Scperciva worker_per_query = TRUE; 248173564Scperciva addremove_io_fd = &sntp_addremove_fd; 249173564Scperciva 250161748Scperciva open_sockets(); 251161748Scperciva 252161748Scperciva if (HAVE_OPT(BROADCAST)) { 253161748Scperciva int cn = STACKCT_OPT( BROADCAST ); 254161748Scperciva const char ** cp = STACKLST_OPT( BROADCAST ); 255161748Scperciva 256161748Scperciva while (cn-- > 0) { 257161748Scperciva handle_lookup(*cp, CTX_BCST); 258161748Scperciva cp++; 259173564Scperciva } 260173564Scperciva } 261173564Scperciva 262173564Scperciva if (HAVE_OPT(CONCURRENT)) { 263173564Scperciva int cn = STACKCT_OPT( CONCURRENT ); 264173564Scperciva const char ** cp = STACKLST_OPT( CONCURRENT ); 265173564Scperciva 266173564Scperciva while (cn-- > 0) { 267173564Scperciva handle_lookup(*cp, CTX_UCST | CTX_CONC); 268173564Scperciva cp++; 269173564Scperciva } 270173564Scperciva } 271173564Scperciva 272173564Scperciva for (i = 0; i < argc; ++i) 273173564Scperciva handle_lookup(argv[i], CTX_UCST); 274173564Scperciva 275173564Scperciva gettimeofday_cached(base, &start_tv); 276173564Scperciva event_base_dispatch(base); 277173564Scperciva event_base_free(base); 278173564Scperciva 279173564Scperciva if (!time_adjusted && 280173564Scperciva (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW))) 281173564Scperciva exitcode = 1; 282173564Scperciva else 283173564Scperciva exitcode = 0; 284173564Scperciva 285173564Scperciva return exitcode; 286173564Scperciva} 287173564Scperciva 288173564Scperciva 289161748Scperciva/* 290161748Scperciva** open sockets and make them non-blocking 291161748Scperciva*/ 292161748Scpercivavoid 293161748Scpercivaopen_sockets( 294161748Scperciva void 295161748Scperciva ) 296161748Scperciva{ 297161748Scperciva sockaddr_u name; 298161748Scperciva 299161748Scperciva if (-1 == sock4) { 300161748Scperciva sock4 = socket(PF_INET, SOCK_DGRAM, 0); 301161748Scperciva if (-1 == sock4) { 302161748Scperciva /* error getting a socket */ 303161748Scperciva msyslog(LOG_ERR, "open_sockets: socket(PF_INET) failed: %m"); 304161748Scperciva exit(1); 305161748Scperciva } 306161748Scperciva /* Make it non-blocking */ 307161748Scperciva make_socket_nonblocking(sock4); 308161748Scperciva 309161748Scperciva /* Let's try using a wildcard... */ 310161748Scperciva ZERO(name); 311196392Ssimon AF(&name) = AF_INET; 312196392Ssimon SET_ADDR4N(&name, INADDR_ANY); 313196392Ssimon SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0)); 314196392Ssimon 315196392Ssimon if (-1 == bind(sock4, &name.sa, 316196392Ssimon SOCKLEN(&name))) { 317196392Ssimon msyslog(LOG_ERR, "open_sockets: bind(sock4) failed: %m"); 318196392Ssimon exit(1); 319196392Ssimon } 320196392Ssimon 321196392Ssimon /* Register an NTP callback for recv/timeout */ 322196392Ssimon ev_sock4 = event_new(base, sock4, 323196392Ssimon EV_TIMEOUT | EV_READ | EV_PERSIST, 324196392Ssimon &sock_cb, NULL); 325196392Ssimon if (NULL == ev_sock4) { 326196392Ssimon msyslog(LOG_ERR, 327196392Ssimon "open_sockets: event_new(base, sock4) failed!"); 328196392Ssimon } else { 329196392Ssimon event_add(ev_sock4, &wakeup_tv); 330196392Ssimon } 331196392Ssimon } 332196392Ssimon 333196392Ssimon /* We may not always have IPv6... */ 334196392Ssimon if (-1 == sock6 && ipv6_works) { 335196392Ssimon sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 336196392Ssimon if (-1 == sock6 && ipv6_works) { 337196392Ssimon /* error getting a socket */ 338196392Ssimon msyslog(LOG_ERR, "open_sockets: socket(PF_INET6) failed: %m"); 339196392Ssimon exit(1); 340196392Ssimon } 341196392Ssimon /* Make it non-blocking */ 342196392Ssimon make_socket_nonblocking(sock6); 343196392Ssimon 344196392Ssimon /* Let's try using a wildcard... */ 345196392Ssimon ZERO(name); 346196392Ssimon AF(&name) = AF_INET6; 347196392Ssimon SET_ADDR6N(&name, in6addr_any); 348196392Ssimon SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0)); 349196392Ssimon 350196392Ssimon if (-1 == bind(sock6, &name.sa, 351196392Ssimon SOCKLEN(&name))) { 352196392Ssimon msyslog(LOG_ERR, "open_sockets: bind(sock6) failed: %m"); 353196392Ssimon exit(1); 354196392Ssimon } 355196392Ssimon /* Register an NTP callback for recv/timeout */ 356196392Ssimon ev_sock6 = event_new(base, sock6, 357196392Ssimon EV_TIMEOUT | EV_READ | EV_PERSIST, 358196392Ssimon &sock_cb, NULL); 359196392Ssimon if (NULL == ev_sock6) { 360196392Ssimon msyslog(LOG_ERR, 361196392Ssimon "open_sockets: event_new(base, sock6) failed!"); 362196392Ssimon } else { 363196392Ssimon event_add(ev_sock6, &wakeup_tv); 364196392Ssimon } 365196392Ssimon } 366196392Ssimon 367196392Ssimon return; 368196392Ssimon} 369196392Ssimon 370196392Ssimon 371196392Ssimon/* 372196392Ssimon** handle_lookup 373196392Ssimon*/ 374196392Ssimonvoid 375161748Scpercivahandle_lookup( 376161748Scperciva const char *name, 377161748Scperciva int flags 378161748Scperciva ) 379161748Scperciva{ 380161748Scperciva struct addrinfo hints; /* Local copy is OK */ 381161748Scperciva struct dns_ctx *ctx; 382161748Scperciva long l; 383161748Scperciva char * name_copy; 384161748Scperciva size_t name_sz; 385161748Scperciva size_t octets; 386161748Scperciva 387161748Scperciva TRACE(1, ("handle_lookup(%s,%#x)\n", name, flags)); 388161748Scperciva 389161748Scperciva ZERO(hints); 390161748Scperciva hints.ai_family = ai_fam_pref; 391161748Scperciva hints.ai_flags = AI_CANONNAME | Z_AI_NUMERICSERV; 392161748Scperciva /* 393161748Scperciva ** Unless we specify a socktype, we'll get at least two 394161748Scperciva ** entries for each address: one for TCP and one for 395161748Scperciva ** UDP. That's not what we want. 396161748Scperciva */ 397161748Scperciva hints.ai_socktype = SOCK_DGRAM; 398161748Scperciva hints.ai_protocol = IPPROTO_UDP; 399161748Scperciva 400161748Scperciva name_sz = 1 + strlen(name); 401161748Scperciva octets = sizeof(*ctx) + name_sz; // Space for a ctx and the name 402161748Scperciva ctx = emalloc_zero(octets); // ctx at ctx[0] 403161748Scperciva name_copy = (char *)(ctx + 1); // Put the name at ctx[1] 404161748Scperciva memcpy(name_copy, name, name_sz); // copy the name to ctx[1] 405161748Scperciva ctx->name = name_copy; // point to it... 406161748Scperciva ctx->flags = flags; 407161748Scperciva ctx->timeout = response_tv; 408161748Scperciva 409161748Scperciva /* The following should arguably be passed in... */ 410161748Scperciva if (ENABLED_OPT(AUTHENTICATION) && 411161748Scperciva atoint(OPT_ARG(AUTHENTICATION), &l)) { 412161748Scperciva ctx->key_id = l; 413161748Scperciva get_key(ctx->key_id, &ctx->key); 414161748Scperciva } else { 415161748Scperciva ctx->key_id = -1; 416161748Scperciva ctx->key = NULL; 417161748Scperciva } 418161748Scperciva 419161748Scperciva ++n_pending_dns; 420161748Scperciva getaddrinfo_sometime(name, "123", &hints, 0, 421161748Scperciva &sntp_name_resolved, ctx); 422161748Scperciva} 423161748Scperciva 424161748Scperciva 425161748Scperciva/* 426161748Scperciva** DNS Callback: 427161748Scperciva** - For each IP: 428161748Scperciva** - - open a socket 429173564Scperciva** - - increment n_pending_ntp 430173564Scperciva** - - send a request if this is a Unicast callback 431173564Scperciva** - - queue wait for response 432173564Scperciva** - decrement n_pending_dns 433161748Scperciva*/ 434161748Scpercivavoid 435161748Scpercivasntp_name_resolved( 436161748Scperciva int rescode, 437161748Scperciva int gai_errno, 438161748Scperciva void * context, 439161748Scperciva const char * name, 440161748Scperciva const char * service, 441161748Scperciva const struct addrinfo * hints, 442161748Scperciva const struct addrinfo * addr 443161748Scperciva ) 444161748Scperciva{ 445161748Scperciva struct dns_ctx * dctx; 446161748Scperciva sent_pkt * spkt; 447161748Scperciva const struct addrinfo * ai; 448161748Scperciva SOCKET sock; 449161748Scperciva u_int xmt_delay_v4; 450161748Scperciva u_int xmt_delay_v6; 451181142Scperciva u_int xmt_delay; 452161748Scperciva size_t octets; 453161748Scperciva 454161748Scperciva xmt_delay_v4 = 0; 455161748Scperciva xmt_delay_v6 = 0; 456161748Scperciva dctx = context; 457161748Scperciva if (rescode) { 458161748Scperciva#ifdef EAI_SYSTEM 459161748Scperciva if (EAI_SYSTEM == rescode) { 460161748Scperciva errno = gai_errno; 461161748Scperciva mfprintf(stderr, "%s lookup error %m\n", 462161748Scperciva dctx->name); 463161748Scperciva } else 464161748Scperciva#endif 465161748Scperciva fprintf(stderr, "%s lookup error %s\n", 466161748Scperciva dctx->name, gai_strerror(rescode)); 467161748Scperciva } else { 468161748Scperciva TRACE(3, ("%s [%s]\n", dctx->name, 469161748Scperciva (addr->ai_canonname != NULL) 470161748Scperciva ? addr->ai_canonname 471161748Scperciva : "")); 472161748Scperciva 473161748Scperciva for (ai = addr; ai != NULL; ai = ai->ai_next) { 474161748Scperciva 475161748Scperciva if (check_kod(ai)) 476161748Scperciva continue; 477161748Scperciva 478161748Scperciva switch (ai->ai_family) { 479161748Scperciva 480161748Scperciva case AF_INET: 481161748Scperciva sock = sock4; 482161748Scperciva xmt_delay = xmt_delay_v4; 483161748Scperciva xmt_delay_v4++; 484161748Scperciva break; 485161748Scperciva 486161748Scperciva case AF_INET6: 487161748Scperciva if (!ipv6_works) 488161748Scperciva continue; 489161748Scperciva 490161748Scperciva sock = sock6; 491161748Scperciva xmt_delay = xmt_delay_v6; 492161748Scperciva xmt_delay_v6++; 493161748Scperciva break; 494161748Scperciva 495161748Scperciva default: 496161748Scperciva msyslog(LOG_ERR, "sntp_name_resolved: unexpected ai_family: %d", 497161748Scperciva ai->ai_family); 498161748Scperciva exit(1); 499161748Scperciva break; 500161748Scperciva } 501161748Scperciva 502161748Scperciva /* 503161748Scperciva ** We're waiting for a response for either unicast 504161748Scperciva ** or broadcast, so... 505161748Scperciva */ 506161748Scperciva ++n_pending_ntp; 507161748Scperciva 508161748Scperciva /* If this is for a unicast IP, queue a request */ 509161748Scperciva if (dctx->flags & CTX_UCST) { 510161748Scperciva spkt = emalloc_zero(sizeof(*spkt)); 511161748Scperciva spkt->dctx = dctx; 512161748Scperciva octets = min(ai->ai_addrlen, sizeof(spkt->addr)); 513161748Scperciva memcpy(&spkt->addr, ai->ai_addr, octets); 514161748Scperciva queue_xmt(sock, dctx, spkt, xmt_delay); 515161748Scperciva } 516161748Scperciva } 517161748Scperciva } 518161748Scperciva /* n_pending_dns really should be >0 here... */ 519161748Scperciva --n_pending_dns; 520161748Scperciva check_exit_conditions(); 521161748Scperciva} 522161748Scperciva 523161748Scperciva 524161748Scperciva/* 525161748Scperciva** queue_xmt 526161748Scperciva*/ 527173564Scpercivavoid 528196392Ssimonqueue_xmt( 529196392Ssimon SOCKET sock, 530196392Ssimon struct dns_ctx * dctx, 531161748Scperciva sent_pkt * spkt, 532161748Scperciva u_int xmt_delay 533161748Scperciva ) 534161748Scperciva{ 535161748Scperciva sockaddr_u * dest; 536161748Scperciva sent_pkt ** pkt_listp; 537161748Scperciva sent_pkt * match; 538161748Scperciva xmt_ctx * xctx; 539161748Scperciva struct timeval start_cb; 540161748Scperciva struct timeval delay; 541161748Scperciva 542161748Scperciva dest = &spkt->addr; 543161748Scperciva if (IS_IPV6(dest)) 544161748Scperciva pkt_listp = &v6_pkts_list; 545161748Scperciva else 546161748Scperciva pkt_listp = &v4_pkts_list; 547161748Scperciva 548161748Scperciva /* reject attempts to add address already listed */ 549161748Scperciva for (match = *pkt_listp; match != NULL; match = match->link) { 550161748Scperciva if (ADDR_PORT_EQ(&spkt->addr, &match->addr)) { 551161748Scperciva if (strcasecmp(spkt->dctx->name, 552161748Scperciva match->dctx->name)) 553161748Scperciva printf("%s %s duplicate address from %s ignored.\n", 554161748Scperciva sptoa(&match->addr), 555161748Scperciva match->dctx->name, 556161748Scperciva spkt->dctx->name); 557161748Scperciva else 558161748Scperciva printf("%s %s, duplicate address ignored.\n", 559161748Scperciva sptoa(&match->addr), 560161748Scperciva match->dctx->name); 561161748Scperciva dec_pending_ntp(spkt->dctx->name, &spkt->addr); 562161748Scperciva free(spkt); 563161748Scperciva return; 564161748Scperciva } 565161748Scperciva } 566161748Scperciva 567161748Scperciva LINK_SLIST(*pkt_listp, spkt, link); 568161748Scperciva 569161748Scperciva xctx = emalloc_zero(sizeof(*xctx)); 570161748Scperciva xctx->sock = sock; 571161748Scperciva xctx->spkt = spkt; 572161748Scperciva gettimeofday_cached(base, &start_cb); 573161748Scperciva xctx->sched = start_cb.tv_sec + (2 * xmt_delay); 574161748Scperciva 575161748Scperciva LINK_SORT_SLIST(xmt_q, xctx, (xctx->sched < L_S_S_CUR()->sched), 576161748Scperciva link, xmt_ctx); 577161748Scperciva if (xmt_q == xctx) { 578161748Scperciva /* 579161748Scperciva * The new entry is the first scheduled. The timer is 580161748Scperciva * either not active or is set for the second xmt 581161748Scperciva * context in xmt_q. 582161748Scperciva */ 583161748Scperciva if (NULL == ev_xmt_timer) 584161748Scperciva ev_xmt_timer = event_new(base, INVALID_SOCKET, 585161748Scperciva EV_TIMEOUT, 586161748Scperciva &xmt_timer_cb, NULL); 587161748Scperciva if (NULL == ev_xmt_timer) { 588161748Scperciva msyslog(LOG_ERR, 589161748Scperciva "queue_xmt: event_new(base, -1, EV_TIMEOUT) failed!"); 590161748Scperciva exit(1); 591161748Scperciva } 592161748Scperciva ZERO(delay); 593161748Scperciva if (xctx->sched > start_cb.tv_sec) 594161748Scperciva delay.tv_sec = xctx->sched - start_cb.tv_sec; 595161748Scperciva event_add(ev_xmt_timer, &delay); 596161748Scperciva TRACE(2, ("queue_xmt: xmt timer for %u usec\n", 597161748Scperciva (u_int)delay.tv_usec)); 598161748Scperciva } 599161748Scperciva} 600161748Scperciva 601161748Scperciva 602161748Scperciva/* 603161748Scperciva** xmt_timer_cb 604161748Scperciva*/ 605161748Scpercivavoid 606161748Scpercivaxmt_timer_cb( 607161748Scperciva evutil_socket_t fd, 608161748Scperciva short what, 609161748Scperciva void * ctx 610161748Scperciva ) 611161748Scperciva{ 612161748Scperciva struct timeval start_cb; 613161748Scperciva struct timeval delay; 614173564Scperciva xmt_ctx * x; 615161748Scperciva 616161748Scperciva UNUSED_ARG(fd); 617161748Scperciva UNUSED_ARG(ctx); 618161748Scperciva DEBUG_INSIST(EV_TIMEOUT == what); 619161748Scperciva 620161748Scperciva if (NULL == xmt_q || shutting_down) 621161748Scperciva return; 622161748Scperciva gettimeofday_cached(base, &start_cb); 623161748Scperciva if (xmt_q->sched <= start_cb.tv_sec) { 624167189Scperciva UNLINK_HEAD_SLIST(x, xmt_q, link); 625167189Scperciva TRACE(2, ("xmt_timer_cb: at .%6.6u -> %s\n", 626167189Scperciva (u_int)start_cb.tv_usec, stoa(&x->spkt->addr))); 627167189Scperciva xmt(x); 628167189Scperciva free(x); 629167189Scperciva if (NULL == xmt_q) 630167189Scperciva return; 631167189Scperciva } 632167189Scperciva if (xmt_q->sched <= start_cb.tv_sec) { 633167189Scperciva event_add(ev_xmt_timer, &gap); 634167189Scperciva TRACE(2, ("xmt_timer_cb: at .%6.6u gap %6.6u\n", 635167189Scperciva (u_int)start_cb.tv_usec, 636167189Scperciva (u_int)gap.tv_usec)); 637167189Scperciva } else { 638167189Scperciva delay.tv_sec = xmt_q->sched - start_cb.tv_sec; 639167189Scperciva delay.tv_usec = 0; 640167189Scperciva event_add(ev_xmt_timer, &delay); 641167189Scperciva TRACE(2, ("xmt_timer_cb: at .%6.6u next %ld seconds\n", 642161748Scperciva (u_int)start_cb.tv_usec, 643161748Scperciva (long)delay.tv_sec)); 644161748Scperciva } 645161748Scperciva} 646161748Scperciva 647161748Scperciva 648161748Scperciva/* 649161748Scperciva** xmt() 650161748Scperciva*/ 651161748Scpercivavoid 652161748Scpercivaxmt( 653161748Scperciva xmt_ctx * xctx 654173564Scperciva ) 655173564Scperciva{ 656173564Scperciva SOCKET sock = xctx->sock; 657173564Scperciva struct dns_ctx *dctx = xctx->spkt->dctx; 658173564Scperciva sent_pkt * spkt = xctx->spkt; 659173564Scperciva sockaddr_u * dst = &spkt->addr; 660173564Scperciva struct timeval tv_xmt; 661173564Scperciva struct pkt x_pkt; 662173564Scperciva size_t pkt_len; 663173564Scperciva int sent; 664173564Scperciva 665173564Scperciva if (0 != gettimeofday(&tv_xmt, NULL)) { 666173564Scperciva msyslog(LOG_ERR, 667173564Scperciva "xmt: gettimeofday() failed: %m"); 668173564Scperciva exit(1); 669173564Scperciva } 670173564Scperciva tv_xmt.tv_sec += JAN_1970; 671173564Scperciva 672173564Scperciva pkt_len = generate_pkt(&x_pkt, &tv_xmt, dctx->key_id, 673173564Scperciva dctx->key); 674173564Scperciva 675173564Scperciva sent = sendpkt(sock, dst, &x_pkt, pkt_len); 676173564Scperciva if (sent) { 677173564Scperciva /* Save the packet we sent... */ 678173564Scperciva memcpy(&spkt->x_pkt, &x_pkt, min(sizeof(spkt->x_pkt), 679173564Scperciva pkt_len)); 680173564Scperciva spkt->stime = tv_xmt.tv_sec - JAN_1970; 681173564Scperciva 682173564Scperciva TRACE(2, ("xmt: %lx.%6.6u %s %s\n", (u_long)tv_xmt.tv_sec, 683173564Scperciva (u_int)tv_xmt.tv_usec, dctx->name, stoa(dst))); 684173564Scperciva } else { 685173564Scperciva dec_pending_ntp(dctx->name, dst); 686173564Scperciva } 687173564Scperciva 688173564Scperciva return; 689173564Scperciva} 690173564Scperciva 691173564Scperciva 692173564Scperciva/* 693173564Scperciva * timeout_queries() -- give up on unrequited NTP queries 694161748Scperciva */ 695161748Scpercivavoid 696161748Scpercivatimeout_queries(void) 697161748Scperciva{ 698161748Scperciva struct timeval start_cb; 699161748Scperciva u_int idx; 700161748Scperciva sent_pkt * head; 701161748Scperciva sent_pkt * spkt; 702161748Scperciva sent_pkt * spkt_next; 703173441Scperciva long age; 704173441Scperciva int didsomething = 0; 705173441Scperciva 706173441Scperciva TRACE(3, ("timeout_queries: called to check %u items\n", 707173441Scperciva (unsigned)COUNTOF(fam_listheads))); 708173441Scperciva 709173441Scperciva gettimeofday_cached(base, &start_cb); 710161748Scperciva for (idx = 0; idx < COUNTOF(fam_listheads); idx++) { 711161748Scperciva head = fam_listheads[idx]; 712161748Scperciva for (spkt = head; spkt != NULL; spkt = spkt_next) { 713161748Scperciva char xcst; 714161748Scperciva 715161748Scperciva didsomething = 1; 716161748Scperciva switch (spkt->dctx->flags & CTX_xCST) { 717161748Scperciva case CTX_BCST: 718161748Scperciva xcst = 'B'; 719161748Scperciva break; 720161748Scperciva 721161748Scperciva case CTX_UCST: 722161748Scperciva xcst = 'U'; 723161748Scperciva break; 724161748Scperciva 725161748Scperciva default: 726161748Scperciva INSIST(!"spkt->dctx->flags neither UCST nor BCST"); 727161748Scperciva break; 728161748Scperciva } 729161748Scperciva 730161748Scperciva spkt_next = spkt->link; 731161748Scperciva if (0 == spkt->stime || spkt->done) 732161748Scperciva continue; 733161748Scperciva age = start_cb.tv_sec - spkt->stime; 734161748Scperciva TRACE(3, ("%s %s %cCST age %ld\n", 735196392Ssimon stoa(&spkt->addr), 736196392Ssimon spkt->dctx->name, xcst, age)); 737196392Ssimon if (age > response_timeout) 738196392Ssimon timeout_query(spkt); 739196392Ssimon } 740196392Ssimon } 741196392Ssimon // Do we care about didsomething? 742196392Ssimon TRACE(3, ("timeout_queries: didsomething is %d, age is %ld\n", 743161748Scperciva didsomething, (long) (start_cb.tv_sec - start_tv.tv_sec))); 744161748Scperciva if (start_cb.tv_sec - start_tv.tv_sec > response_timeout) { 745161748Scperciva TRACE(3, ("timeout_queries: bail!\n")); 746161748Scperciva event_base_loopexit(base, NULL); 747161748Scperciva shutting_down = TRUE; 748161748Scperciva } 749161748Scperciva} 750161748Scperciva 751161748Scperciva 752161748Scpercivavoid dec_pending_ntp( 753161748Scperciva const char * name, 754161748Scperciva sockaddr_u * server 755161748Scperciva ) 756161748Scperciva{ 757161748Scperciva if (n_pending_ntp > 0) { 758161748Scperciva --n_pending_ntp; 759161748Scperciva check_exit_conditions(); 760161748Scperciva } else { 761161748Scperciva INSIST(0 == n_pending_ntp); 762161748Scperciva TRACE(1, ("n_pending_ntp was zero before decrement for %s\n", 763161748Scperciva hostnameaddr(name, server))); 764161748Scperciva } 765161748Scperciva} 766161748Scperciva 767161748Scperciva 768161748Scpercivavoid timeout_query( 769161748Scperciva sent_pkt * spkt 770161748Scperciva ) 771161748Scperciva{ 772161748Scperciva sockaddr_u * server; 773161748Scperciva char xcst; 774161748Scperciva 775161748Scperciva 776161748Scperciva switch (spkt->dctx->flags & CTX_xCST) { 777161748Scperciva case CTX_BCST: 778161748Scperciva xcst = 'B'; 779181142Scperciva break; 780181142Scperciva 781181142Scperciva case CTX_UCST: 782181142Scperciva xcst = 'U'; 783181142Scperciva break; 784181142Scperciva 785181142Scperciva default: 786181142Scperciva INSIST(!"spkt->dctx->flags neither UCST nor BCST"); 787181142Scperciva break; 788181142Scperciva } 789181142Scperciva spkt->done = TRUE; 790181142Scperciva server = &spkt->addr; 791181142Scperciva msyslog(LOG_INFO, "%s no %cCST response after %d seconds", 792181142Scperciva hostnameaddr(spkt->dctx->name, server), xcst, 793181142Scperciva response_timeout); 794181142Scperciva dec_pending_ntp(spkt->dctx->name, server); 795181142Scperciva return; 796181142Scperciva} 797181142Scperciva 798181142Scperciva 799181142Scperciva/* 800181142Scperciva** check_kod 801181142Scperciva*/ 802181142Scpercivaint 803181142Scpercivacheck_kod( 804181142Scperciva const struct addrinfo * ai 805181142Scperciva ) 806181142Scperciva{ 807181142Scperciva char *hostname; 808181142Scperciva struct kod_entry *reason; 809181142Scperciva 810181142Scperciva /* Is there a KoD on file for this address? */ 811181142Scperciva hostname = addrinfo_to_str(ai); 812181142Scperciva TRACE(2, ("check_kod: checking <%s>\n", hostname)); 813181142Scperciva if (search_entry(hostname, &reason)) { 814181142Scperciva printf("prior KoD for %s, skipping.\n", 815181142Scperciva hostname); 816181142Scperciva free(reason); 817181142Scperciva free(hostname); 818181142Scperciva 819181142Scperciva return 1; 820181142Scperciva } 821181142Scperciva free(hostname); 822181142Scperciva 823181142Scperciva return 0; 824181142Scperciva} 825181142Scperciva 826181142Scperciva 827181142Scperciva/* 828181142Scperciva** Socket readable/timeout Callback: 829181142Scperciva** Read in the packet 830181142Scperciva** Unicast: 831181142Scperciva** - close socket 832181142Scperciva** - decrement n_pending_ntp 833181142Scperciva** - If packet is good, set the time and "exit" 834181142Scperciva** Broadcast: 835181142Scperciva** - If packet is good, set the time and "exit" 836181142Scperciva*/ 837181142Scpercivavoid 838181142Scpercivasock_cb( 839181142Scperciva evutil_socket_t fd, 840181142Scperciva short what, 841181142Scperciva void *ptr 842181142Scperciva ) 843181142Scperciva{ 844181142Scperciva sockaddr_u sender; 845181142Scperciva sockaddr_u * psau; 846181142Scperciva sent_pkt ** p_pktlist; 847181142Scperciva sent_pkt * spkt; 848181142Scperciva int rpktl; 849181142Scperciva int rc; 850181142Scperciva 851181142Scperciva INSIST(sock4 == fd || sock6 == fd); 852181142Scperciva 853181142Scperciva TRACE(3, ("sock_cb: event on sock%s:%s%s%s%s\n", 854181142Scperciva (fd == sock6) 855181142Scperciva ? "6" 856181142Scperciva : "4", 857181142Scperciva (what & EV_TIMEOUT) ? " timeout" : "", 858181142Scperciva (what & EV_READ) ? " read" : "", 859181142Scperciva (what & EV_WRITE) ? " write" : "", 860181142Scperciva (what & EV_SIGNAL) ? " signal" : "")); 861181142Scperciva 862181142Scperciva if (!(EV_READ & what)) { 863181142Scperciva if (EV_TIMEOUT & what) 864161748Scperciva timeout_queries(); 865161748Scperciva 866161748Scperciva return; 867161748Scperciva } 868161748Scperciva 869161748Scperciva /* Read in the packet */ 870161748Scperciva rpktl = recvdata(fd, &sender, &rbuf, sizeof(rbuf)); 871161748Scperciva if (rpktl < 0) { 872161748Scperciva msyslog(LOG_DEBUG, "recvfrom error %m"); 873161748Scperciva return; 874161748Scperciva } 875161748Scperciva 876161748Scperciva if (sock6 == fd) 877161748Scperciva p_pktlist = &v6_pkts_list; 878161748Scperciva else 879161748Scperciva p_pktlist = &v4_pkts_list; 880161748Scperciva 881161748Scperciva for (spkt = *p_pktlist; spkt != NULL; spkt = spkt->link) { 882161748Scperciva psau = &spkt->addr; 883161748Scperciva if (SOCK_EQ(&sender, psau)) 884161748Scperciva break; 885161748Scperciva } 886161748Scperciva if (NULL == spkt) { 887161748Scperciva msyslog(LOG_WARNING, 888161748Scperciva "Packet from unexpected source %s dropped", 889161748Scperciva sptoa(&sender)); 890161748Scperciva return; 891161748Scperciva } 892161748Scperciva 893161748Scperciva TRACE(1, ("sock_cb: %s %s\n", spkt->dctx->name, 894161748Scperciva sptoa(&sender))); 895161748Scperciva 896161748Scperciva rpktl = process_pkt(&r_pkt, &sender, rpktl, MODE_SERVER, 897161748Scperciva &spkt->x_pkt, "sock_cb"); 898161748Scperciva 899161748Scperciva TRACE(2, ("sock_cb: process_pkt returned %d\n", rpktl)); 900161748Scperciva 901161748Scperciva /* If this is a Unicast packet, one down ... */ 902161748Scperciva if (!spkt->done && (CTX_UCST & spkt->dctx->flags)) { 903161748Scperciva dec_pending_ntp(spkt->dctx->name, &spkt->addr); 904161748Scperciva spkt->done = TRUE; 905161748Scperciva } 906161748Scperciva 907161748Scperciva 908161748Scperciva /* If the packet is good, set the time and we're all done */ 909161748Scperciva rc = handle_pkt(rpktl, &r_pkt, &spkt->addr, spkt->dctx->name); 910161748Scperciva if (0 != rc) 911161748Scperciva TRACE(1, ("sock_cb: handle_pkt() returned %d\n", rc)); 912161748Scperciva check_exit_conditions(); 913161748Scperciva} 914161748Scperciva 915161748Scperciva 916161748Scperciva/* 917161748Scperciva * check_exit_conditions() 918161748Scperciva * 919161748Scperciva * If sntp has a reply, ask the event loop to stop after this round of 920161748Scperciva * callbacks, unless --wait was used. 921161748Scperciva */ 922161748Scpercivavoid 923161748Scpercivacheck_exit_conditions(void) 924161748Scperciva{ 925161748Scperciva if ((0 == n_pending_ntp && 0 == n_pending_dns) || 926161748Scperciva (time_derived && !HAVE_OPT(WAIT))) { 927161748Scperciva event_base_loopexit(base, NULL); 928161748Scperciva shutting_down = TRUE; 929161748Scperciva } else { 930161748Scperciva TRACE(2, ("%d NTP and %d name queries pending\n", 931161748Scperciva n_pending_ntp, n_pending_dns)); 932161748Scperciva } 933161748Scperciva} 934161748Scperciva 935161748Scperciva 936161748Scperciva/* 937161748Scperciva * sntp_addremove_fd() is invoked by the intres blocking worker code 938161748Scperciva * to read from a pipe, or to stop same. 939161748Scperciva */ 940161748Scpercivavoid sntp_addremove_fd( 941161748Scperciva int fd, 942161748Scperciva int is_pipe, 943161748Scperciva int remove_it 944161748Scperciva ) 945161748Scperciva{ 946161748Scperciva u_int idx; 947161748Scperciva blocking_child *c; 948161748Scperciva struct event * ev; 949161748Scperciva 950161748Scperciva#ifdef HAVE_SOCKETPAIR 951161748Scperciva if (is_pipe) { 952161748Scperciva /* sntp only asks for EV_FEATURE_FDS without HAVE_SOCKETPAIR */ 953161748Scperciva msyslog(LOG_ERR, "fatal: pipes not supported on systems with socketpair()"); 954161748Scperciva exit(1); 955161748Scperciva } 956161748Scperciva#endif 957161748Scperciva 958161748Scperciva c = NULL; 959161748Scperciva for (idx = 0; idx < blocking_children_alloc; idx++) { 960161748Scperciva c = blocking_children[idx]; 961161748Scperciva if (NULL == c) 962161748Scperciva continue; 963161748Scperciva if (fd == c->resp_read_pipe) 964161748Scperciva break; 965161748Scperciva } 966161748Scperciva if (idx == blocking_children_alloc) 967161748Scperciva return; 968161748Scperciva 969161748Scperciva if (remove_it) { 970161748Scperciva ev = c->resp_read_ctx; 971161748Scperciva c->resp_read_ctx = NULL; 972161748Scperciva event_del(ev); 973161748Scperciva event_free(ev); 974161748Scperciva 975161748Scperciva return; 976161748Scperciva } 977161748Scperciva 978161748Scperciva ev = event_new(base, fd, EV_READ | EV_PERSIST, 979161748Scperciva &worker_resp_cb, c); 980161748Scperciva if (NULL == ev) { 981161748Scperciva msyslog(LOG_ERR, 982161748Scperciva "sntp_addremove_fd: event_new(base, fd) failed!"); 983161748Scperciva return; 984161748Scperciva } 985161748Scperciva c->resp_read_ctx = ev; 986161748Scperciva event_add(ev, NULL); 987161748Scperciva} 988161748Scperciva 989161748Scperciva 990161748Scperciva/* called by forked intres child to close open descriptors */ 991161748Scperciva#ifdef WORK_FORK 992161748Scpercivavoid 993161748Scpercivakill_asyncio( 994161748Scperciva int startfd 995161748Scperciva ) 996161748Scperciva{ 997161748Scperciva if (INVALID_SOCKET != sock4) { 998161748Scperciva closesocket(sock4); 999161748Scperciva sock4 = INVALID_SOCKET; 1000161748Scperciva } 1001161748Scperciva if (INVALID_SOCKET != sock6) { 1002161748Scperciva closesocket(sock6); 1003161748Scperciva sock6 = INVALID_SOCKET; 1004161748Scperciva } 1005161748Scperciva if (INVALID_SOCKET != bsock4) { 1006161748Scperciva closesocket(sock4); 1007173564Scperciva sock4 = INVALID_SOCKET; 1008173564Scperciva } 1009173564Scperciva if (INVALID_SOCKET != bsock6) { 1010173564Scperciva closesocket(sock6); 1011173564Scperciva sock6 = INVALID_SOCKET; 1012173564Scperciva } 1013173564Scperciva} 1014173564Scperciva#endif 1015173564Scperciva 1016173564Scperciva 1017173564Scperciva/* 1018173564Scperciva * worker_resp_cb() is invoked when resp_read_pipe is readable. 1019173564Scperciva */ 1020173564Scpercivavoid 1021161748Scpercivaworker_resp_cb( 1022161748Scperciva evutil_socket_t fd, 1023161748Scperciva short what, 1024161748Scperciva void * ctx /* blocking_child * */ 1025161748Scperciva ) 1026161748Scperciva{ 1027161748Scperciva blocking_child * c; 1028161748Scperciva 1029161748Scperciva DEBUG_INSIST(EV_READ & what); 1030161748Scperciva c = ctx; 1031161748Scperciva DEBUG_INSIST(fd == c->resp_read_pipe); 1032161748Scperciva process_blocking_resp(c); 1033161748Scperciva} 1034161748Scperciva 1035161748Scperciva 1036161748Scperciva/* 1037161748Scperciva * intres_timeout_req(s) is invoked in the parent to schedule an idle 1038161748Scperciva * timeout to fire in s seconds, if not reset earlier by a call to 1039161748Scperciva * intres_timeout_req(0), which clears any pending timeout. When the 1040161748Scperciva * timeout expires, worker_idle_timer_fired() is invoked (again, in the 1041161748Scperciva * parent). 1042161748Scperciva * 1043161748Scperciva * sntp and ntpd each provide implementations adapted to their timers. 1044161748Scperciva */ 1045161748Scpercivavoid 1046161748Scpercivaintres_timeout_req( 1047161748Scperciva u_int seconds /* 0 cancels */ 1048161748Scperciva ) 1049161748Scperciva{ 1050161748Scperciva struct timeval tv_to; 1051161748Scperciva 1052161748Scperciva if (NULL == ev_worker_timeout) { 1053173564Scperciva ev_worker_timeout = event_new(base, -1, 1054173564Scperciva EV_TIMEOUT | EV_PERSIST, 1055161748Scperciva &worker_timeout, NULL); 1056161748Scperciva DEBUG_INSIST(NULL != ev_worker_timeout); 1057161748Scperciva } else { 1058161748Scperciva event_del(ev_worker_timeout); 1059161748Scperciva } 1060161748Scperciva if (0 == seconds) 1061161748Scperciva return; 1062161748Scperciva tv_to.tv_sec = seconds; 1063161748Scperciva tv_to.tv_usec = 0; 1064161748Scperciva event_add(ev_worker_timeout, &tv_to); 1065161748Scperciva} 1066161748Scperciva 1067161748Scperciva 1068161748Scpercivavoid 1069161748Scpercivaworker_timeout( 1070161748Scperciva evutil_socket_t fd, 1071161748Scperciva short what, 1072161748Scperciva void * ctx 1073161748Scperciva ) 1074161748Scperciva{ 1075161748Scperciva UNUSED_ARG(fd); 1076161748Scperciva UNUSED_ARG(ctx); 1077161748Scperciva 1078161748Scperciva DEBUG_REQUIRE(EV_TIMEOUT & what); 1079161748Scperciva worker_idle_timer_fired(); 1080161748Scperciva} 1081161748Scperciva 1082161748Scperciva 1083161748Scpercivavoid 1084161748Scpercivasntp_libevent_log_cb( 1085161748Scperciva int severity, 1086161748Scperciva const char * msg 1087161748Scperciva ) 1088161748Scperciva{ 1089161748Scperciva int level; 1090161748Scperciva 1091161748Scperciva switch (severity) { 1092161748Scperciva 1093161748Scperciva default: 1094161748Scperciva case _EVENT_LOG_DEBUG: 1095161748Scperciva level = LOG_DEBUG; 1096161748Scperciva break; 1097161748Scperciva 1098161748Scperciva case _EVENT_LOG_MSG: 1099161748Scperciva level = LOG_NOTICE; 1100161748Scperciva break; 1101161748Scperciva 1102161748Scperciva case _EVENT_LOG_WARN: 1103161748Scperciva level = LOG_WARNING; 1104161748Scperciva break; 1105161748Scperciva 1106161748Scperciva case _EVENT_LOG_ERR: 1107161748Scperciva level = LOG_ERR; 1108161748Scperciva break; 1109161748Scperciva } 1110161748Scperciva 1111161748Scperciva msyslog(level, "%s", msg); 1112161748Scperciva} 1113161748Scperciva 1114161748Scperciva 1115161748Scpercivaint 1116161748Scpercivagenerate_pkt ( 1117161748Scperciva struct pkt *x_pkt, 1118161748Scperciva const struct timeval *tv_xmt, 1119161748Scperciva int key_id, 1120161748Scperciva struct key *pkt_key 1121161748Scperciva ) 1122161748Scperciva{ 1123161748Scperciva l_fp xmt_fp; 1124161748Scperciva int pkt_len; 1125161748Scperciva int mac_size; 1126161748Scperciva 1127161748Scperciva pkt_len = LEN_PKT_NOMAC; 1128161748Scperciva ZERO(*x_pkt); 1129161748Scperciva TVTOTS(tv_xmt, &xmt_fp); 1130161748Scperciva HTONL_FP(&xmt_fp, &x_pkt->xmt); 1131161748Scperciva x_pkt->stratum = STRATUM_TO_PKT(STRATUM_UNSPEC); 1132161748Scperciva x_pkt->ppoll = 8; 1133161748Scperciva /* FIXME! Modus broadcast + adr. check -> bdr. pkt */ 1134161748Scperciva set_li_vn_mode(x_pkt, LEAP_NOTINSYNC, ntpver, 3); 1135161748Scperciva if (pkt_key != NULL) { 1136161748Scperciva x_pkt->exten[0] = htonl(key_id); 1137161748Scperciva mac_size = 20; /* max room for MAC */ 1138161748Scperciva mac_size = make_mac(x_pkt, pkt_len, mac_size, 1139161748Scperciva pkt_key, (char *)&x_pkt->exten[1]); 1140161748Scperciva if (mac_size > 0) 1141161748Scperciva pkt_len += mac_size + 4; 1142161748Scperciva } 1143161748Scperciva return pkt_len; 1144161748Scperciva} 1145161748Scperciva 1146161748Scperciva 1147161748Scpercivaint 1148161748Scpercivahandle_pkt( 1149161748Scperciva int rpktl, 1150161748Scperciva struct pkt * rpkt, 1151161748Scperciva sockaddr_u * host, 1152161748Scperciva const char * hostname 1153161748Scperciva ) 1154161748Scperciva{ 1155161748Scperciva char disptxt[32]; 1156161748Scperciva const char * addrtxt; 1157161748Scperciva struct timeval tv_dst; 1158161748Scperciva int cnt; 1159161748Scperciva int sw_case; 1160161748Scperciva int digits; 1161161748Scperciva int stratum; 1162161748Scperciva char * ref; 1163161748Scperciva char * ts_str; 1164161748Scperciva const char * leaptxt; 1165161748Scperciva double offset; 1166161748Scperciva double precision; 1167161748Scperciva double synch_distance; 1168161748Scperciva char * p_SNTP_PRETEND_TIME; 1169161748Scperciva time_t pretend_time; 1170161748Scperciva#if SIZEOF_TIME_T == 8 1171161748Scperciva long long ll; 1172161748Scperciva#else 1173161748Scperciva long l; 1174161748Scperciva#endif 1175161748Scperciva 1176161748Scperciva ts_str = NULL; 1177161748Scperciva 1178161748Scperciva if (rpktl > 0) 1179161748Scperciva sw_case = 1; 1180161748Scperciva else 1181161748Scperciva sw_case = rpktl; 1182161748Scperciva 1183161748Scperciva switch (sw_case) { 1184161748Scperciva 1185161748Scperciva case SERVER_UNUSEABLE: 1186161748Scperciva return -1; 1187161748Scperciva break; 1188161748Scperciva 1189161748Scperciva case PACKET_UNUSEABLE: 1190161748Scperciva break; 1191161748Scperciva 1192161748Scperciva case SERVER_AUTH_FAIL: 1193161748Scperciva break; 1194161748Scperciva 1195161748Scperciva case KOD_DEMOBILIZE: 1196161748Scperciva /* Received a DENY or RESTR KOD packet */ 1197161748Scperciva addrtxt = stoa(host); 1198161748Scperciva ref = (char *)&rpkt->refid; 1199161748Scperciva add_entry(addrtxt, ref); 1200161748Scperciva msyslog(LOG_WARNING, "KOD code %c%c%c%c from %s %s", 1201161748Scperciva ref[0], ref[1], ref[2], ref[3], addrtxt, hostname); 1202161748Scperciva break; 1203161748Scperciva 1204161748Scperciva case KOD_RATE: 1205161748Scperciva /* 1206161748Scperciva ** Hmm... 1207161748Scperciva ** We should probably call add_entry() with an 1208161748Scperciva ** expiration timestamp of several seconds in the future, 1209161748Scperciva ** and back-off even more if we get more RATE responses. 1210161748Scperciva */ 1211161748Scperciva break; 1212161748Scperciva 1213161748Scperciva case 1: 1214161748Scperciva TRACE(3, ("handle_pkt: %d bytes from %s %s\n", 1215161748Scperciva rpktl, stoa(host), hostname)); 1216161748Scperciva 1217161748Scperciva gettimeofday_cached(base, &tv_dst); 1218161748Scperciva 1219161748Scperciva p_SNTP_PRETEND_TIME = getenv("SNTP_PRETEND_TIME"); 1220161748Scperciva if (p_SNTP_PRETEND_TIME) { 1221161748Scperciva pretend_time = 0; 1222161748Scperciva#if SIZEOF_TIME_T == 4 1223161748Scperciva if (1 == sscanf(p_SNTP_PRETEND_TIME, "%ld", &l)) 1224161748Scperciva pretend_time = (time_t)l; 1225161748Scperciva#elif SIZEOF_TIME_T == 8 1226161748Scperciva if (1 == sscanf(p_SNTP_PRETEND_TIME, "%lld", &ll)) 1227161748Scperciva pretend_time = (time_t)ll; 1228161748Scperciva#else 1229161748Scperciva# include "GRONK: unexpected value for SIZEOF_TIME_T" 1230161748Scperciva#endif 1231161748Scperciva if (0 != pretend_time) 1232161748Scperciva tv_dst.tv_sec = pretend_time; 1233161748Scperciva } 1234161748Scperciva 1235161748Scperciva offset_calculation(rpkt, rpktl, &tv_dst, &offset, 1236161748Scperciva &precision, &synch_distance); 1237161748Scperciva time_derived = TRUE; 1238161748Scperciva 1239161748Scperciva for (digits = 0; (precision *= 10.) < 1.; ++digits) 1240161748Scperciva /* empty */ ; 1241161748Scperciva if (digits > 6) 1242161748Scperciva digits = 6; 1243161748Scperciva 1244161748Scperciva ts_str = tv_to_str(&tv_dst); 1245161748Scperciva stratum = rpkt->stratum; 1246161748Scperciva if (0 == stratum) 1247161748Scperciva stratum = 16; 1248161748Scperciva 1249161748Scperciva if (synch_distance > 0.) { 1250161748Scperciva cnt = snprintf(disptxt, sizeof(disptxt), 1251161748Scperciva " +/- %f", synch_distance); 1252161748Scperciva if ((size_t)cnt >= sizeof(disptxt)) 1253161748Scperciva snprintf(disptxt, sizeof(disptxt), 1254161748Scperciva "ERROR %d >= %d", cnt, 1255161748Scperciva (int)sizeof(disptxt)); 1256161748Scperciva } else { 1257161748Scperciva disptxt[0] = '\0'; 1258161748Scperciva } 1259161748Scperciva 1260161748Scperciva switch (PKT_LEAP(rpkt->li_vn_mode)) { 1261161748Scperciva case LEAP_NOWARNING: 1262161748Scperciva leaptxt = "no-leap"; 1263161748Scperciva break; 1264161748Scperciva case LEAP_ADDSECOND: 1265161748Scperciva leaptxt = "add-leap"; 1266161748Scperciva break; 1267161748Scperciva case LEAP_DELSECOND: 1268161748Scperciva leaptxt = "del-leap"; 1269161748Scperciva break; 1270161748Scperciva case LEAP_NOTINSYNC: 1271161748Scperciva leaptxt = "unsync"; 1272161748Scperciva break; 1273161748Scperciva default: 1274161748Scperciva leaptxt = "LEAP-ERROR"; 1275161748Scperciva break; 1276161748Scperciva } 1277161748Scperciva 1278161748Scperciva msyslog(LOG_INFO, "%s %+.*f%s %s s%d %s%s", ts_str, 1279161748Scperciva digits, offset, disptxt, 1280161748Scperciva hostnameaddr(hostname, host), stratum, 1281161748Scperciva leaptxt, 1282161748Scperciva (time_adjusted) 1283161748Scperciva ? " [excess]" 1284161748Scperciva : ""); 1285161748Scperciva free(ts_str); 1286161748Scperciva 1287161748Scperciva if (p_SNTP_PRETEND_TIME) 1288161748Scperciva return 0; 1289161748Scperciva 1290161748Scperciva if (!time_adjusted && 1291161748Scperciva (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW))) 1292161748Scperciva return set_time(offset); 1293161748Scperciva 1294161748Scperciva return EX_OK; 1295164600Scperciva } 1296164600Scperciva 1297161748Scperciva return 1; 1298161748Scperciva} 1299161748Scperciva 1300161748Scperciva 1301161748Scpercivavoid 1302161748Scpercivaoffset_calculation( 1303161748Scperciva struct pkt *rpkt, 1304161748Scperciva int rpktl, 1305161748Scperciva struct timeval *tv_dst, 1306161748Scperciva double *offset, 1307161748Scperciva double *precision, 1308161748Scperciva double *synch_distance 1309161748Scperciva ) 1310161748Scperciva{ 1311161748Scperciva l_fp p_rec, p_xmt, p_ref, p_org, tmp, dst; 1312161748Scperciva u_fp p_rdly, p_rdsp; 1313161748Scperciva double t21, t34, delta; 1314161748Scperciva 1315161748Scperciva /* Convert timestamps from network to host byte order */ 1316161748Scperciva p_rdly = NTOHS_FP(rpkt->rootdelay); 1317161748Scperciva p_rdsp = NTOHS_FP(rpkt->rootdisp); 1318161748Scperciva NTOHL_FP(&rpkt->reftime, &p_ref); 1319161748Scperciva NTOHL_FP(&rpkt->org, &p_org); 1320161748Scperciva NTOHL_FP(&rpkt->rec, &p_rec); 1321161748Scperciva NTOHL_FP(&rpkt->xmt, &p_xmt); 1322161748Scperciva 1323161748Scperciva *precision = LOGTOD(rpkt->precision); 1324161748Scperciva 1325161748Scperciva TRACE(3, ("offset_calculation: LOGTOD(rpkt->precision): %f\n", *precision)); 1326161748Scperciva 1327161748Scperciva /* Compute offset etc. */ 1328161748Scperciva tmp = p_rec; 1329161748Scperciva L_SUB(&tmp, &p_org); 1330161748Scperciva LFPTOD(&tmp, t21); 1331161748Scperciva TVTOTS(tv_dst, &dst); 1332161748Scperciva dst.l_ui += JAN_1970; 1333161748Scperciva tmp = p_xmt; 1334161748Scperciva L_SUB(&tmp, &dst); 1335161748Scperciva LFPTOD(&tmp, t34); 1336161748Scperciva *offset = (t21 + t34) / 2.; 1337161748Scperciva delta = t21 - t34; 1338161748Scperciva 1339161748Scperciva // synch_distance is: 1340161748Scperciva // (peer->delay + peer->rootdelay) / 2 + peer->disp 1341161748Scperciva // + peer->rootdisp + clock_phi * (current_time - peer->update) 1342161748Scperciva // + peer->jitter; 1343161748Scperciva // 1344161748Scperciva // and peer->delay = fabs(peer->offset - p_offset) * 2; 1345173564Scperciva // and peer->offset needs history, so we're left with 1346173564Scperciva // p_offset = (t21 + t34) / 2.; 1347173564Scperciva // peer->disp = 0; (we have no history to augment this) 1348173564Scperciva // clock_phi = 15e-6; 1349173564Scperciva // peer->jitter = LOGTOD(sys_precision); (we have no history to augment this) 1350173564Scperciva // and ntp_proto.c:set_sys_tick_precision() should get us sys_precision. 1351173564Scperciva // 1352173564Scperciva // so our answer seems to be: 1353173564Scperciva // 1354173564Scperciva // (fabs(t21 + t34) + peer->rootdelay) / 3. 1355173564Scperciva // + 0 (peer->disp) 1356173564Scperciva // + peer->rootdisp 1357173564Scperciva // + 15e-6 (clock_phi) 1358173564Scperciva // + LOGTOD(sys_precision) 1359173564Scperciva 1360161869Scperciva INSIST( FPTOD(p_rdly) >= 0. ); 1361161748Scperciva#if 1 1362161748Scperciva *synch_distance = (fabs(t21 + t34) + FPTOD(p_rdly)) / 3. 1363161748Scperciva + 0. 1364161748Scperciva + FPTOD(p_rdsp) 1365173564Scperciva + 15e-6 1366173564Scperciva + 0. /* LOGTOD(sys_precision) when we can get it */ 1367161748Scperciva ; 1368161748Scperciva INSIST( *synch_distance >= 0. ); 1369161748Scperciva#else 1370161748Scperciva *synch_distance = (FPTOD(p_rdly) + FPTOD(p_rdsp))/2.0; 1371161748Scperciva#endif 1372173564Scperciva 1373161748Scperciva#ifdef DEBUG 1374161748Scperciva if (debug > 3) { 1375161748Scperciva printf("sntp rootdelay: %f\n", FPTOD(p_rdly)); 1376161748Scperciva printf("sntp rootdisp: %f\n", FPTOD(p_rdsp)); 1377161748Scperciva printf("sntp syncdist: %f\n", *synch_distance); 1378161748Scperciva 1379161748Scperciva pkt_output(rpkt, rpktl, stdout); 1380161748Scperciva 1381161748Scperciva printf("sntp offset_calculation: rpkt->reftime:\n"); 1382161748Scperciva l_fp_output(&p_ref, stdout); 1383161748Scperciva printf("sntp offset_calculation: rpkt->org:\n"); 1384173564Scperciva l_fp_output(&p_org, stdout); 1385161748Scperciva printf("sntp offset_calculation: rpkt->rec:\n"); 1386161748Scperciva l_fp_output(&p_rec, stdout); 1387173564Scperciva printf("sntp offset_calculation: rpkt->xmt:\n"); 1388164600Scperciva l_fp_output(&p_xmt, stdout); 1389173564Scperciva } 1390164600Scperciva#endif 1391164600Scperciva 1392164600Scperciva TRACE(3, ("sntp offset_calculation:\trec - org t21: %.6f\n" 1393161748Scperciva "\txmt - dst t34: %.6f\tdelta: %.6f\toffset: %.6f\n", 1394173564Scperciva t21, t34, delta, *offset)); 1395173564Scperciva 1396161748Scperciva return; 1397161748Scperciva} 1398164600Scperciva 1399173564Scperciva 1400173564Scperciva 1401164600Scperciva/* Compute the 8 bits for li_vn_mode */ 1402164600Scpercivavoid 1403161748Scpercivaset_li_vn_mode ( 1404161748Scperciva struct pkt *spkt, 1405161748Scperciva char leap, 1406161748Scperciva char version, 1407161748Scperciva char mode 1408161748Scperciva ) 1409161748Scperciva{ 1410161748Scperciva if (leap > 3) { 1411161748Scperciva msyslog(LOG_DEBUG, "set_li_vn_mode: leap > 3, using max. 3"); 1412161748Scperciva leap = 3; 1413161748Scperciva } 1414161748Scperciva 1415161748Scperciva if ((unsigned char)version > 7) { 1416161748Scperciva msyslog(LOG_DEBUG, "set_li_vn_mode: version < 0 or > 7, using 4"); 1417161748Scperciva version = 4; 1418161748Scperciva } 1419161748Scperciva 1420161748Scperciva if (mode > 7) { 1421161748Scperciva msyslog(LOG_DEBUG, "set_li_vn_mode: mode > 7, using client mode 3"); 1422161748Scperciva mode = 3; 1423161748Scperciva } 1424161748Scperciva 1425161748Scperciva spkt->li_vn_mode = leap << 6; 1426161748Scperciva spkt->li_vn_mode |= version << 3; 1427161748Scperciva spkt->li_vn_mode |= mode; 1428161748Scperciva} 1429161748Scperciva 1430161748Scperciva 1431161748Scperciva/* 1432161748Scperciva** set_time applies 'offset' to the local clock. 1433161748Scperciva*/ 1434161748Scpercivaint 1435161748Scpercivaset_time( 1436161748Scperciva double offset 1437161748Scperciva ) 1438161748Scperciva{ 1439161748Scperciva int rc; 1440161748Scperciva 1441161748Scperciva if (time_adjusted) 1442161748Scperciva return EX_OK; 1443161748Scperciva 1444161748Scperciva /* 1445161748Scperciva ** If we can step but we cannot slew, then step. 1446161748Scperciva ** If we can step or slew and and |offset| > steplimit, then step. 1447161748Scperciva */ 1448161748Scperciva if (ENABLED_OPT(STEP) && 1449161748Scperciva ( !ENABLED_OPT(SLEW) 1450161748Scperciva || (ENABLED_OPT(SLEW) && (fabs(offset) > steplimit)) 1451161748Scperciva )) { 1452161748Scperciva rc = step_systime(offset); 1453161748Scperciva 1454161748Scperciva /* If there was a problem, can we rely on errno? */ 1455161748Scperciva if (1 == rc) 1456161748Scperciva time_adjusted = TRUE; 1457161748Scperciva return (time_adjusted) 1458161748Scperciva ? EX_OK 1459161748Scperciva : 1; 1460161748Scperciva /* 1461161748Scperciva ** In case of error, what should we use? 1462161748Scperciva ** EX_UNAVAILABLE? 1463161748Scperciva ** EX_OSERR? 1464161748Scperciva ** EX_NOPERM? 1465161748Scperciva */ 1466161748Scperciva } 1467161748Scperciva 1468161748Scperciva if (ENABLED_OPT(SLEW)) { 1469161748Scperciva rc = adj_systime(offset); 1470161748Scperciva 1471161748Scperciva /* If there was a problem, can we rely on errno? */ 1472161748Scperciva if (1 == rc) 1473161748Scperciva time_adjusted = TRUE; 1474161748Scperciva return (time_adjusted) 1475161748Scperciva ? EX_OK 1476161748Scperciva : 1; 1477161748Scperciva /* 1478161748Scperciva ** In case of error, what should we use? 1479161748Scperciva ** EX_UNAVAILABLE? 1480161748Scperciva ** EX_OSERR? 1481161748Scperciva ** EX_NOPERM? 1482161748Scperciva */ 1483173564Scperciva } 1484173564Scperciva 1485173564Scperciva return EX_SOFTWARE; 1486173564Scperciva} 1487173564Scperciva 1488173564Scperciva 1489173564Scpercivaint 1490173564Scpercivalibevent_version_ok(void) 1491173564Scperciva{ 1492173564Scperciva ev_uint32_t v_compile_maj; 1493173564Scperciva ev_uint32_t v_run_maj; 1494173564Scperciva 1495173564Scperciva v_compile_maj = LIBEVENT_VERSION_NUMBER & 0xffff0000; 1496173564Scperciva v_run_maj = event_get_version_number() & 0xffff0000; 1497173564Scperciva if (v_compile_maj != v_run_maj) { 1498173564Scperciva fprintf(stderr, 1499173564Scperciva "Incompatible libevent versions: have %s, built with %s\n", 1500173564Scperciva event_get_version(), 1501173564Scperciva LIBEVENT_VERSION); 1502173564Scperciva return 0; 1503173564Scperciva } 1504173564Scperciva return 1; 1505173564Scperciva} 1506173564Scperciva 1507173564Scperciva/* 1508173564Scperciva * gettimeofday_cached() 1509173564Scperciva * 1510173564Scperciva * Clones the event_base_gettimeofday_cached() interface but ensures the 1511173564Scperciva * times are always on the gettimeofday() 1970 scale. Older libevent 2 1512173564Scperciva * sometimes used gettimeofday(), sometimes the since-system-start 1513173564Scperciva * clock_gettime(CLOCK_MONOTONIC), depending on the platform. 1514173564Scperciva * 1515161748Scperciva * It is not cleanly possible to tell which timescale older libevent is 1516173564Scperciva * using. 1517173564Scperciva * 1518173564Scperciva * The strategy involves 1 hour thresholds chosen to be far longer than 1519173564Scperciva * the duration of a round of libevent callbacks, which share a cached 1520161748Scperciva * start-of-round time. First compare the last cached time with the 1521161748Scperciva * current gettimeofday() time. If they are within one hour, libevent 1522161748Scperciva * is using the proper timescale so leave the offset 0. Otherwise, 1523161748Scperciva * compare libevent's cached time and the current time on the monotonic 1524161748Scperciva * scale. If they are within an hour, libevent is using the monotonic 1525161748Scperciva * scale so calculate the offset to add to such times to bring them to 1526161748Scperciva * gettimeofday()'s scale. 1527161748Scperciva */ 1528161748Scpercivaint 1529161748Scpercivagettimeofday_cached( 1530161748Scperciva struct event_base * b, 1531161748Scperciva struct timeval * caller_tv 1532161748Scperciva ) 1533161748Scperciva{ 1534161748Scperciva#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 1535161748Scperciva static struct event_base * cached_b; 1536161748Scperciva static struct timeval cached; 1537161748Scperciva static struct timeval adj_cached; 1538161748Scperciva static struct timeval offset; 1539161748Scperciva static int offset_ready; 1540161748Scperciva struct timeval latest; 1541173564Scperciva struct timeval systemt; 1542173564Scperciva struct timespec ts; 1543173564Scperciva struct timeval mono; 1544173564Scperciva struct timeval diff; 1545173564Scperciva int cgt_rc; 1546173564Scperciva int gtod_rc; 1547173564Scperciva 1548173564Scperciva event_base_gettimeofday_cached(b, &latest); 1549173564Scperciva if (b == cached_b && 1550161748Scperciva !memcmp(&latest, &cached, sizeof(latest))) { 1551161748Scperciva *caller_tv = adj_cached; 1552161748Scperciva return 0; 1553161748Scperciva } 1554161748Scperciva cached = latest; 1555161748Scperciva cached_b = b; 1556161748Scperciva if (!offset_ready) { 1557161748Scperciva cgt_rc = clock_gettime(CLOCK_MONOTONIC, &ts); 1558161748Scperciva gtod_rc = gettimeofday(&systemt, NULL); 1559161748Scperciva if (0 != gtod_rc) { 1560161748Scperciva msyslog(LOG_ERR, 1561161748Scperciva "%s: gettimeofday() error %m", 1562161748Scperciva progname); 1563161748Scperciva exit(1); 1564161748Scperciva } 1565161748Scperciva diff = sub_tval(systemt, latest); 1566161748Scperciva if (debug > 1) 1567161748Scperciva printf("system minus cached %+ld.%06ld\n", 1568161748Scperciva (long)diff.tv_sec, (long)diff.tv_usec); 1569161748Scperciva if (0 != cgt_rc || labs((long)diff.tv_sec) < 3600) { 1570161748Scperciva /* 1571161748Scperciva * Either use_monotonic == 0, or this libevent 1572161748Scperciva * has been repaired. Leave offset at zero. 1573161748Scperciva */ 1574161748Scperciva } else { 1575161748Scperciva mono.tv_sec = ts.tv_sec; 1576161748Scperciva mono.tv_usec = ts.tv_nsec / 1000; 1577161748Scperciva diff = sub_tval(latest, mono); 1578161748Scperciva if (debug > 1) 1579161748Scperciva printf("cached minus monotonic %+ld.%06ld\n", 1580161748Scperciva (long)diff.tv_sec, (long)diff.tv_usec); 1581161748Scperciva if (labs((long)diff.tv_sec) < 3600) { 1582161748Scperciva /* older libevent2 using monotonic */ 1583161748Scperciva offset = sub_tval(systemt, mono); 1584161748Scperciva TRACE(1, ("%s: Offsetting libevent CLOCK_MONOTONIC times by %+ld.%06ld\n", 1585161748Scperciva "gettimeofday_cached", 1586161748Scperciva (long)offset.tv_sec, 1587161748Scperciva (long)offset.tv_usec)); 1588161748Scperciva } 1589161748Scperciva } 1590161748Scperciva offset_ready = TRUE; 1591161748Scperciva } 1592161748Scperciva adj_cached = add_tval(cached, offset); 1593161748Scperciva *caller_tv = adj_cached; 1594161748Scperciva 1595161748Scperciva return 0; 1596161748Scperciva#else 1597161748Scperciva return event_base_gettimeofday_cached(b, caller_tv); 1598161748Scperciva#endif 1599161748Scperciva} 1600161748Scperciva 1601161748Scperciva