154359Sroberto/* 254359Sroberto * ntp_timer.c - event timer support routines 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto# include <config.h> 654359Sroberto#endif 754359Sroberto 882498Sroberto#include "ntp_machine.h" 982498Sroberto#include "ntpd.h" 1082498Sroberto#include "ntp_stdlib.h" 11285612Sdelphij#include "ntp_calendar.h" 12285612Sdelphij#include "ntp_leapsec.h" 1382498Sroberto 14285612Sdelphij#if defined(HAVE_IO_COMPLETION_PORT) 15285612Sdelphij# include "ntp_iocompletionport.h" 16285612Sdelphij# include "ntp_timer.h" 17285612Sdelphij#endif 18285612Sdelphij 1954359Sroberto#include <stdio.h> 2054359Sroberto#include <signal.h> 21106163Sroberto#ifdef HAVE_SYS_SIGNAL_H 22106163Sroberto# include <sys/signal.h> 23106163Sroberto#endif 2482498Sroberto#ifdef HAVE_UNISTD_H 2582498Sroberto# include <unistd.h> 2682498Sroberto#endif 2754359Sroberto 28285612Sdelphij#ifdef KERNEL_PLL 29285612Sdelphij#include "ntp_syscall.h" 30285612Sdelphij#endif /* KERNEL_PLL */ 31285612Sdelphij 32285612Sdelphij#ifdef AUTOKEY 33285612Sdelphij#include <openssl/rand.h> 34285612Sdelphij#endif /* AUTOKEY */ 35285612Sdelphij 36285612Sdelphij 37285612Sdelphij/* TC_ERR represents the timer_create() error return value. */ 38285612Sdelphij#ifdef SYS_VXWORKS 39285612Sdelphij#define TC_ERR ERROR 40285612Sdelphij#else 41285612Sdelphij#define TC_ERR (-1) 4254359Sroberto#endif 4354359Sroberto 44285612Sdelphij 45285612Sdelphijstatic void check_leapsec(u_int32, const time_t*, int/*BOOL*/); 46285612Sdelphij 4754359Sroberto/* 48285612Sdelphij * These routines provide support for the event timer. The timer is 4954359Sroberto * implemented by an interrupt routine which sets a flag once every 50285612Sdelphij * second, and a timer routine which is called when the mainline code 51285612Sdelphij * gets around to seeing the flag. The timer routine dispatches the 52285612Sdelphij * clock adjustment code if its time has come, then searches the timer 53285612Sdelphij * queue for expiries which are dispatched to the transmit procedure. 54285612Sdelphij * Finally, we call the hourly procedure to do cleanup and print a 55285612Sdelphij * message. 5654359Sroberto */ 57285612Sdelphijvolatile int interface_interval; /* init_io() sets def. 300s */ 5854359Sroberto 5954359Sroberto/* 60289997Sglebius * Initializing flag. All async routines watch this and only do their 61289997Sglebius * thing when it is clear. 62289997Sglebius */ 63289997Sglebiusint initializing; 64289997Sglebius 65289997Sglebius/* 66285612Sdelphij * Alarm flag. The mainline code imports this. 6754359Sroberto */ 6854359Srobertovolatile int alarm_flag; 6954359Sroberto 7054359Sroberto/* 71285612Sdelphij * The counters and timeouts 7254359Sroberto */ 73285612Sdelphijstatic u_long interface_timer; /* interface update timer */ 74285612Sdelphijstatic u_long adjust_timer; /* second timer */ 75285612Sdelphijstatic u_long stats_timer; /* stats timer */ 76285612Sdelphijstatic u_long leapf_timer; /* Report leapfile problems once/day */ 77285612Sdelphijstatic u_long huffpuff_timer; /* huff-n'-puff timer */ 78285612Sdelphijstatic u_long worker_idle_timer;/* next check for idle intres */ 79285612Sdelphiju_long leapsec; /* seconds to next leap (proximity class) */ 80285612Sdelphijint leapdif; /* TAI difference step at next leap second*/ 81285612Sdelphiju_long orphwait; /* orphan wait time */ 82285612Sdelphij#ifdef AUTOKEY 83285612Sdelphijstatic u_long revoke_timer; /* keys revoke timer */ 84285612Sdelphijstatic u_long keys_timer; /* session key timer */ 85285612Sdelphiju_long sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ 86285612Sdelphiju_long sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */ 87285612Sdelphij#endif /* AUTOKEY */ 8854359Sroberto 8954359Sroberto/* 9054359Sroberto * Statistics counter for the interested. 9154359Sroberto */ 9254359Srobertovolatile u_long alarm_overflow; 9354359Sroberto 94285612Sdelphiju_long current_time; /* seconds since startup */ 9554359Sroberto 9654359Sroberto/* 9754359Sroberto * Stats. Number of overflows and number of calls to transmit(). 9854359Sroberto */ 9954359Srobertou_long timer_timereset; 10054359Srobertou_long timer_overflows; 10154359Srobertou_long timer_xmtcalls; 10254359Sroberto 10354359Sroberto#if defined(VMS) 10454359Srobertostatic int vmstimer[2]; /* time for next timer AST */ 10554359Srobertostatic int vmsinc[2]; /* timer increment */ 10654359Sroberto#endif /* VMS */ 10754359Sroberto 108285612Sdelphij#ifdef SYS_WINNT 109285612SdelphijHANDLE WaitableTimerHandle; 11054359Sroberto#else 111285612Sdelphijstatic RETSIGTYPE alarming (int); 11254359Sroberto#endif /* SYS_WINNT */ 11354359Sroberto 114132451Sroberto#if !defined(VMS) 115132451Sroberto# if !defined SYS_WINNT || defined(SYS_CYGWIN32) 116285612Sdelphij# ifdef HAVE_TIMER_CREATE 117285612Sdelphijstatic timer_t timer_id; 118285612Sdelphijtypedef struct itimerspec intervaltimer; 119285612Sdelphij# define itv_frac tv_nsec 120285612Sdelphij# else 121285612Sdelphijtypedef struct itimerval intervaltimer; 122285612Sdelphij# define itv_frac tv_usec 123285612Sdelphij# endif 124285612Sdelphijintervaltimer itimer; 125285612Sdelphij# endif 126285612Sdelphij#endif 12754359Sroberto 128285612Sdelphij#if !defined(SYS_WINNT) && !defined(VMS) 129285612Sdelphijvoid set_timer_or_die(const intervaltimer *); 130285612Sdelphij#endif 131285612Sdelphij 132285612Sdelphij 133285612Sdelphij#if !defined(SYS_WINNT) && !defined(VMS) 134285612Sdelphijvoid 135285612Sdelphijset_timer_or_die( 136285612Sdelphij const intervaltimer * ptimer 137285612Sdelphij ) 138285612Sdelphij{ 139285612Sdelphij const char * setfunc; 140285612Sdelphij int rc; 141285612Sdelphij 142285612Sdelphij# ifdef HAVE_TIMER_CREATE 143285612Sdelphij setfunc = "timer_settime"; 144285612Sdelphij rc = timer_settime(timer_id, 0, &itimer, NULL); 145285612Sdelphij# else 146285612Sdelphij setfunc = "setitimer"; 147285612Sdelphij rc = setitimer(ITIMER_REAL, &itimer, NULL); 148285612Sdelphij# endif 149285612Sdelphij if (-1 == rc) { 150285612Sdelphij msyslog(LOG_ERR, "interval timer %s failed, %m", 151285612Sdelphij setfunc); 152285612Sdelphij exit(1); 153285612Sdelphij } 154285612Sdelphij} 155285612Sdelphij#endif /* !SYS_WINNT && !VMS */ 156285612Sdelphij 157285612Sdelphij 15854359Sroberto/* 159285612Sdelphij * reinit_timer - reinitialize interval timer after a clock step. 160132451Sroberto */ 161285612Sdelphijvoid 162132451Srobertoreinit_timer(void) 163132451Sroberto{ 164132451Sroberto#if !defined(SYS_WINNT) && !defined(VMS) 165285612Sdelphij ZERO(itimer); 166285612Sdelphij# ifdef HAVE_TIMER_CREATE 167285612Sdelphij timer_gettime(timer_id, &itimer); 168285612Sdelphij# else 169132451Sroberto getitimer(ITIMER_REAL, &itimer); 170285612Sdelphij# endif 171285612Sdelphij if (itimer.it_value.tv_sec < 0 || 172285612Sdelphij itimer.it_value.tv_sec > (1 << EVENT_TIMEOUT)) 173285612Sdelphij itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 174285612Sdelphij if (itimer.it_value.itv_frac < 0) 175285612Sdelphij itimer.it_value.itv_frac = 0; 176285612Sdelphij if (0 == itimer.it_value.tv_sec && 177285612Sdelphij 0 == itimer.it_value.itv_frac) 178285612Sdelphij itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 179285612Sdelphij itimer.it_interval.tv_sec = (1 << EVENT_TIMEOUT); 180285612Sdelphij itimer.it_interval.itv_frac = 0; 181285612Sdelphij set_timer_or_die(&itimer); 182132451Sroberto# endif /* VMS */ 183132451Sroberto} 184132451Sroberto 185285612Sdelphij 186132451Sroberto/* 18754359Sroberto * init_timer - initialize the timer data structures 18854359Sroberto */ 18954359Srobertovoid 19054359Srobertoinit_timer(void) 19154359Sroberto{ 19254359Sroberto /* 19354359Sroberto * Initialize... 19454359Sroberto */ 195285612Sdelphij alarm_flag = FALSE; 19654359Sroberto alarm_overflow = 0; 19754359Sroberto adjust_timer = 1; 198285612Sdelphij stats_timer = SECSPERHR; 199285612Sdelphij leapf_timer = SECSPERDAY; 20082498Sroberto huffpuff_timer = 0; 201182007Sroberto interface_timer = 0; 20254359Sroberto current_time = 0; 20354359Sroberto timer_overflows = 0; 20454359Sroberto timer_xmtcalls = 0; 20554359Sroberto timer_timereset = 0; 20654359Sroberto 207285612Sdelphij#ifndef SYS_WINNT 20854359Sroberto /* 20954359Sroberto * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT 21054359Sroberto * seconds from now and they continue on every 2**EVENT_TIMEOUT 21154359Sroberto * seconds. 21254359Sroberto */ 213285612Sdelphij# ifndef VMS 214285612Sdelphij# ifdef HAVE_TIMER_CREATE 215285612Sdelphij if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) { 216285612Sdelphij msyslog(LOG_ERR, "timer_create failed, %m"); 217285612Sdelphij exit(1); 21854359Sroberto } 21954359Sroberto# endif 220285612Sdelphij signal_no_reset(SIGALRM, alarming); 221285612Sdelphij itimer.it_interval.tv_sec = 222285612Sdelphij itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); 223285612Sdelphij itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0; 224285612Sdelphij set_timer_or_die(&itimer); 225285612Sdelphij# else /* VMS follows */ 22654359Sroberto vmsinc[0] = 10000000; /* 1 sec */ 22754359Sroberto vmsinc[1] = 0; 22854359Sroberto lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); 22954359Sroberto 23054359Sroberto sys$gettim(&vmstimer); /* that's "now" as abstime */ 23154359Sroberto 23254359Sroberto lib$addx(&vmsinc, &vmstimer, &vmstimer); 23354359Sroberto sys$setimr(0, &vmstimer, alarming, alarming, 0); 234285612Sdelphij# endif /* VMS */ 235285612Sdelphij#else /* SYS_WINNT follows */ 23654359Sroberto /* 23754359Sroberto * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds 238285612Sdelphij * Under Windows/NT, 23954359Sroberto */ 24054359Sroberto 24154359Sroberto WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); 24254359Sroberto if (WaitableTimerHandle == NULL) { 24354359Sroberto msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); 24454359Sroberto exit(1); 24554359Sroberto } 24654359Sroberto else { 247285612Sdelphij DWORD Period; 248285612Sdelphij LARGE_INTEGER DueTime; 249285612Sdelphij BOOL rc; 250285612Sdelphij 251285612Sdelphij Period = (1 << EVENT_TIMEOUT) * 1000; 25254359Sroberto DueTime.QuadPart = Period * 10000i64; 253285612Sdelphij rc = SetWaitableTimer(WaitableTimerHandle, &DueTime, 254285612Sdelphij Period, NULL, NULL, FALSE); 255285612Sdelphij if (!rc) { 25654359Sroberto msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); 25754359Sroberto exit(1); 25854359Sroberto } 25954359Sroberto } 26054359Sroberto 261285612Sdelphij#endif /* SYS_WINNT */ 26254359Sroberto} 26354359Sroberto 264285612Sdelphij 265285612Sdelphij/* 266285612Sdelphij * intres_timeout_req(s) is invoked in the parent to schedule an idle 267285612Sdelphij * timeout to fire in s seconds, if not reset earlier by a call to 268285612Sdelphij * intres_timeout_req(0), which clears any pending timeout. When the 269285612Sdelphij * timeout expires, worker_idle_timer_fired() is invoked (again, in the 270285612Sdelphij * parent). 271285612Sdelphij * 272285612Sdelphij * sntp and ntpd each provide implementations adapted to their timers. 273285612Sdelphij */ 274285612Sdelphijvoid 275285612Sdelphijintres_timeout_req( 276285612Sdelphij u_int seconds /* 0 cancels */ 277285612Sdelphij ) 27854359Sroberto{ 279298770Sdelphij#if defined(HAVE_DROPROOT) && defined(NEED_EARLY_FORK) 280298770Sdelphij if (droproot) { 281298770Sdelphij worker_idle_timer = 0; 282298770Sdelphij return; 283298770Sdelphij } 284298770Sdelphij#endif 285285612Sdelphij if (0 == seconds) { 286285612Sdelphij worker_idle_timer = 0; 287285612Sdelphij return; 288285612Sdelphij } 289285612Sdelphij worker_idle_timer = current_time + seconds; 29054359Sroberto} 29154359Sroberto 292285612Sdelphij 29354359Sroberto/* 294285612Sdelphij * timer - event timer 29554359Sroberto */ 29654359Srobertovoid 29754359Srobertotimer(void) 29854359Sroberto{ 299285612Sdelphij struct peer * p; 300285612Sdelphij struct peer * next_peer; 301285612Sdelphij l_fp now; 302285612Sdelphij time_t tnow; 30354359Sroberto 30454359Sroberto /* 305285612Sdelphij * The basic timerevent is one second. This is used to adjust the 306285612Sdelphij * system clock in time and frequency, implement the kiss-o'-death 307285612Sdelphij * function and the association polling function. 30854359Sroberto */ 309285612Sdelphij current_time++; 31054359Sroberto if (adjust_timer <= current_time) { 31154359Sroberto adjust_timer += 1; 31254359Sroberto adj_host_clock(); 313182007Sroberto#ifdef REFCLOCK 314285612Sdelphij for (p = peer_list; p != NULL; p = next_peer) { 315285612Sdelphij next_peer = p->p_link; 316285612Sdelphij if (FLAG_REFCLOCK & p->flags) 317285612Sdelphij refclock_timer(p); 318182007Sroberto } 319182007Sroberto#endif /* REFCLOCK */ 32054359Sroberto } 32154359Sroberto 32254359Sroberto /* 323285612Sdelphij * Now dispatch any peers whose event timer has expired. Be 324285612Sdelphij * careful here, since the peer structure might go away as the 325285612Sdelphij * result of the call. 32654359Sroberto */ 327285612Sdelphij for (p = peer_list; p != NULL; p = next_peer) { 328285612Sdelphij next_peer = p->p_link; 329285612Sdelphij 330285612Sdelphij /* 331285612Sdelphij * Restrain the non-burst packet rate not more 332285612Sdelphij * than one packet every 16 seconds. This is 333285612Sdelphij * usually tripped using iburst and minpoll of 334285612Sdelphij * 128 s or less. 335285612Sdelphij */ 336285612Sdelphij if (p->throttle > 0) 337285612Sdelphij p->throttle--; 338285612Sdelphij if (p->nextdate <= current_time) { 33954359Sroberto#ifdef REFCLOCK 340285612Sdelphij if (FLAG_REFCLOCK & p->flags) 341285612Sdelphij refclock_transmit(p); 342285612Sdelphij else 343285612Sdelphij#endif /* REFCLOCK */ 344285612Sdelphij transmit(p); 34554359Sroberto } 34654359Sroberto } 34754359Sroberto 34854359Sroberto /* 349285612Sdelphij * Orphan mode is active when enabled and when no servers less 350285612Sdelphij * than the orphan stratum are available. A server with no other 351285612Sdelphij * synchronization source is an orphan. It shows offset zero and 352285612Sdelphij * reference ID the loopback address. 35354359Sroberto */ 354285612Sdelphij if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL && 355285612Sdelphij current_time > orphwait) { 356285612Sdelphij if (sys_leap == LEAP_NOTINSYNC) { 357285612Sdelphij set_sys_leap(LEAP_NOWARNING); 358285612Sdelphij#ifdef AUTOKEY 359285612Sdelphij if (crypto_flags) 360285612Sdelphij crypto_update(); 361285612Sdelphij#endif /* AUTOKEY */ 362285612Sdelphij } 363285612Sdelphij sys_stratum = (u_char)sys_orphan; 364285612Sdelphij if (sys_stratum > 1) 365285612Sdelphij sys_refid = htonl(LOOPBACKADR); 366285612Sdelphij else 367285612Sdelphij memcpy(&sys_refid, "LOOP", 4); 368285612Sdelphij sys_offset = 0; 369285612Sdelphij sys_rootdelay = 0; 370285612Sdelphij sys_rootdisp = 0; 37154359Sroberto } 37254359Sroberto 373285612Sdelphij get_systime(&now); 374285612Sdelphij time(&tnow); 375285612Sdelphij 37654359Sroberto /* 377285612Sdelphij * Leapseconds. Get time and defer to worker if either something 378285612Sdelphij * is imminent or every 8th second. 37954359Sroberto */ 380285612Sdelphij if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7)) 381285612Sdelphij check_leapsec(now.l_ui, &tnow, 382285612Sdelphij (sys_leap == LEAP_NOTINSYNC)); 383285612Sdelphij if (sys_leap != LEAP_NOTINSYNC) { 384285612Sdelphij if (leapsec >= LSPROX_ANNOUNCE && leapdif) { 385285612Sdelphij if (leapdif > 0) 386285612Sdelphij set_sys_leap(LEAP_ADDSECOND); 387285612Sdelphij else 388285612Sdelphij set_sys_leap(LEAP_DELSECOND); 389285612Sdelphij } else { 390285612Sdelphij set_sys_leap(LEAP_NOWARNING); 391285612Sdelphij } 392285612Sdelphij } 393285612Sdelphij 394285612Sdelphij /* 395285612Sdelphij * Update huff-n'-puff filter. 396285612Sdelphij */ 39782498Sroberto if (huffpuff_timer <= current_time) { 39882498Sroberto huffpuff_timer += HUFFPUFF; 39982498Sroberto huffpuff(); 40082498Sroberto } 40182498Sroberto 402285612Sdelphij#ifdef AUTOKEY 40382498Sroberto /* 404285612Sdelphij * Garbage collect expired keys. 40582498Sroberto */ 406285612Sdelphij if (keys_timer <= current_time) { 407285612Sdelphij keys_timer += 1 << sys_automax; 408285612Sdelphij auth_agekeys(); 40954359Sroberto } 41054359Sroberto 41154359Sroberto /* 412285612Sdelphij * Generate new private value. This causes all associations 413285612Sdelphij * to regenerate cookies. 41454359Sroberto */ 415285612Sdelphij if (revoke_timer && revoke_timer <= current_time) { 416285612Sdelphij revoke_timer += 1 << sys_revoke; 417285612Sdelphij RAND_bytes((u_char *)&sys_private, 4); 418285612Sdelphij } 419285612Sdelphij#endif /* AUTOKEY */ 420285612Sdelphij 421285612Sdelphij /* 422285612Sdelphij * Interface update timer 423285612Sdelphij */ 424182007Sroberto if (interface_interval && interface_timer <= current_time) { 425285612Sdelphij timer_interfacetimeout(current_time + 426285612Sdelphij interface_interval); 427285612Sdelphij DPRINTF(2, ("timer: interface update\n")); 428200576Sroberto interface_update(NULL, NULL); 42954359Sroberto } 430285612Sdelphij 431285612Sdelphij if (worker_idle_timer && worker_idle_timer <= current_time) 432285612Sdelphij worker_idle_timer_fired(); 433285612Sdelphij 434182007Sroberto /* 435285612Sdelphij * Finally, write hourly stats and do the hourly 436285612Sdelphij * and daily leapfile checks. 437182007Sroberto */ 438182007Sroberto if (stats_timer <= current_time) { 439285612Sdelphij stats_timer += SECSPERHR; 440285612Sdelphij write_stats(); 441285612Sdelphij if (leapf_timer <= current_time) { 442285612Sdelphij leapf_timer += SECSPERDAY; 443285612Sdelphij check_leap_file(TRUE, now.l_ui, &tnow); 444285612Sdelphij } else { 445285612Sdelphij check_leap_file(FALSE, now.l_ui, &tnow); 446285612Sdelphij } 447182007Sroberto } 44854359Sroberto} 44954359Sroberto 45054359Sroberto 45154359Sroberto#ifndef SYS_WINNT 45254359Sroberto/* 45354359Sroberto * alarming - tell the world we've been alarmed 45454359Sroberto */ 45554359Srobertostatic RETSIGTYPE 45654359Srobertoalarming( 45754359Sroberto int sig 45854359Sroberto ) 45954359Sroberto{ 460285612Sdelphij# ifdef DEBUG 461285612Sdelphij const char *msg = "alarming: initializing TRUE\n"; 462285612Sdelphij# endif 463285612Sdelphij 46454359Sroberto if (!initializing) { 465285612Sdelphij if (alarm_flag) { 466285612Sdelphij alarm_overflow++; 467285612Sdelphij# ifdef DEBUG 468285612Sdelphij msg = "alarming: overflow\n"; 469285612Sdelphij# endif 470285612Sdelphij } else { 471285612Sdelphij# ifndef VMS 472285612Sdelphij alarm_flag++; 473285612Sdelphij# else 474285612Sdelphij /* VMS AST routine, increment is no good */ 475285612Sdelphij alarm_flag = 1; 476285612Sdelphij# endif 477285612Sdelphij# ifdef DEBUG 478285612Sdelphij msg = "alarming: normal\n"; 479285612Sdelphij# endif 480285612Sdelphij } 48154359Sroberto } 482285612Sdelphij# ifdef VMS 483285612Sdelphij lib$addx(&vmsinc, &vmstimer, &vmstimer); 484285612Sdelphij sys$setimr(0, &vmstimer, alarming, alarming, 0); 485285612Sdelphij# endif 486285612Sdelphij# ifdef DEBUG 487285612Sdelphij if (debug >= 4) 488285612Sdelphij (void)(-1 == write(1, msg, strlen(msg))); 489285612Sdelphij# endif 49054359Sroberto} 49154359Sroberto#endif /* SYS_WINNT */ 49254359Sroberto 493285612Sdelphij 494182007Srobertovoid 495182007Srobertotimer_interfacetimeout(u_long timeout) 496182007Sroberto{ 497182007Sroberto interface_timer = timeout; 498182007Sroberto} 49954359Sroberto 500182007Sroberto 50154359Sroberto/* 50254359Sroberto * timer_clr_stats - clear timer module stat counters 50354359Sroberto */ 50454359Srobertovoid 50554359Srobertotimer_clr_stats(void) 50654359Sroberto{ 50754359Sroberto timer_overflows = 0; 50854359Sroberto timer_xmtcalls = 0; 50954359Sroberto timer_timereset = current_time; 51054359Sroberto} 51154359Sroberto 512285612Sdelphij 513285612Sdelphijstatic void 514285612Sdelphijcheck_leap_sec_in_progress( const leap_result_t *lsdata ) { 515285612Sdelphij int prv_leap_sec_in_progress = leap_sec_in_progress; 516285612Sdelphij leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3); 517285612Sdelphij 518285612Sdelphij /* if changed we may have to update the leap status sent to clients */ 519285612Sdelphij if (leap_sec_in_progress != prv_leap_sec_in_progress) 520285612Sdelphij set_sys_leap(sys_leap); 521285612Sdelphij} 522285612Sdelphij 523285612Sdelphij 524285612Sdelphijstatic void 525285612Sdelphijcheck_leapsec( 526285612Sdelphij u_int32 now , 527285612Sdelphij const time_t * tpiv , 528285612Sdelphij int/*BOOL*/ reset) 529285612Sdelphij{ 530285612Sdelphij static const char leapmsg_p_step[] = 531285612Sdelphij "Positive leap second, stepped backward."; 532285612Sdelphij static const char leapmsg_p_slew[] = 533285612Sdelphij "Positive leap second, no step correction. " 534285612Sdelphij "System clock will be inaccurate for a long time."; 535285612Sdelphij 536285612Sdelphij static const char leapmsg_n_step[] = 537285612Sdelphij "Negative leap second, stepped forward."; 538285612Sdelphij static const char leapmsg_n_slew[] = 539285612Sdelphij "Negative leap second, no step correction. " 540285612Sdelphij "System clock will be inaccurate for a long time."; 541285612Sdelphij 542285612Sdelphij leap_result_t lsdata; 543285612Sdelphij u_int32 lsprox; 544285612Sdelphij#ifdef AUTOKEY 545285612Sdelphij int/*BOOL*/ update_autokey = FALSE; 546285612Sdelphij#endif 547285612Sdelphij 548285612Sdelphij#ifndef SYS_WINNT /* WinNT port has its own leap second handling */ 549285612Sdelphij# ifdef KERNEL_PLL 550285612Sdelphij leapsec_electric(pll_control && kern_enable); 551285612Sdelphij# else 552285612Sdelphij leapsec_electric(0); 553285612Sdelphij# endif 554285612Sdelphij#endif 555285612Sdelphij#ifdef LEAP_SMEAR 556285612Sdelphij leap_smear.enabled = leap_smear_intv != 0; 557285612Sdelphij#endif 558294569Sdelphij if (reset) { 559285612Sdelphij lsprox = LSPROX_NOWARN; 560285612Sdelphij leapsec_reset_frame(); 561285612Sdelphij memset(&lsdata, 0, sizeof(lsdata)); 562285612Sdelphij } else { 563294569Sdelphij int fired; 564285612Sdelphij 565294569Sdelphij fired = leapsec_query(&lsdata, now, tpiv); 566294569Sdelphij 567294569Sdelphij DPRINTF(3, ("*** leapsec_query: fired %i, now %u (0x%08X), tai_diff %i, ddist %u\n", 568285612Sdelphij fired, now, now, lsdata.tai_diff, lsdata.ddist)); 569285612Sdelphij 570285612Sdelphij#ifdef LEAP_SMEAR 571285612Sdelphij leap_smear.in_progress = 0; 572285612Sdelphij leap_smear.doffset = 0.0; 573285612Sdelphij 574285612Sdelphij if (leap_smear.enabled) { 575285612Sdelphij if (lsdata.tai_diff) { 576285612Sdelphij if (leap_smear.interval == 0) { 577285612Sdelphij leap_smear.interval = leap_smear_intv; 578285612Sdelphij leap_smear.intv_end = lsdata.ttime.Q_s; 579285612Sdelphij leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval; 580285612Sdelphij DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n", 581285612Sdelphij leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end)); 582285612Sdelphij } 583294569Sdelphij } else { 584285612Sdelphij if (leap_smear.interval) 585285612Sdelphij DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n")); 586285612Sdelphij leap_smear.interval = 0; 587285612Sdelphij } 588285612Sdelphij 589285612Sdelphij if (leap_smear.interval) { 590285612Sdelphij double dtemp = now; 591285612Sdelphij if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) { 592285612Sdelphij double leap_smear_time = dtemp - leap_smear.intv_start; 593285612Sdelphij /* 594285612Sdelphij * For now we just do a linear interpolation over the smear interval 595285612Sdelphij */ 596285612Sdelphij#if 0 597285612Sdelphij // linear interpolation 598285612Sdelphij leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval); 599285612Sdelphij#else 600285612Sdelphij // Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0 601285612Sdelphij leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0; 602285612Sdelphij#endif 603285612Sdelphij /* 604285612Sdelphij * TODO see if we're inside an inserted leap second, so we need to compute 605285612Sdelphij * leap_smear.doffset = 1.0 - leap_smear.doffset 606285612Sdelphij */ 607285612Sdelphij leap_smear.in_progress = 1; 608285612Sdelphij#if 0 && defined( DEBUG ) 609285612Sdelphij msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", 610285612Sdelphij leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, 611285612Sdelphij now, leap_smear_time, leap_smear.doffset); 612285612Sdelphij#else 613285612Sdelphij DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", 614285612Sdelphij leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, 615285612Sdelphij now, leap_smear_time, leap_smear.doffset)); 616285612Sdelphij#endif 617285612Sdelphij 618285612Sdelphij } 619285612Sdelphij } 620285612Sdelphij } 621285612Sdelphij else 622285612Sdelphij leap_smear.interval = 0; 623285612Sdelphij 624285612Sdelphij /* 625285612Sdelphij * Update the current leap smear offset, eventually 0.0 if outside smear interval. 626285612Sdelphij */ 627285612Sdelphij DTOLFP(leap_smear.doffset, &leap_smear.offset); 628285612Sdelphij 629285612Sdelphij#endif /* LEAP_SMEAR */ 630285612Sdelphij 631285612Sdelphij if (fired) { 632285612Sdelphij /* Full hit. Eventually step the clock, but always 633285612Sdelphij * announce the leap event has happened. 634285612Sdelphij */ 635285612Sdelphij const char *leapmsg = NULL; 636293650Sglebius double lswarp = lsdata.warped; 637293650Sglebius if (lswarp < 0.0) { 638285612Sdelphij if (clock_max_back > 0.0 && 639293650Sglebius clock_max_back < -lswarp) { 640293650Sglebius step_systime(lswarp); 641285612Sdelphij leapmsg = leapmsg_p_step; 642285612Sdelphij } else { 643285612Sdelphij leapmsg = leapmsg_p_slew; 644285612Sdelphij } 645293650Sglebius } else if (lswarp > 0.0) { 646285612Sdelphij if (clock_max_fwd > 0.0 && 647293650Sglebius clock_max_fwd < lswarp) { 648293650Sglebius step_systime(lswarp); 649285612Sdelphij leapmsg = leapmsg_n_step; 650285612Sdelphij } else { 651285612Sdelphij leapmsg = leapmsg_n_slew; 652285612Sdelphij } 653285612Sdelphij } 654285612Sdelphij if (leapmsg) 655285612Sdelphij msyslog(LOG_NOTICE, "%s", leapmsg); 656285612Sdelphij report_event(EVNT_LEAP, NULL, NULL); 657285612Sdelphij#ifdef AUTOKEY 658285612Sdelphij update_autokey = TRUE; 659285612Sdelphij#endif 660285612Sdelphij lsprox = LSPROX_NOWARN; 661285612Sdelphij leapsec = LSPROX_NOWARN; 662285612Sdelphij sys_tai = lsdata.tai_offs; 663285612Sdelphij } else { 664285612Sdelphij#ifdef AUTOKEY 665294569Sdelphij update_autokey = (sys_tai != (u_int)lsdata.tai_offs); 666285612Sdelphij#endif 667294569Sdelphij lsprox = lsdata.proximity; 668294569Sdelphij sys_tai = lsdata.tai_offs; 669285612Sdelphij } 670285612Sdelphij } 671285612Sdelphij 672285612Sdelphij /* We guard against panic alarming during the red alert phase. 673285612Sdelphij * Strange and evil things might happen if we go from stone cold 674285612Sdelphij * to piping hot in one step. If things are already that wobbly, 675285612Sdelphij * we let the normal clock correction take over, even if a jump 676285612Sdelphij * is involved. 677285612Sdelphij * Also make sure the alarming events are edge-triggered, that is, 678285612Sdelphij * ceated only when the threshold is crossed. 679285612Sdelphij */ 680285612Sdelphij if ( (leapsec > 0 || lsprox < LSPROX_ALERT) 681285612Sdelphij && leapsec < lsprox ) { 682285612Sdelphij if ( leapsec < LSPROX_SCHEDULE 683285612Sdelphij && lsprox >= LSPROX_SCHEDULE) { 684285612Sdelphij if (lsdata.dynamic) 685285612Sdelphij report_event(PEVNT_ARMED, sys_peer, NULL); 686285612Sdelphij else 687285612Sdelphij report_event(EVNT_ARMED, NULL, NULL); 688285612Sdelphij } 689285612Sdelphij leapsec = lsprox; 690285612Sdelphij } 691285612Sdelphij if (leapsec > lsprox) { 692285612Sdelphij if ( leapsec >= LSPROX_SCHEDULE 693285612Sdelphij && lsprox < LSPROX_SCHEDULE) { 694285612Sdelphij report_event(EVNT_DISARMED, NULL, NULL); 695285612Sdelphij } 696285612Sdelphij leapsec = lsprox; 697285612Sdelphij } 698285612Sdelphij 699285612Sdelphij if (leapsec >= LSPROX_SCHEDULE) 700285612Sdelphij leapdif = lsdata.tai_diff; 701285612Sdelphij else 702285612Sdelphij leapdif = 0; 703285612Sdelphij 704285612Sdelphij check_leap_sec_in_progress(&lsdata); 705285612Sdelphij 706285612Sdelphij#ifdef AUTOKEY 707285612Sdelphij if (update_autokey) 708285612Sdelphij crypto_update_taichange(); 709285612Sdelphij#endif 710285612Sdelphij} 711