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