ntp_timer.c revision 298699
1275970Scy/* 2275970Scy * ntp_timer.c - event timer support routines 3275970Scy */ 4275970Scy#ifdef HAVE_CONFIG_H 5275970Scy# include <config.h> 6275970Scy#endif 7275970Scy 8275970Scy#include "ntp_machine.h" 9275970Scy#include "ntpd.h" 10275970Scy#include "ntp_stdlib.h" 11275970Scy#include "ntp_calendar.h" 12275970Scy#include "ntp_leapsec.h" 13275970Scy 14275970Scy#if defined(HAVE_IO_COMPLETION_PORT) 15275970Scy# include "ntp_iocompletionport.h" 16275970Scy# include "ntp_timer.h" 17275970Scy#endif 18275970Scy 19275970Scy#include <stdio.h> 20275970Scy#include <signal.h> 21275970Scy#ifdef HAVE_SYS_SIGNAL_H 22275970Scy# include <sys/signal.h> 23275970Scy#endif 24275970Scy#ifdef HAVE_UNISTD_H 25275970Scy# include <unistd.h> 26275970Scy#endif 27275970Scy 28275970Scy#ifdef KERNEL_PLL 29275970Scy#include "ntp_syscall.h" 30275970Scy#endif /* KERNEL_PLL */ 31275970Scy 32275970Scy#ifdef AUTOKEY 33275970Scy#include <openssl/rand.h> 34275970Scy#endif /* AUTOKEY */ 35275970Scy 36275970Scy 37275970Scy/* TC_ERR represents the timer_create() error return value. */ 38275970Scy#ifdef SYS_VXWORKS 39275970Scy#define TC_ERR ERROR 40275970Scy#else 41275970Scy#define TC_ERR (-1) 42275970Scy#endif 43275970Scy 44275970Scy 45275970Scystatic void check_leapsec(u_int32, const time_t*, int/*BOOL*/); 46275970Scy 47275970Scy/* 48275970Scy * These routines provide support for the event timer. The timer is 49275970Scy * implemented by an interrupt routine which sets a flag once every 50275970Scy * second, and a timer routine which is called when the mainline code 51275970Scy * gets around to seeing the flag. The timer routine dispatches the 52275970Scy * clock adjustment code if its time has come, then searches the timer 53275970Scy * queue for expiries which are dispatched to the transmit procedure. 54275970Scy * Finally, we call the hourly procedure to do cleanup and print a 55275970Scy * message. 56275970Scy */ 57275970Scyvolatile int interface_interval; /* init_io() sets def. 300s */ 58275970Scy 59275970Scy/* 60275970Scy * Initializing flag. All async routines watch this and only do their 61275970Scy * thing when it is clear. 62275970Scy */ 63275970Scyint initializing; 64275970Scy 65275970Scy/* 66275970Scy * Alarm flag. The mainline code imports this. 67275970Scy */ 68275970Scyvolatile int alarm_flag; 69275970Scy 70275970Scy/* 71275970Scy * The counters and timeouts 72275970Scy */ 73275970Scystatic u_long interface_timer; /* interface update timer */ 74275970Scystatic u_long adjust_timer; /* second timer */ 75275970Scystatic u_long stats_timer; /* stats timer */ 76275970Scystatic u_long leapf_timer; /* Report leapfile problems once/day */ 77275970Scystatic u_long huffpuff_timer; /* huff-n'-puff timer */ 78275970Scystatic u_long worker_idle_timer;/* next check for idle intres */ 79275970Scyu_long leapsec; /* seconds to next leap (proximity class) */ 80275970Scyint leapdif; /* TAI difference step at next leap second*/ 81275970Scyu_long orphwait; /* orphan wait time */ 82275970Scy#ifdef AUTOKEY 83275970Scystatic u_long revoke_timer; /* keys revoke timer */ 84275970Scystatic u_long keys_timer; /* session key timer */ 85275970Scyu_long sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ 86275970Scyu_long sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */ 87275970Scy#endif /* AUTOKEY */ 88275970Scy 89275970Scy/* 90275970Scy * Statistics counter for the interested. 91275970Scy */ 92275970Scyvolatile u_long alarm_overflow; 93275970Scy 94275970Scyu_long current_time; /* seconds since startup */ 95275970Scy 96275970Scy/* 97275970Scy * Stats. Number of overflows and number of calls to transmit(). 98275970Scy */ 99275970Scyu_long timer_timereset; 100275970Scyu_long timer_overflows; 101275970Scyu_long timer_xmtcalls; 102275970Scy 103275970Scy#if defined(VMS) 104275970Scystatic int vmstimer[2]; /* time for next timer AST */ 105275970Scystatic int vmsinc[2]; /* timer increment */ 106275970Scy#endif /* VMS */ 107275970Scy 108275970Scy#ifdef SYS_WINNT 109275970ScyHANDLE WaitableTimerHandle; 110275970Scy#else 111275970Scystatic RETSIGTYPE alarming (int); 112275970Scy#endif /* SYS_WINNT */ 113275970Scy 114275970Scy#if !defined(VMS) 115275970Scy# if !defined SYS_WINNT || defined(SYS_CYGWIN32) 116275970Scy# ifdef HAVE_TIMER_CREATE 117275970Scystatic timer_t timer_id; 118275970Scytypedef struct itimerspec intervaltimer; 119275970Scy# define itv_frac tv_nsec 120275970Scy# else 121275970Scytypedef struct itimerval intervaltimer; 122275970Scy# define itv_frac tv_usec 123275970Scy# endif 124275970Scyintervaltimer itimer; 125275970Scy# endif 126275970Scy#endif 127275970Scy 128275970Scy#if !defined(SYS_WINNT) && !defined(VMS) 129275970Scyvoid set_timer_or_die(const intervaltimer *); 130275970Scy#endif 131275970Scy 132275970Scy 133275970Scy#if !defined(SYS_WINNT) && !defined(VMS) 134275970Scyvoid 135275970Scyset_timer_or_die( 136275970Scy const intervaltimer * ptimer 137275970Scy ) 138275970Scy{ 139275970Scy const char * setfunc; 140275970Scy int rc; 141275970Scy 142275970Scy# ifdef HAVE_TIMER_CREATE 143275970Scy setfunc = "timer_settime"; 144275970Scy rc = timer_settime(timer_id, 0, &itimer, NULL); 145275970Scy# else 146275970Scy setfunc = "setitimer"; 147275970Scy rc = setitimer(ITIMER_REAL, &itimer, NULL); 148275970Scy# endif 149275970Scy if (-1 == rc) { 150275970Scy msyslog(LOG_ERR, "interval timer %s failed, %m", 151275970Scy setfunc); 152275970Scy exit(1); 153275970Scy } 154275970Scy} 155275970Scy#endif /* !SYS_WINNT && !VMS */ 156275970Scy 157275970Scy 158275970Scy/* 159275970Scy * reinit_timer - reinitialize interval timer after a clock step. 160275970Scy */ 161275970Scyvoid 162275970Scyreinit_timer(void) 163275970Scy{ 164275970Scy#if !defined(SYS_WINNT) && !defined(VMS) 165275970Scy ZERO(itimer); 166275970Scy# ifdef HAVE_TIMER_CREATE 167275970Scy timer_gettime(timer_id, &itimer); 168275970Scy# else 169275970Scy getitimer(ITIMER_REAL, &itimer); 170275970Scy# endif 171275970Scy if (itimer.it_value.tv_sec < 0 || 172275970Scy itimer.it_value.tv_sec > (1 << EVENT_TIMEOUT)) 173275970Scy itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 174275970Scy if (itimer.it_value.itv_frac < 0) 175275970Scy itimer.it_value.itv_frac = 0; 176275970Scy if (0 == itimer.it_value.tv_sec && 177275970Scy 0 == itimer.it_value.itv_frac) 178275970Scy itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 179275970Scy itimer.it_interval.tv_sec = (1 << EVENT_TIMEOUT); 180275970Scy itimer.it_interval.itv_frac = 0; 181275970Scy set_timer_or_die(&itimer); 182275970Scy# endif /* VMS */ 183275970Scy} 184275970Scy 185275970Scy 186275970Scy/* 187275970Scy * init_timer - initialize the timer data structures 188275970Scy */ 189275970Scyvoid 190275970Scyinit_timer(void) 191275970Scy{ 192275970Scy /* 193275970Scy * Initialize... 194275970Scy */ 195275970Scy alarm_flag = FALSE; 196275970Scy alarm_overflow = 0; 197275970Scy adjust_timer = 1; 198275970Scy stats_timer = SECSPERHR; 199275970Scy leapf_timer = SECSPERDAY; 200275970Scy huffpuff_timer = 0; 201275970Scy interface_timer = 0; 202275970Scy current_time = 0; 203275970Scy timer_overflows = 0; 204275970Scy timer_xmtcalls = 0; 205275970Scy timer_timereset = 0; 206275970Scy 207275970Scy#ifndef SYS_WINNT 208275970Scy /* 209275970Scy * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT 210275970Scy * seconds from now and they continue on every 2**EVENT_TIMEOUT 211275970Scy * seconds. 212275970Scy */ 213275970Scy# ifndef VMS 214275970Scy# ifdef HAVE_TIMER_CREATE 215275970Scy if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) { 216275970Scy msyslog(LOG_ERR, "timer_create failed, %m"); 217275970Scy exit(1); 218275970Scy } 219275970Scy# endif 220275970Scy signal_no_reset(SIGALRM, alarming); 221275970Scy itimer.it_interval.tv_sec = 222275970Scy itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 223275970Scy itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0; 224275970Scy set_timer_or_die(&itimer); 225275970Scy# else /* VMS follows */ 226275970Scy vmsinc[0] = 10000000; /* 1 sec */ 227275970Scy vmsinc[1] = 0; 228275970Scy lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); 229275970Scy 230275970Scy sys$gettim(&vmstimer); /* that's "now" as abstime */ 231275970Scy 232275970Scy lib$addx(&vmsinc, &vmstimer, &vmstimer); 233275970Scy sys$setimr(0, &vmstimer, alarming, alarming, 0); 234275970Scy# endif /* VMS */ 235275970Scy#else /* SYS_WINNT follows */ 236275970Scy /* 237275970Scy * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds 238275970Scy * Under Windows/NT, 239275970Scy */ 240275970Scy 241275970Scy WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); 242275970Scy if (WaitableTimerHandle == NULL) { 243275970Scy msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); 244275970Scy exit(1); 245275970Scy } 246275970Scy else { 247275970Scy DWORD Period; 248275970Scy LARGE_INTEGER DueTime; 249275970Scy BOOL rc; 250275970Scy 251275970Scy Period = (1 << EVENT_TIMEOUT) * 1000; 252275970Scy DueTime.QuadPart = Period * 10000i64; 253275970Scy rc = SetWaitableTimer(WaitableTimerHandle, &DueTime, 254275970Scy Period, NULL, NULL, FALSE); 255275970Scy if (!rc) { 256275970Scy msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); 257275970Scy exit(1); 258275970Scy } 259275970Scy } 260275970Scy 261275970Scy#endif /* SYS_WINNT */ 262275970Scy} 263275970Scy 264275970Scy 265275970Scy/* 266275970Scy * intres_timeout_req(s) is invoked in the parent to schedule an idle 267275970Scy * timeout to fire in s seconds, if not reset earlier by a call to 268275970Scy * intres_timeout_req(0), which clears any pending timeout. When the 269275970Scy * timeout expires, worker_idle_timer_fired() is invoked (again, in the 270275970Scy * parent). 271275970Scy * 272275970Scy * sntp and ntpd each provide implementations adapted to their timers. 273275970Scy */ 274275970Scyvoid 275275970Scyintres_timeout_req( 276275970Scy u_int seconds /* 0 cancels */ 277275970Scy ) 278275970Scy{ 279275970Scy#if defined(HAVE_DROPROOT) && defined(NEED_EARLY_FORK) 280275970Scy if (droproot) { 281275970Scy worker_idle_timer = 0; 282275970Scy return; 283275970Scy } 284275970Scy#endif 285275970Scy if (0 == seconds) { 286275970Scy worker_idle_timer = 0; 287275970Scy return; 288275970Scy } 289275970Scy worker_idle_timer = current_time + seconds; 290275970Scy} 291275970Scy 292275970Scy 293275970Scy/* 294275970Scy * timer - event timer 295275970Scy */ 296275970Scyvoid 297275970Scytimer(void) 298275970Scy{ 299275970Scy struct peer * p; 300275970Scy struct peer * next_peer; 301275970Scy l_fp now; 302275970Scy time_t tnow; 303275970Scy 304275970Scy /* 305275970Scy * The basic timerevent is one second. This is used to adjust the 306275970Scy * system clock in time and frequency, implement the kiss-o'-death 307275970Scy * function and the association polling function. 308275970Scy */ 309275970Scy current_time++; 310275970Scy if (adjust_timer <= current_time) { 311275970Scy adjust_timer += 1; 312275970Scy adj_host_clock(); 313275970Scy#ifdef REFCLOCK 314275970Scy for (p = peer_list; p != NULL; p = next_peer) { 315275970Scy next_peer = p->p_link; 316275970Scy if (FLAG_REFCLOCK & p->flags) 317275970Scy refclock_timer(p); 318275970Scy } 319275970Scy#endif /* REFCLOCK */ 320275970Scy } 321275970Scy 322275970Scy /* 323275970Scy * Now dispatch any peers whose event timer has expired. Be 324275970Scy * careful here, since the peer structure might go away as the 325275970Scy * result of the call. 326275970Scy */ 327275970Scy for (p = peer_list; p != NULL; p = next_peer) { 328275970Scy next_peer = p->p_link; 329275970Scy 330275970Scy /* 331275970Scy * Restrain the non-burst packet rate not more 332275970Scy * than one packet every 16 seconds. This is 333275970Scy * usually tripped using iburst and minpoll of 334275970Scy * 128 s or less. 335275970Scy */ 336275970Scy if (p->throttle > 0) 337275970Scy p->throttle--; 338275970Scy if (p->nextdate <= current_time) { 339275970Scy#ifdef REFCLOCK 340275970Scy if (FLAG_REFCLOCK & p->flags) 341275970Scy refclock_transmit(p); 342275970Scy else 343275970Scy#endif /* REFCLOCK */ 344275970Scy transmit(p); 345275970Scy } 346275970Scy } 347275970Scy 348275970Scy /* 349275970Scy * Orphan mode is active when enabled and when no servers less 350275970Scy * than the orphan stratum are available. A server with no other 351275970Scy * synchronization source is an orphan. It shows offset zero and 352275970Scy * reference ID the loopback address. 353275970Scy */ 354275970Scy if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL && 355275970Scy current_time > orphwait) { 356275970Scy if (sys_leap == LEAP_NOTINSYNC) { 357275970Scy set_sys_leap(LEAP_NOWARNING); 358275970Scy#ifdef AUTOKEY 359275970Scy if (crypto_flags) 360275970Scy crypto_update(); 361275970Scy#endif /* AUTOKEY */ 362275970Scy } 363275970Scy sys_stratum = (u_char)sys_orphan; 364275970Scy if (sys_stratum > 1) 365275970Scy sys_refid = htonl(LOOPBACKADR); 366275970Scy else 367275970Scy memcpy(&sys_refid, "LOOP", 4); 368275970Scy sys_offset = 0; 369275970Scy sys_rootdelay = 0; 370275970Scy sys_rootdisp = 0; 371275970Scy } 372275970Scy 373275970Scy get_systime(&now); 374275970Scy time(&tnow); 375275970Scy 376275970Scy /* 377275970Scy * Leapseconds. Get time and defer to worker if either something 378275970Scy * is imminent or every 8th second. 379275970Scy */ 380275970Scy if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7)) 381275970Scy check_leapsec(now.l_ui, &tnow, 382275970Scy (sys_leap == LEAP_NOTINSYNC)); 383275970Scy if (sys_leap != LEAP_NOTINSYNC) { 384275970Scy if (leapsec >= LSPROX_ANNOUNCE && leapdif) { 385275970Scy if (leapdif > 0) 386275970Scy set_sys_leap(LEAP_ADDSECOND); 387275970Scy else 388275970Scy set_sys_leap(LEAP_DELSECOND); 389275970Scy } else { 390275970Scy set_sys_leap(LEAP_NOWARNING); 391275970Scy } 392275970Scy } 393275970Scy 394275970Scy /* 395275970Scy * Update huff-n'-puff filter. 396275970Scy */ 397275970Scy if (huffpuff_timer <= current_time) { 398275970Scy huffpuff_timer += HUFFPUFF; 399275970Scy huffpuff(); 400275970Scy } 401275970Scy 402275970Scy#ifdef AUTOKEY 403275970Scy /* 404275970Scy * Garbage collect expired keys. 405275970Scy */ 406275970Scy if (keys_timer <= current_time) { 407275970Scy keys_timer += 1 << sys_automax; 408275970Scy auth_agekeys(); 409275970Scy } 410275970Scy 411275970Scy /* 412275970Scy * Generate new private value. This causes all associations 413275970Scy * to regenerate cookies. 414275970Scy */ 415275970Scy if (revoke_timer && revoke_timer <= current_time) { 416275970Scy revoke_timer += 1 << sys_revoke; 417275970Scy RAND_bytes((u_char *)&sys_private, 4); 418275970Scy } 419275970Scy#endif /* AUTOKEY */ 420275970Scy 421275970Scy /* 422275970Scy * Interface update timer 423275970Scy */ 424275970Scy if (interface_interval && interface_timer <= current_time) { 425275970Scy timer_interfacetimeout(current_time + 426275970Scy interface_interval); 427275970Scy DPRINTF(2, ("timer: interface update\n")); 428275970Scy interface_update(NULL, NULL); 429275970Scy } 430275970Scy 431275970Scy if (worker_idle_timer && worker_idle_timer <= current_time) 432275970Scy worker_idle_timer_fired(); 433275970Scy 434275970Scy /* 435275970Scy * Finally, write hourly stats and do the hourly 436275970Scy * and daily leapfile checks. 437275970Scy */ 438275970Scy if (stats_timer <= current_time) { 439275970Scy stats_timer += SECSPERHR; 440275970Scy write_stats(); 441275970Scy if (leapf_timer <= current_time) { 442275970Scy leapf_timer += SECSPERDAY; 443275970Scy check_leap_file(TRUE, now.l_ui, &tnow); 444275970Scy } else { 445275970Scy check_leap_file(FALSE, now.l_ui, &tnow); 446275970Scy } 447275970Scy } 448275970Scy} 449275970Scy 450275970Scy 451275970Scy#ifndef SYS_WINNT 452275970Scy/* 453275970Scy * alarming - tell the world we've been alarmed 454275970Scy */ 455275970Scystatic RETSIGTYPE 456275970Scyalarming( 457275970Scy int sig 458275970Scy ) 459275970Scy{ 460275970Scy# ifdef DEBUG 461275970Scy const char *msg = "alarming: initializing TRUE\n"; 462275970Scy# endif 463275970Scy 464275970Scy if (!initializing) { 465275970Scy if (alarm_flag) { 466275970Scy alarm_overflow++; 467275970Scy# ifdef DEBUG 468275970Scy msg = "alarming: overflow\n"; 469275970Scy# endif 470275970Scy } else { 471275970Scy# ifndef VMS 472275970Scy alarm_flag++; 473275970Scy# else 474275970Scy /* VMS AST routine, increment is no good */ 475275970Scy alarm_flag = 1; 476275970Scy# endif 477275970Scy# ifdef DEBUG 478275970Scy msg = "alarming: normal\n"; 479275970Scy# endif 480275970Scy } 481275970Scy } 482275970Scy# ifdef VMS 483275970Scy lib$addx(&vmsinc, &vmstimer, &vmstimer); 484275970Scy sys$setimr(0, &vmstimer, alarming, alarming, 0); 485275970Scy# endif 486275970Scy# ifdef DEBUG 487275970Scy if (debug >= 4) 488275970Scy (void)(-1 == write(1, msg, strlen(msg))); 489275970Scy# endif 490275970Scy} 491275970Scy#endif /* SYS_WINNT */ 492275970Scy 493275970Scy 494275970Scyvoid 495275970Scytimer_interfacetimeout(u_long timeout) 496275970Scy{ 497275970Scy interface_timer = timeout; 498275970Scy} 499275970Scy 500275970Scy 501275970Scy/* 502275970Scy * timer_clr_stats - clear timer module stat counters 503275970Scy */ 504275970Scyvoid 505275970Scytimer_clr_stats(void) 506275970Scy{ 507275970Scy timer_overflows = 0; 508275970Scy timer_xmtcalls = 0; 509275970Scy timer_timereset = current_time; 510275970Scy} 511275970Scy 512275970Scy 513275970Scystatic void 514275970Scycheck_leap_sec_in_progress( const leap_result_t *lsdata ) { 515275970Scy int prv_leap_sec_in_progress = leap_sec_in_progress; 516275970Scy leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3); 517275970Scy 518275970Scy /* if changed we may have to update the leap status sent to clients */ 519275970Scy if (leap_sec_in_progress != prv_leap_sec_in_progress) 520275970Scy set_sys_leap(sys_leap); 521275970Scy} 522275970Scy 523275970Scy 524275970Scystatic void 525275970Scycheck_leapsec( 526275970Scy u_int32 now , 527275970Scy const time_t * tpiv , 528275970Scy int/*BOOL*/ reset) 529275970Scy{ 530275970Scy static const char leapmsg_p_step[] = 531275970Scy "Positive leap second, stepped backward."; 532285612Sdelphij static const char leapmsg_p_slew[] = 533275970Scy "Positive leap second, no step correction. " 534275970Scy "System clock will be inaccurate for a long time."; 535275970Scy 536275970Scy static const char leapmsg_n_step[] = 537275970Scy "Negative leap second, stepped forward."; 538285612Sdelphij static const char leapmsg_n_slew[] = 539275970Scy "Negative leap second, no step correction. " 540275970Scy "System clock will be inaccurate for a long time."; 541275970Scy 542275970Scy leap_result_t lsdata; 543285612Sdelphij u_int32 lsprox; 544285612Sdelphij#ifdef AUTOKEY 545285612Sdelphij int/*BOOL*/ update_autokey = FALSE; 546275970Scy#endif 547275970Scy 548275970Scy#ifndef SYS_WINNT /* WinNT port has its own leap second handling */ 549275970Scy# ifdef KERNEL_PLL 550275970Scy leapsec_electric(pll_control && kern_enable); 551275970Scy# else 552275970Scy leapsec_electric(0); 553275970Scy# endif 554275970Scy#endif 555275970Scy#ifdef LEAP_SMEAR 556275970Scy leap_smear.enabled = leap_smear_intv != 0; 557275970Scy#endif 558275970Scy if (reset) { 559275970Scy lsprox = LSPROX_NOWARN; 560275970Scy leapsec_reset_frame(); 561275970Scy memset(&lsdata, 0, sizeof(lsdata)); 562275970Scy } else { 563275970Scy int fired; 564275970Scy 565275970Scy fired = leapsec_query(&lsdata, now, tpiv); 566275970Scy 567275970Scy DPRINTF(3, ("*** leapsec_query: fired %i, now %u (0x%08X), tai_diff %i, ddist %u\n", 568275970Scy fired, now, now, lsdata.tai_diff, lsdata.ddist)); 569275970Scy 570275970Scy#ifdef LEAP_SMEAR 571275970Scy leap_smear.in_progress = 0; 572275970Scy leap_smear.doffset = 0.0; 573275970Scy 574275970Scy if (leap_smear.enabled) { 575275970Scy if (lsdata.tai_diff) { 576275970Scy if (leap_smear.interval == 0) { 577275970Scy leap_smear.interval = leap_smear_intv; 578275970Scy leap_smear.intv_end = lsdata.ttime.Q_s; 579275970Scy leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval; 580275970Scy DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n", 581275970Scy leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end)); 582275970Scy } 583275970Scy } else { 584275970Scy if (leap_smear.interval) 585275970Scy DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n")); 586275970Scy leap_smear.interval = 0; 587275970Scy } 588275970Scy 589275970Scy if (leap_smear.interval) { 590275970Scy double dtemp = now; 591275970Scy if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) { 592275970Scy double leap_smear_time = dtemp - leap_smear.intv_start; 593275970Scy /* 594275970Scy * For now we just do a linear interpolation over the smear interval 595275970Scy */ 596275970Scy#if 0 597275970Scy // linear interpolation 598275970Scy leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval); 599275970Scy#else 600275970Scy // Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0 601275970Scy leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0; 602275970Scy#endif 603275970Scy /* 604275970Scy * TODO see if we're inside an inserted leap second, so we need to compute 605275970Scy * leap_smear.doffset = 1.0 - leap_smear.doffset 606275970Scy */ 607275970Scy leap_smear.in_progress = 1; 608275970Scy#if 0 && defined( DEBUG ) 609275970Scy msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", 610275970Scy leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, 611275970Scy now, leap_smear_time, leap_smear.doffset); 612275970Scy#else 613275970Scy DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", 614275970Scy leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, 615275970Scy now, leap_smear_time, leap_smear.doffset)); 616275970Scy#endif 617275970Scy 618275970Scy } 619275970Scy } 620275970Scy } 621275970Scy else 622275970Scy leap_smear.interval = 0; 623275970Scy 624275970Scy /* 625275970Scy * Update the current leap smear offset, eventually 0.0 if outside smear interval. 626275970Scy */ 627275970Scy DTOLFP(leap_smear.doffset, &leap_smear.offset); 628275970Scy 629275970Scy#endif /* LEAP_SMEAR */ 630275970Scy 631275970Scy if (fired) { 632275970Scy /* Full hit. Eventually step the clock, but always 633275970Scy * announce the leap event has happened. 634275970Scy */ 635275970Scy const char *leapmsg = NULL; 636275970Scy double lswarp = lsdata.warped; 637275970Scy if (lswarp < 0.0) { 638275970Scy if (clock_max_back > 0.0 && 639275970Scy clock_max_back < -lswarp) { 640275970Scy step_systime(lswarp); 641275970Scy leapmsg = leapmsg_p_step; 642275970Scy } else { 643275970Scy leapmsg = leapmsg_p_slew; 644275970Scy } 645275970Scy } else if (lswarp > 0.0) { 646275970Scy if (clock_max_fwd > 0.0 && 647275970Scy clock_max_fwd < lswarp) { 648275970Scy step_systime(lswarp); 649275970Scy leapmsg = leapmsg_n_step; 650275970Scy } else { 651275970Scy leapmsg = leapmsg_n_slew; 652275970Scy } 653275970Scy } 654275970Scy if (leapmsg) 655275970Scy msyslog(LOG_NOTICE, "%s", leapmsg); 656275970Scy report_event(EVNT_LEAP, NULL, NULL); 657275970Scy#ifdef AUTOKEY 658275970Scy update_autokey = TRUE; 659275970Scy#endif 660275970Scy lsprox = LSPROX_NOWARN; 661275970Scy leapsec = LSPROX_NOWARN; 662275970Scy sys_tai = lsdata.tai_offs; 663275970Scy } else { 664275970Scy#ifdef AUTOKEY 665275970Scy update_autokey = (sys_tai != (u_int)lsdata.tai_offs); 666275970Scy#endif 667275970Scy lsprox = lsdata.proximity; 668275970Scy sys_tai = lsdata.tai_offs; 669275970Scy } 670275970Scy } 671275970Scy 672275970Scy /* We guard against panic alarming during the red alert phase. 673275970Scy * Strange and evil things might happen if we go from stone cold 674275970Scy * to piping hot in one step. If things are already that wobbly, 675275970Scy * we let the normal clock correction take over, even if a jump 676275970Scy * is involved. 677275970Scy * Also make sure the alarming events are edge-triggered, that is, 678275970Scy * ceated only when the threshold is crossed. 679275970Scy */ 680275970Scy if ( (leapsec > 0 || lsprox < LSPROX_ALERT) 681275970Scy && leapsec < lsprox ) { 682275970Scy if ( leapsec < LSPROX_SCHEDULE 683275970Scy && lsprox >= LSPROX_SCHEDULE) { 684275970Scy if (lsdata.dynamic) 685275970Scy report_event(PEVNT_ARMED, sys_peer, NULL); 686275970Scy else 687275970Scy report_event(EVNT_ARMED, NULL, NULL); 688275970Scy } 689275970Scy leapsec = lsprox; 690275970Scy } 691275970Scy if (leapsec > lsprox) { 692275970Scy if ( leapsec >= LSPROX_SCHEDULE 693275970Scy && lsprox < LSPROX_SCHEDULE) { 694275970Scy report_event(EVNT_DISARMED, NULL, NULL); 695275970Scy } 696275970Scy leapsec = lsprox; 697275970Scy } 698275970Scy 699275970Scy if (leapsec >= LSPROX_SCHEDULE) 700275970Scy leapdif = lsdata.tai_diff; 701275970Scy else 702275970Scy leapdif = 0; 703275970Scy 704275970Scy check_leap_sec_in_progress(&lsdata); 705275970Scy 706275970Scy#ifdef AUTOKEY 707275970Scy if (update_autokey) 708275970Scy crypto_update_taichange(); 709275970Scy#endif 710275970Scy} 711275970Scy