2 * ntp_timer.c - event timer support routines
8 #include "ntp_machine.h"
10 #include "ntp_stdlib.h"
14 #ifdef HAVE_SYS_SIGNAL_H
15 # include <sys/signal.h>
21 #if defined(HAVE_IO_COMPLETION_PORT)
22 # include "ntp_iocompletionport.h"
23 # include "ntp_timer.h"
27 * These routines provide support for the event timer. The timer is
28 * implemented by an interrupt routine which sets a flag once every
29 * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
30 * is called when the mainline code gets around to seeing the flag.
31 * The timer routine dispatches the clock adjustment code if its time
32 * has come, then searches the timer queue for expiries which are
33 * dispatched to the transmit procedure. Finally, we call the hourly
34 * procedure to do cleanup and print a message.
37 volatile int interface_interval = 300; /* update interface every 5 minutes as default */
40 * Alarm flag. The mainline code imports this.
42 volatile int alarm_flag;
47 static u_long adjust_timer; /* second timer */
48 static u_long keys_timer; /* minute timer */
49 static u_long stats_timer; /* stats timer */
50 static u_long huffpuff_timer; /* huff-n'-puff timer */
51 static u_long interface_timer; /* interface update timer */
53 static u_long revoke_timer; /* keys revoke timer */
54 u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
58 * Statistics counter for the interested.
60 volatile u_long alarm_overflow;
68 * Stats. Number of overflows and number of calls to transmit().
70 u_long timer_timereset;
71 u_long timer_overflows;
72 u_long timer_xmtcalls;
75 static int vmstimer[2]; /* time for next timer AST */
76 static int vmsinc[2]; /* timer increment */
80 static HANDLE WaitableTimerHandle = NULL;
82 static RETSIGTYPE alarming P((int));
83 #endif /* SYS_WINNT */
86 # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
87 # ifndef HAVE_TIMER_SETTIME
88 struct itimerval itimer;
90 static timer_t ntpd_timerid;
91 struct itimerspec itimer;
92 # endif /* HAVE_TIMER_SETTIME */
93 # endif /* SYS_WINNT */
97 * reinit_timer - reinitialize interval timer.
102 #if !defined(SYS_WINNT) && !defined(VMS)
103 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
104 timer_gettime(ntpd_timerid, &itimer);
105 if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
106 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
108 if (itimer.it_value.tv_nsec < 0 ) {
109 itimer.it_value.tv_nsec = 0;
111 if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
112 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
113 itimer.it_value.tv_nsec = 0;
115 itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
116 itimer.it_interval.tv_nsec = 0;
117 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
119 getitimer(ITIMER_REAL, &itimer);
120 if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
121 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
123 if (itimer.it_value.tv_usec < 0 ) {
124 itimer.it_value.tv_usec = 0;
126 if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
127 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
128 itimer.it_value.tv_usec = 0;
130 itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
131 itimer.it_interval.tv_usec = 0;
132 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
138 * init_timer - initialize the timer data structures
143 # if defined SYS_WINNT & !defined(SYS_CYGWIN32)
144 HANDLE hToken = INVALID_HANDLE_VALUE;
145 TOKEN_PRIVILEGES tkp;
146 # endif /* SYS_WINNT */
162 #if !defined(SYS_WINNT)
164 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
165 * seconds from now and they continue on every 2**EVENT_TIMEOUT
169 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
170 if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
178 fprintf (stderr, "timer create FAILED\n");
181 (void) signal_no_reset(SIGALRM, alarming);
182 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
183 itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
184 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
186 (void) signal_no_reset(SIGALRM, alarming);
187 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
188 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
189 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
192 vmsinc[0] = 10000000; /* 1 sec */
194 lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
196 sys$gettim(&vmstimer); /* that's "now" as abstime */
198 lib$addx(&vmsinc, &vmstimer, &vmstimer);
199 sys$setimr(0, &vmstimer, alarming, alarming, 0);
201 #else /* SYS_WINNT */
205 * Get privileges needed for fiddling with the clock
208 /* get the current process token handle */
209 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
210 msyslog(LOG_ERR, "OpenProcessToken failed: %m");
213 /* get the LUID for system-time privilege. */
214 LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
215 tkp.PrivilegeCount = 1; /* one privilege to set */
216 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
217 /* get set-time privilege for this process. */
218 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
219 /* cannot test return value of AdjustTokenPrivileges. */
220 if (GetLastError() != ERROR_SUCCESS) {
221 msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
225 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
229 WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
230 if (WaitableTimerHandle == NULL) {
231 msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
235 DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
236 LARGE_INTEGER DueTime;
237 DueTime.QuadPart = Period * 10000i64;
238 if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
239 msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
244 #endif /* SYS_WINNT */
247 #if defined(SYS_WINNT)
249 get_timer_handle(void)
251 return WaitableTimerHandle;
256 * timer - dispatch anyone who needs to be
261 register struct peer *peer, *next_peer;
263 char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
267 current_time += (1<<EVENT_TIMEOUT);
270 * Adjustment timeout first.
272 if (adjust_timer <= current_time) {
277 for (n = 0; n < NTP_HASH_SIZE; n++) {
278 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
279 next_peer = peer->next;
280 if (peer->flags & FLAG_REFCLOCK)
281 refclock_timer(peer);
284 #endif /* REFCLOCK */
288 * Now dispatch any peers whose event timer has expired. Be careful
289 * here, since the peer structure might go away as the result of
292 for (n = 0; n < NTP_HASH_SIZE; n++) {
293 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
294 next_peer = peer->next;
295 if (peer->action && peer->nextaction <= current_time)
297 if (peer->nextdate <= current_time) {
299 if (peer->flags & FLAG_REFCLOCK)
300 refclock_transmit(peer);
305 #endif /* REFCLOCK */
311 * Garbage collect expired keys.
313 if (keys_timer <= current_time) {
314 keys_timer += MINUTE;
319 * Huff-n'-puff filter
321 if (huffpuff_timer <= current_time) {
322 huffpuff_timer += HUFFPUFF;
328 * Garbage collect old keys and generate new private value
330 if (revoke_timer <= current_time) {
331 revoke_timer += RANDPOLL(sys_revoke);
333 sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
334 record_crypto_stats(NULL, statstr);
337 printf("timer: %s\n", statstr);
343 * interface update timer
345 if (interface_interval && interface_timer <= current_time) {
347 timer_interfacetimeout(current_time + interface_interval);
348 DPRINTF(1, ("timer: interface update\n"));
349 interface_update(NULL, NULL);
353 * Finally, periodically write stats.
355 if (stats_timer <= current_time) {
356 if (stats_timer != 0)
358 stats_timer += stats_write_period;
365 * alarming - tell the world we've been alarmed
379 #else /* VMS AST routine */
381 if (alarm_flag) alarm_overflow++;
382 else alarm_flag = 1; /* increment is no good */
384 lib$addx(&vmsinc,&vmstimer,&vmstimer);
385 sys$setimr(0,&vmstimer,alarming,alarming,0);
388 #endif /* SYS_WINNT */
391 timer_interfacetimeout(u_long timeout)
393 interface_timer = timeout;
398 * timer_clr_stats - clear timer module stat counters
401 timer_clr_stats(void)
405 timer_timereset = current_time;