1 /* $NetBSD: ntp_timer.c,v 1.4 2015/07/20 13:13:31 joerg Exp $ */ 2 3 /* 4 * ntp_timer.c - event timer support routines 5 */ 6 #ifdef HAVE_CONFIG_H 7 # include <config.h> 8 #endif 9 10 #include "ntp_machine.h" 11 #include "ntpd.h" 12 #include "ntp_stdlib.h" 13 #include "ntp_calendar.h" 14 #include "ntp_leapsec.h" 15 16 #if defined(HAVE_IO_COMPLETION_PORT) 17 # include "ntp_iocompletionport.h" 18 # include "ntp_timer.h" 19 #endif 20 21 #include <stdio.h> 22 #include <signal.h> 23 #ifdef HAVE_SYS_SIGNAL_H 24 # include <sys/signal.h> 25 #endif 26 #ifdef HAVE_UNISTD_H 27 # include <unistd.h> 28 #endif 29 30 #ifdef KERNEL_PLL 31 #include "ntp_syscall.h" 32 #endif /* KERNEL_PLL */ 33 34 #ifdef AUTOKEY 35 #include <openssl/rand.h> 36 #endif /* AUTOKEY */ 37 38 39 /* TC_ERR represents the timer_create() error return value. */ 40 #ifdef SYS_VXWORKS 41 #define TC_ERR ERROR 42 #else 43 #define TC_ERR (-1) 44 #endif 45 46 47 static void check_leapsec(u_int32, const time_t*, int/*BOOL*/); 48 49 /* 50 * These routines provide support for the event timer. The timer is 51 * implemented by an interrupt routine which sets a flag once every 52 * second, and a timer routine which is called when the mainline code 53 * gets around to seeing the flag. The timer routine dispatches the 54 * clock adjustment code if its time has come, then searches the timer 55 * queue for expiries which are dispatched to the transmit procedure. 56 * Finally, we call the hourly procedure to do cleanup and print a 57 * message. 58 */ 59 volatile int interface_interval; /* init_io() sets def. 300s */ 60 61 /* 62 * Alarm flag. The mainline code imports this. 63 */ 64 volatile int alarm_flag; 65 66 /* 67 * The counters and timeouts 68 */ 69 static u_long interface_timer; /* interface update timer */ 70 static u_long adjust_timer; /* second timer */ 71 static u_long stats_timer; /* stats timer */ 72 static u_long leapf_timer; /* Report leapfile problems once/day */ 73 static u_long huffpuff_timer; /* huff-n'-puff timer */ 74 static u_long worker_idle_timer;/* next check for idle intres */ 75 u_long leapsec; /* seconds to next leap (proximity class) */ 76 int leapdif; /* TAI difference step at next leap second*/ 77 u_long orphwait; /* orphan wait time */ 78 #ifdef AUTOKEY 79 static u_long revoke_timer; /* keys revoke timer */ 80 static u_long keys_timer; /* session key timer */ 81 u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ 82 u_long sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */ 83 #endif /* AUTOKEY */ 84 85 /* 86 * Statistics counter for the interested. 87 */ 88 volatile u_long alarm_overflow; 89 90 u_long current_time; /* seconds since startup */ 91 92 /* 93 * Stats. Number of overflows and number of calls to transmit(). 94 */ 95 u_long timer_timereset; 96 u_long timer_overflows; 97 u_long timer_xmtcalls; 98 99 #if defined(VMS) 100 static int vmstimer[2]; /* time for next timer AST */ 101 static int vmsinc[2]; /* timer increment */ 102 #endif /* VMS */ 103 104 #ifdef SYS_WINNT 105 HANDLE WaitableTimerHandle; 106 #else 107 static RETSIGTYPE alarming (int); 108 #endif /* SYS_WINNT */ 109 110 #if !defined(VMS) 111 # if !defined SYS_WINNT || defined(SYS_CYGWIN32) 112 # ifdef HAVE_TIMER_CREATE 113 static timer_t timer_id; 114 typedef struct itimerspec intervaltimer; 115 # define itv_frac tv_nsec 116 # else 117 typedef struct itimerval intervaltimer; 118 # define itv_frac tv_usec 119 # endif 120 intervaltimer itimer; 121 # endif 122 #endif 123 124 #if !defined(SYS_WINNT) && !defined(VMS) 125 void set_timer_or_die(const intervaltimer *); 126 #endif 127 128 129 #if !defined(SYS_WINNT) && !defined(VMS) 130 void 131 set_timer_or_die( 132 const intervaltimer * ptimer 133 ) 134 { 135 const char * setfunc; 136 int rc; 137 138 # ifdef HAVE_TIMER_CREATE 139 setfunc = "timer_settime"; 140 rc = timer_settime(timer_id, 0, &itimer, NULL); 141 # else 142 setfunc = "setitimer"; 143 rc = setitimer(ITIMER_REAL, &itimer, NULL); 144 # endif 145 if (-1 == rc) { 146 msyslog(LOG_ERR, "interval timer %s failed, %m", 147 setfunc); 148 exit(1); 149 } 150 } 151 #endif /* !SYS_WINNT && !VMS */ 152 153 154 /* 155 * reinit_timer - reinitialize interval timer after a clock step. 156 */ 157 void 158 reinit_timer(void) 159 { 160 #if !defined(SYS_WINNT) && !defined(VMS) 161 ZERO(itimer); 162 # ifdef HAVE_TIMER_CREATE 163 timer_gettime(timer_id, &itimer); 164 # else 165 getitimer(ITIMER_REAL, &itimer); 166 # endif 167 if (itimer.it_value.tv_sec < 0 || 168 itimer.it_value.tv_sec > (1 << EVENT_TIMEOUT)) 169 itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 170 if (itimer.it_value.itv_frac < 0) 171 itimer.it_value.itv_frac = 0; 172 if (0 == itimer.it_value.tv_sec && 173 0 == itimer.it_value.itv_frac) 174 itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 175 itimer.it_interval.tv_sec = (1 << EVENT_TIMEOUT); 176 itimer.it_interval.itv_frac = 0; 177 set_timer_or_die(&itimer); 178 # endif /* VMS */ 179 } 180 181 182 /* 183 * init_timer - initialize the timer data structures 184 */ 185 void 186 init_timer(void) 187 { 188 /* 189 * Initialize... 190 */ 191 alarm_flag = FALSE; 192 alarm_overflow = 0; 193 adjust_timer = 1; 194 stats_timer = SECSPERHR; 195 leapf_timer = SECSPERDAY; 196 huffpuff_timer = 0; 197 interface_timer = 0; 198 current_time = 0; 199 timer_overflows = 0; 200 timer_xmtcalls = 0; 201 timer_timereset = 0; 202 203 #ifndef SYS_WINNT 204 /* 205 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT 206 * seconds from now and they continue on every 2**EVENT_TIMEOUT 207 * seconds. 208 */ 209 # ifndef VMS 210 # ifdef HAVE_TIMER_CREATE 211 if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) { 212 msyslog(LOG_ERR, "timer_create failed, %m"); 213 exit(1); 214 } 215 # endif 216 signal_no_reset(SIGALRM, alarming); 217 itimer.it_interval.tv_sec = 218 itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 219 itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0; 220 set_timer_or_die(&itimer); 221 # else /* VMS follows */ 222 vmsinc[0] = 10000000; /* 1 sec */ 223 vmsinc[1] = 0; 224 lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); 225 226 sys$gettim(&vmstimer); /* that's "now" as abstime */ 227 228 lib$addx(&vmsinc, &vmstimer, &vmstimer); 229 sys$setimr(0, &vmstimer, alarming, alarming, 0); 230 # endif /* VMS */ 231 #else /* SYS_WINNT follows */ 232 /* 233 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds 234 * Under Windows/NT, 235 */ 236 237 WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); 238 if (WaitableTimerHandle == NULL) { 239 msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); 240 exit(1); 241 } 242 else { 243 DWORD Period; 244 LARGE_INTEGER DueTime; 245 BOOL rc; 246 247 Period = (1 << EVENT_TIMEOUT) * 1000; 248 DueTime.QuadPart = Period * 10000i64; 249 rc = SetWaitableTimer(WaitableTimerHandle, &DueTime, 250 Period, NULL, NULL, FALSE); 251 if (!rc) { 252 msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); 253 exit(1); 254 } 255 } 256 257 #endif /* SYS_WINNT */ 258 } 259 260 261 /* 262 * intres_timeout_req(s) is invoked in the parent to schedule an idle 263 * timeout to fire in s seconds, if not reset earlier by a call to 264 * intres_timeout_req(0), which clears any pending timeout. When the 265 * timeout expires, worker_idle_timer_fired() is invoked (again, in the 266 * parent). 267 * 268 * sntp and ntpd each provide implementations adapted to their timers. 269 */ 270 void 271 intres_timeout_req( 272 u_int seconds /* 0 cancels */ 273 ) 274 { 275 if (0 == seconds) { 276 worker_idle_timer = 0; 277 return; 278 } 279 worker_idle_timer = current_time + seconds; 280 } 281 282 283 /* 284 * timer - event timer 285 */ 286 void 287 timer(void) 288 { 289 struct peer * p; 290 struct peer * next_peer; 291 l_fp now; 292 time_t tnow; 293 294 /* 295 * The basic timerevent is one second. This is used to adjust the 296 * system clock in time and frequency, implement the kiss-o'-death 297 * function and the association polling function. 298 */ 299 current_time++; 300 if (adjust_timer <= current_time) { 301 adjust_timer += 1; 302 adj_host_clock(); 303 #ifdef REFCLOCK 304 for (p = peer_list; p != NULL; p = next_peer) { 305 next_peer = p->p_link; 306 if (FLAG_REFCLOCK & p->flags) 307 refclock_timer(p); 308 } 309 #endif /* REFCLOCK */ 310 } 311 312 /* 313 * Now dispatch any peers whose event timer has expired. Be 314 * careful here, since the peer structure might go away as the 315 * result of the call. 316 */ 317 for (p = peer_list; p != NULL; p = next_peer) { 318 next_peer = p->p_link; 319 320 /* 321 * Restrain the non-burst packet rate not more 322 * than one packet every 16 seconds. This is 323 * usually tripped using iburst and minpoll of 324 * 128 s or less. 325 */ 326 if (p->throttle > 0) 327 p->throttle--; 328 if (p->nextdate <= current_time) { 329 #ifdef REFCLOCK 330 if (FLAG_REFCLOCK & p->flags) 331 refclock_transmit(p); 332 else 333 #endif /* REFCLOCK */ 334 transmit(p); 335 } 336 } 337 338 /* 339 * Orphan mode is active when enabled and when no servers less 340 * than the orphan stratum are available. A server with no other 341 * synchronization source is an orphan. It shows offset zero and 342 * reference ID the loopback address. 343 */ 344 if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL && 345 current_time > orphwait) { 346 if (sys_leap == LEAP_NOTINSYNC) { 347 set_sys_leap(LEAP_NOWARNING); 348 #ifdef AUTOKEY 349 if (crypto_flags) 350 crypto_update(); 351 #endif /* AUTOKEY */ 352 } 353 sys_stratum = (u_char)sys_orphan; 354 if (sys_stratum > 1) 355 sys_refid = htonl(LOOPBACKADR); 356 else 357 memcpy(&sys_refid, "LOOP", 4); 358 sys_offset = 0; 359 sys_rootdelay = 0; 360 sys_rootdisp = 0; 361 } 362 363 get_systime(&now); 364 time(&tnow); 365 366 /* 367 * Leapseconds. Get time and defer to worker if either something 368 * is imminent or every 8th second. 369 */ 370 if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7)) 371 check_leapsec(now.l_ui, &tnow, 372 (sys_leap == LEAP_NOTINSYNC)); 373 if (sys_leap != LEAP_NOTINSYNC) { 374 if (leapsec >= LSPROX_ANNOUNCE && leapdif) { 375 if (leapdif > 0) 376 set_sys_leap(LEAP_ADDSECOND); 377 else 378 set_sys_leap(LEAP_DELSECOND); 379 } else { 380 set_sys_leap(LEAP_NOWARNING); 381 } 382 } 383 384 /* 385 * Update huff-n'-puff filter. 386 */ 387 if (huffpuff_timer <= current_time) { 388 huffpuff_timer += HUFFPUFF; 389 huffpuff(); 390 } 391 392 #ifdef AUTOKEY 393 /* 394 * Garbage collect expired keys. 395 */ 396 if (keys_timer <= current_time) { 397 keys_timer += 1 << sys_automax; 398 auth_agekeys(); 399 } 400 401 /* 402 * Generate new private value. This causes all associations 403 * to regenerate cookies. 404 */ 405 if (revoke_timer && revoke_timer <= current_time) { 406 revoke_timer += 1 << sys_revoke; 407 RAND_bytes((u_char *)&sys_private, 4); 408 } 409 #endif /* AUTOKEY */ 410 411 /* 412 * Interface update timer 413 */ 414 if (interface_interval && interface_timer <= current_time) { 415 timer_interfacetimeout(current_time + 416 interface_interval); 417 DPRINTF(2, ("timer: interface update\n")); 418 interface_update(NULL, NULL); 419 } 420 421 if (worker_idle_timer && worker_idle_timer <= current_time) 422 worker_idle_timer_fired(); 423 424 /* 425 * Finally, write hourly stats and do the hourly 426 * and daily leapfile checks. 427 */ 428 if (stats_timer <= current_time) { 429 stats_timer += SECSPERHR; 430 write_stats(); 431 if (leapf_timer <= current_time) { 432 leapf_timer += SECSPERDAY; 433 check_leap_file(TRUE, now.l_ui, &tnow); 434 } else { 435 check_leap_file(FALSE, now.l_ui, &tnow); 436 } 437 } 438 } 439 440 441 #ifndef SYS_WINNT 442 /* 443 * alarming - tell the world we've been alarmed 444 */ 445 static RETSIGTYPE 446 alarming( 447 int sig 448 ) 449 { 450 # ifdef DEBUG 451 const char *msg = "alarming: initializing TRUE\n"; 452 # endif 453 454 if (!initializing) { 455 if (alarm_flag) { 456 alarm_overflow++; 457 # ifdef DEBUG 458 msg = "alarming: overflow\n"; 459 # endif 460 } else { 461 # ifndef VMS 462 alarm_flag++; 463 # else 464 /* VMS AST routine, increment is no good */ 465 alarm_flag = 1; 466 # endif 467 # ifdef DEBUG 468 msg = "alarming: normal\n"; 469 # endif 470 } 471 } 472 # ifdef VMS 473 lib$addx(&vmsinc, &vmstimer, &vmstimer); 474 sys$setimr(0, &vmstimer, alarming, alarming, 0); 475 # endif 476 # ifdef DEBUG 477 if (debug >= 4) 478 (void)(-1 == write(1, msg, strlen(msg))); 479 # endif 480 } 481 #endif /* SYS_WINNT */ 482 483 484 void 485 timer_interfacetimeout(u_long timeout) 486 { 487 interface_timer = timeout; 488 } 489 490 491 /* 492 * timer_clr_stats - clear timer module stat counters 493 */ 494 void 495 timer_clr_stats(void) 496 { 497 timer_overflows = 0; 498 timer_xmtcalls = 0; 499 timer_timereset = current_time; 500 } 501 502 503 static void 504 check_leap_sec_in_progress( const leap_result_t *lsdata ) { 505 int prv_leap_sec_in_progress = leap_sec_in_progress; 506 leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3); 507 508 /* if changed we may have to update the leap status sent to clients */ 509 if (leap_sec_in_progress != prv_leap_sec_in_progress) 510 set_sys_leap(sys_leap); 511 } 512 513 514 static void 515 check_leapsec( 516 u_int32 now , 517 const time_t * tpiv , 518 int/*BOOL*/ reset) 519 { 520 static const char leapmsg_p_step[] = 521 "Positive leap second, stepped backward."; 522 static const char leapmsg_p_slew[] = 523 "Positive leap second, no step correction. " 524 "System clock will be inaccurate for a long time."; 525 526 static const char leapmsg_n_step[] = 527 "Negative leap second, stepped forward."; 528 static const char leapmsg_n_slew[] = 529 "Negative leap second, no step correction. " 530 "System clock will be inaccurate for a long time."; 531 532 leap_result_t lsdata; 533 u_int32 lsprox; 534 #ifdef AUTOKEY 535 int/*BOOL*/ update_autokey = FALSE; 536 #endif 537 538 #ifndef SYS_WINNT /* WinNT port has its own leap second handling */ 539 # ifdef KERNEL_PLL 540 leapsec_electric(pll_control && kern_enable); 541 # else 542 leapsec_electric(0); 543 # endif 544 #endif 545 #ifdef LEAP_SMEAR 546 leap_smear.enabled = leap_smear_intv != 0; 547 #endif 548 if (reset) { 549 lsprox = LSPROX_NOWARN; 550 leapsec_reset_frame(); 551 memset(&lsdata, 0, sizeof(lsdata)); 552 } else { 553 int fired = leapsec_query(&lsdata, now, tpiv); 554 555 DPRINTF(1, ("*** leapsec_query: fired %i, now %u (0x%08X), tai_diff %i, ddist %u\n", 556 fired, now, now, lsdata.tai_diff, lsdata.ddist)); 557 558 #ifdef LEAP_SMEAR 559 leap_smear.in_progress = 0; 560 leap_smear.doffset = 0.0; 561 562 if (leap_smear.enabled) { 563 if (lsdata.tai_diff) { 564 if (leap_smear.interval == 0) { 565 leap_smear.interval = leap_smear_intv; 566 leap_smear.intv_end = lsdata.ttime.Q_s; 567 leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval; 568 DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n", 569 leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end)); 570 } 571 } 572 else { 573 if (leap_smear.interval) 574 DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n")); 575 leap_smear.interval = 0; 576 } 577 578 if (leap_smear.interval) { 579 double dtemp = now; 580 if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) { 581 double leap_smear_time = dtemp - leap_smear.intv_start; 582 /* 583 * For now we just do a linear interpolation over the smear interval 584 */ 585 #if 0 586 // linear interpolation 587 leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval); 588 #else 589 // Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0 590 leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0; 591 #endif 592 /* 593 * TODO see if we're inside an inserted leap second, so we need to compute 594 * leap_smear.doffset = 1.0 - leap_smear.doffset 595 */ 596 leap_smear.in_progress = 1; 597 #if 0 && defined( DEBUG ) 598 msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", 599 leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, 600 now, leap_smear_time, leap_smear.doffset); 601 #else 602 DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", 603 leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, 604 now, leap_smear_time, leap_smear.doffset)); 605 #endif 606 607 } 608 } 609 } 610 else 611 leap_smear.interval = 0; 612 613 /* 614 * Update the current leap smear offset, eventually 0.0 if outside smear interval. 615 */ 616 DTOLFP(leap_smear.doffset, &leap_smear.offset); 617 618 #endif /* LEAP_SMEAR */ 619 620 if (fired) { 621 /* Full hit. Eventually step the clock, but always 622 * announce the leap event has happened. 623 */ 624 const char *leapmsg = NULL; 625 if (lsdata.warped < 0) { 626 if (clock_max_back > 0.0 && 627 clock_max_back < abs(lsdata.warped)) { 628 step_systime(lsdata.warped); 629 leapmsg = leapmsg_p_step; 630 } else { 631 leapmsg = leapmsg_p_slew; 632 } 633 } else if (lsdata.warped > 0) { 634 if (clock_max_fwd > 0.0 && 635 clock_max_fwd < abs(lsdata.warped)) { 636 step_systime(lsdata.warped); 637 leapmsg = leapmsg_n_step; 638 } else { 639 leapmsg = leapmsg_n_slew; 640 } 641 } 642 if (leapmsg) 643 msyslog(LOG_NOTICE, "%s", leapmsg); 644 report_event(EVNT_LEAP, NULL, NULL); 645 #ifdef AUTOKEY 646 update_autokey = TRUE; 647 #endif 648 lsprox = LSPROX_NOWARN; 649 leapsec = LSPROX_NOWARN; 650 sys_tai = lsdata.tai_offs; 651 } else { 652 #ifdef AUTOKEY 653 update_autokey = (sys_tai != (u_int)lsdata.tai_offs); 654 #endif 655 lsprox = lsdata.proximity; 656 sys_tai = lsdata.tai_offs; 657 } 658 } 659 660 /* We guard against panic alarming during the red alert phase. 661 * Strange and evil things might happen if we go from stone cold 662 * to piping hot in one step. If things are already that wobbly, 663 * we let the normal clock correction take over, even if a jump 664 * is involved. 665 * Also make sure the alarming events are edge-triggered, that is, 666 * ceated only when the threshold is crossed. 667 */ 668 if ( (leapsec > 0 || lsprox < LSPROX_ALERT) 669 && leapsec < lsprox ) { 670 if ( leapsec < LSPROX_SCHEDULE 671 && lsprox >= LSPROX_SCHEDULE) { 672 if (lsdata.dynamic) 673 report_event(PEVNT_ARMED, sys_peer, NULL); 674 else 675 report_event(EVNT_ARMED, NULL, NULL); 676 } 677 leapsec = lsprox; 678 } 679 if (leapsec > lsprox) { 680 if ( leapsec >= LSPROX_SCHEDULE 681 && lsprox < LSPROX_SCHEDULE) { 682 report_event(EVNT_DISARMED, NULL, NULL); 683 } 684 leapsec = lsprox; 685 } 686 687 if (leapsec >= LSPROX_SCHEDULE) 688 leapdif = lsdata.tai_diff; 689 else 690 leapdif = 0; 691 692 check_leap_sec_in_progress(&lsdata); 693 694 #ifdef AUTOKEY 695 if (update_autokey) 696 crypto_update_taichange(); 697 #endif 698 } 699