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" 1182498Sroberto 1254359Sroberto#include <stdio.h> 1354359Sroberto#include <signal.h> 14106163Sroberto#ifdef HAVE_SYS_SIGNAL_H 15106163Sroberto# include <sys/signal.h> 16106163Sroberto#endif 1782498Sroberto#ifdef HAVE_UNISTD_H 1882498Sroberto# include <unistd.h> 1982498Sroberto#endif 2054359Sroberto 2154359Sroberto#if defined(HAVE_IO_COMPLETION_PORT) 2254359Sroberto# include "ntp_iocompletionport.h" 2354359Sroberto# include "ntp_timer.h" 2454359Sroberto#endif 2554359Sroberto 2654359Sroberto/* 2754359Sroberto * These routines provide support for the event timer. The timer is 2854359Sroberto * implemented by an interrupt routine which sets a flag once every 2954359Sroberto * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which 3054359Sroberto * is called when the mainline code gets around to seeing the flag. 3154359Sroberto * The timer routine dispatches the clock adjustment code if its time 3254359Sroberto * has come, then searches the timer queue for expiries which are 3354359Sroberto * dispatched to the transmit procedure. Finally, we call the hourly 3454359Sroberto * procedure to do cleanup and print a message. 3554359Sroberto */ 3654359Sroberto 37182007Srobertovolatile int interface_interval = 300; /* update interface every 5 minutes as default */ 38182007Sroberto 3954359Sroberto/* 4054359Sroberto * Alarm flag. The mainline code imports this. 4154359Sroberto */ 4254359Srobertovolatile int alarm_flag; 4354359Sroberto 4454359Sroberto/* 4554359Sroberto * The counters 4654359Sroberto */ 4754359Srobertostatic u_long adjust_timer; /* second timer */ 4854359Srobertostatic u_long keys_timer; /* minute timer */ 49182007Srobertostatic u_long stats_timer; /* stats timer */ 5082498Srobertostatic u_long huffpuff_timer; /* huff-n'-puff timer */ 51182007Srobertostatic u_long interface_timer; /* interface update timer */ 52132451Sroberto#ifdef OPENSSL 5354359Srobertostatic u_long revoke_timer; /* keys revoke timer */ 54132451Srobertou_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ 55132451Sroberto#endif /* OPENSSL */ 5654359Sroberto 5754359Sroberto/* 5854359Sroberto * Statistics counter for the interested. 5954359Sroberto */ 6054359Srobertovolatile u_long alarm_overflow; 6154359Sroberto 6254359Sroberto#define MINUTE 60 6354359Sroberto#define HOUR (60*60) 6454359Sroberto 6554359Srobertou_long current_time; 6654359Sroberto 6754359Sroberto/* 6854359Sroberto * Stats. Number of overflows and number of calls to transmit(). 6954359Sroberto */ 7054359Srobertou_long timer_timereset; 7154359Srobertou_long timer_overflows; 7254359Srobertou_long timer_xmtcalls; 7354359Sroberto 7454359Sroberto#if defined(VMS) 7554359Srobertostatic int vmstimer[2]; /* time for next timer AST */ 7654359Srobertostatic int vmsinc[2]; /* timer increment */ 7754359Sroberto#endif /* VMS */ 7854359Sroberto 7954359Sroberto#if defined SYS_WINNT 8054359Srobertostatic HANDLE WaitableTimerHandle = NULL; 8154359Sroberto#else 8254359Srobertostatic RETSIGTYPE alarming P((int)); 8354359Sroberto#endif /* SYS_WINNT */ 8454359Sroberto 85132451Sroberto#if !defined(VMS) 86132451Sroberto# if !defined SYS_WINNT || defined(SYS_CYGWIN32) 87132451Sroberto# ifndef HAVE_TIMER_SETTIME 88132451Sroberto struct itimerval itimer; 89132451Sroberto# else 90132451Sroberto static timer_t ntpd_timerid; 91132451Sroberto struct itimerspec itimer; 92132451Sroberto# endif /* HAVE_TIMER_SETTIME */ 93132451Sroberto# endif /* SYS_WINNT */ 94132451Sroberto#endif /* VMS */ 9554359Sroberto 9654359Sroberto/* 97132451Sroberto * reinit_timer - reinitialize interval timer. 98132451Sroberto */ 99132451Srobertovoid 100132451Srobertoreinit_timer(void) 101132451Sroberto{ 102132451Sroberto#if !defined(SYS_WINNT) && !defined(VMS) 103132451Sroberto# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) 104132451Sroberto timer_gettime(ntpd_timerid, &itimer); 105132451Sroberto if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) { 106132451Sroberto itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 107132451Sroberto } 108132451Sroberto if (itimer.it_value.tv_nsec < 0 ) { 109132451Sroberto itimer.it_value.tv_nsec = 0; 110132451Sroberto } 111132451Sroberto if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) { 112132451Sroberto itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 113132451Sroberto itimer.it_value.tv_nsec = 0; 114132451Sroberto } 115132451Sroberto itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT); 116132451Sroberto itimer.it_interval.tv_nsec = 0; 117132451Sroberto timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL); 118132451Sroberto# else 119132451Sroberto getitimer(ITIMER_REAL, &itimer); 120132451Sroberto if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) { 121132451Sroberto itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 122132451Sroberto } 123132451Sroberto if (itimer.it_value.tv_usec < 0 ) { 124132451Sroberto itimer.it_value.tv_usec = 0; 125132451Sroberto } 126132451Sroberto if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) { 127132451Sroberto itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 128132451Sroberto itimer.it_value.tv_usec = 0; 129132451Sroberto } 130132451Sroberto itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT); 131132451Sroberto itimer.it_interval.tv_usec = 0; 132132451Sroberto setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); 133132451Sroberto# endif 134132451Sroberto# endif /* VMS */ 135132451Sroberto} 136132451Sroberto 137132451Sroberto/* 13854359Sroberto * init_timer - initialize the timer data structures 13954359Sroberto */ 14054359Srobertovoid 14154359Srobertoinit_timer(void) 14254359Sroberto{ 143132451Sroberto# if defined SYS_WINNT & !defined(SYS_CYGWIN32) 144182007Sroberto HANDLE hToken = INVALID_HANDLE_VALUE; 14554359Sroberto TOKEN_PRIVILEGES tkp; 14654359Sroberto# endif /* SYS_WINNT */ 14754359Sroberto 14854359Sroberto /* 14954359Sroberto * Initialize... 15054359Sroberto */ 15154359Sroberto alarm_flag = 0; 15254359Sroberto alarm_overflow = 0; 15354359Sroberto adjust_timer = 1; 154182007Sroberto stats_timer = 0; 15582498Sroberto huffpuff_timer = 0; 156182007Sroberto interface_timer = 0; 15754359Sroberto current_time = 0; 15854359Sroberto timer_overflows = 0; 15954359Sroberto timer_xmtcalls = 0; 16054359Sroberto timer_timereset = 0; 16154359Sroberto 16254359Sroberto#if !defined(SYS_WINNT) 16354359Sroberto /* 16454359Sroberto * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT 16554359Sroberto * seconds from now and they continue on every 2**EVENT_TIMEOUT 16654359Sroberto * seconds. 16754359Sroberto */ 16854359Sroberto# if !defined(VMS) 16954359Sroberto# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) 17054359Sroberto if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) == 17154359Sroberto# ifdef SYS_VXWORKS 17254359Sroberto ERROR 17354359Sroberto# else 17454359Sroberto -1 17554359Sroberto# endif 17654359Sroberto ) 17754359Sroberto { 17854359Sroberto fprintf (stderr, "timer create FAILED\n"); 17954359Sroberto exit (0); 18054359Sroberto } 18154359Sroberto (void) signal_no_reset(SIGALRM, alarming); 18254359Sroberto itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 18354359Sroberto itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0; 18454359Sroberto timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL); 18554359Sroberto# else 18654359Sroberto (void) signal_no_reset(SIGALRM, alarming); 18754359Sroberto itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 18854359Sroberto itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0; 18954359Sroberto setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); 19054359Sroberto# endif 19154359Sroberto# else /* VMS */ 19254359Sroberto vmsinc[0] = 10000000; /* 1 sec */ 19354359Sroberto vmsinc[1] = 0; 19454359Sroberto lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); 19554359Sroberto 19654359Sroberto sys$gettim(&vmstimer); /* that's "now" as abstime */ 19754359Sroberto 19854359Sroberto lib$addx(&vmsinc, &vmstimer, &vmstimer); 19954359Sroberto sys$setimr(0, &vmstimer, alarming, alarming, 0); 20054359Sroberto# endif /* VMS */ 20154359Sroberto#else /* SYS_WINNT */ 20254359Sroberto _tzset(); 20354359Sroberto 20454359Sroberto /* 20554359Sroberto * Get privileges needed for fiddling with the clock 20654359Sroberto */ 20754359Sroberto 20854359Sroberto /* get the current process token handle */ 20954359Sroberto if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { 21054359Sroberto msyslog(LOG_ERR, "OpenProcessToken failed: %m"); 21154359Sroberto exit(1); 21254359Sroberto } 21354359Sroberto /* get the LUID for system-time privilege. */ 21454359Sroberto LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); 21554359Sroberto tkp.PrivilegeCount = 1; /* one privilege to set */ 21654359Sroberto tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 21754359Sroberto /* get set-time privilege for this process. */ 21854359Sroberto AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); 21954359Sroberto /* cannot test return value of AdjustTokenPrivileges. */ 22054359Sroberto if (GetLastError() != ERROR_SUCCESS) { 22154359Sroberto msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); 22254359Sroberto } 22354359Sroberto 22454359Sroberto /* 22554359Sroberto * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds 22654359Sroberto * Under Windows/NT, 22754359Sroberto */ 22854359Sroberto 22954359Sroberto WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); 23054359Sroberto if (WaitableTimerHandle == NULL) { 23154359Sroberto msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); 23254359Sroberto exit(1); 23354359Sroberto } 23454359Sroberto else { 23554359Sroberto DWORD Period = (1<<EVENT_TIMEOUT) * 1000; 23654359Sroberto LARGE_INTEGER DueTime; 23754359Sroberto DueTime.QuadPart = Period * 10000i64; 23854359Sroberto if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) { 23954359Sroberto msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); 24054359Sroberto exit(1); 24154359Sroberto } 24254359Sroberto } 24354359Sroberto 24454359Sroberto#endif /* SYS_WINNT */ 24554359Sroberto} 24654359Sroberto 24754359Sroberto#if defined(SYS_WINNT) 24854359Srobertoextern HANDLE 24954359Srobertoget_timer_handle(void) 25054359Sroberto{ 25154359Sroberto return WaitableTimerHandle; 25254359Sroberto} 25354359Sroberto#endif 25454359Sroberto 25554359Sroberto/* 25654359Sroberto * timer - dispatch anyone who needs to be 25754359Sroberto */ 25854359Srobertovoid 25954359Srobertotimer(void) 26054359Sroberto{ 26154359Sroberto register struct peer *peer, *next_peer; 262132451Sroberto#ifdef OPENSSL 263132451Sroberto char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ 264132451Sroberto#endif /* OPENSSL */ 26582498Sroberto u_int n; 26654359Sroberto 26754359Sroberto current_time += (1<<EVENT_TIMEOUT); 26854359Sroberto 26954359Sroberto /* 27054359Sroberto * Adjustment timeout first. 27154359Sroberto */ 27254359Sroberto if (adjust_timer <= current_time) { 27354359Sroberto adjust_timer += 1; 27454359Sroberto adj_host_clock(); 275132451Sroberto kod_proto(); 276182007Sroberto#ifdef REFCLOCK 277182007Sroberto for (n = 0; n < NTP_HASH_SIZE; n++) { 278182007Sroberto for (peer = peer_hash[n]; peer != 0; peer = next_peer) { 279182007Sroberto next_peer = peer->next; 280182007Sroberto if (peer->flags & FLAG_REFCLOCK) 281182007Sroberto refclock_timer(peer); 282182007Sroberto } 283182007Sroberto } 284182007Sroberto#endif /* REFCLOCK */ 28554359Sroberto } 28654359Sroberto 28754359Sroberto /* 28854359Sroberto * Now dispatch any peers whose event timer has expired. Be careful 28954359Sroberto * here, since the peer structure might go away as the result of 29054359Sroberto * the call. 29154359Sroberto */ 292182007Sroberto for (n = 0; n < NTP_HASH_SIZE; n++) { 29354359Sroberto for (peer = peer_hash[n]; peer != 0; peer = next_peer) { 29454359Sroberto next_peer = peer->next; 29554359Sroberto if (peer->action && peer->nextaction <= current_time) 29654359Sroberto peer->action(peer); 29754359Sroberto if (peer->nextdate <= current_time) { 29854359Sroberto#ifdef REFCLOCK 29954359Sroberto if (peer->flags & FLAG_REFCLOCK) 30054359Sroberto refclock_transmit(peer); 30154359Sroberto else 30254359Sroberto transmit(peer); 30354359Sroberto#else /* REFCLOCK */ 30454359Sroberto transmit(peer); 30554359Sroberto#endif /* REFCLOCK */ 30654359Sroberto } 30754359Sroberto } 30854359Sroberto } 30954359Sroberto 31054359Sroberto /* 31154359Sroberto * Garbage collect expired keys. 31254359Sroberto */ 31354359Sroberto if (keys_timer <= current_time) { 31454359Sroberto keys_timer += MINUTE; 31554359Sroberto auth_agekeys(); 31654359Sroberto } 31754359Sroberto 31854359Sroberto /* 31982498Sroberto * Huff-n'-puff filter 32054359Sroberto */ 32182498Sroberto if (huffpuff_timer <= current_time) { 32282498Sroberto huffpuff_timer += HUFFPUFF; 32382498Sroberto huffpuff(); 32482498Sroberto } 32582498Sroberto 326132451Sroberto#ifdef OPENSSL 32782498Sroberto /* 32882498Sroberto * Garbage collect old keys and generate new private value 32982498Sroberto */ 33054359Sroberto if (revoke_timer <= current_time) { 331132451Sroberto revoke_timer += RANDPOLL(sys_revoke); 33282498Sroberto expire_all(); 333132451Sroberto sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp)); 334132451Sroberto record_crypto_stats(NULL, statstr); 33582498Sroberto#ifdef DEBUG 33682498Sroberto if (debug) 337132451Sroberto printf("timer: %s\n", statstr); 33882498Sroberto#endif 33954359Sroberto } 340132451Sroberto#endif /* OPENSSL */ 34154359Sroberto 34254359Sroberto /* 343182007Sroberto * interface update timer 34454359Sroberto */ 345182007Sroberto if (interface_interval && interface_timer <= current_time) { 346200576Sroberto 347182007Sroberto timer_interfacetimeout(current_time + interface_interval); 348200576Sroberto DPRINTF(1, ("timer: interface update\n")); 349200576Sroberto interface_update(NULL, NULL); 35054359Sroberto } 351182007Sroberto 352182007Sroberto /* 353182007Sroberto * Finally, periodically write stats. 354182007Sroberto */ 355182007Sroberto if (stats_timer <= current_time) { 356182007Sroberto if (stats_timer != 0) 357182007Sroberto write_stats(); 358182007Sroberto stats_timer += stats_write_period; 359182007Sroberto } 36054359Sroberto} 36154359Sroberto 36254359Sroberto 36354359Sroberto#ifndef SYS_WINNT 36454359Sroberto/* 36554359Sroberto * alarming - tell the world we've been alarmed 36654359Sroberto */ 36754359Srobertostatic RETSIGTYPE 36854359Srobertoalarming( 36954359Sroberto int sig 37054359Sroberto ) 37154359Sroberto{ 37254359Sroberto#if !defined(VMS) 37354359Sroberto if (initializing) 37454359Sroberto return; 37554359Sroberto if (alarm_flag) 37654359Sroberto alarm_overflow++; 37754359Sroberto else 37854359Sroberto alarm_flag++; 37954359Sroberto#else /* VMS AST routine */ 38054359Sroberto if (!initializing) { 38154359Sroberto if (alarm_flag) alarm_overflow++; 38254359Sroberto else alarm_flag = 1; /* increment is no good */ 38354359Sroberto } 38454359Sroberto lib$addx(&vmsinc,&vmstimer,&vmstimer); 38554359Sroberto sys$setimr(0,&vmstimer,alarming,alarming,0); 38654359Sroberto#endif /* VMS */ 38754359Sroberto} 38854359Sroberto#endif /* SYS_WINNT */ 38954359Sroberto 390182007Srobertovoid 391182007Srobertotimer_interfacetimeout(u_long timeout) 392182007Sroberto{ 393182007Sroberto interface_timer = timeout; 394182007Sroberto} 39554359Sroberto 396182007Sroberto 39754359Sroberto/* 39854359Sroberto * timer_clr_stats - clear timer module stat counters 39954359Sroberto */ 40054359Srobertovoid 40154359Srobertotimer_clr_stats(void) 40254359Sroberto{ 40354359Sroberto timer_overflows = 0; 40454359Sroberto timer_xmtcalls = 0; 40554359Sroberto timer_timereset = current_time; 40654359Sroberto} 40754359Sroberto 408