Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / ntpd / ntp_timer.c
blob578850cff4f7985009809d724c9644cac325ec65
1 /* $NetBSD: ntp_timer.c,v 1.4 2007/01/06 19:45:23 kardel Exp $ */
3 /*
4 * ntp_timer.c - event timer support routines
5 */
6 #ifdef HAVE_CONFIG_H
7 # include <config.h>
8 #endif
10 #include "ntp_machine.h"
11 #include "ntpd.h"
12 #include "ntp_stdlib.h"
14 #include <stdio.h>
15 #include <signal.h>
16 #ifdef HAVE_SYS_SIGNAL_H
17 # include <sys/signal.h>
18 #endif
19 #ifdef HAVE_UNISTD_H
20 # include <unistd.h>
21 #endif
23 #if defined(HAVE_IO_COMPLETION_PORT)
24 # include "ntp_iocompletionport.h"
25 # include "ntp_timer.h"
26 #endif
29 * These routines provide support for the event timer. The timer is
30 * implemented by an interrupt routine which sets a flag once every
31 * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
32 * is called when the mainline code gets around to seeing the flag.
33 * The timer routine dispatches the clock adjustment code if its time
34 * has come, then searches the timer queue for expiries which are
35 * dispatched to the transmit procedure. Finally, we call the hourly
36 * procedure to do cleanup and print a message.
39 volatile int interface_interval = 300; /* update interface every 5 minutes as default */
42 * Alarm flag. The mainline code imports this.
44 volatile int alarm_flag;
47 * The counters
49 static u_long adjust_timer; /* second timer */
50 static u_long keys_timer; /* minute timer */
51 static u_long stats_timer; /* stats timer */
52 static u_long huffpuff_timer; /* huff-n'-puff timer */
53 static u_long interface_timer; /* interface update timer */
54 #ifdef OPENSSL
55 static u_long revoke_timer; /* keys revoke timer */
56 u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
57 #endif /* OPENSSL */
60 * Statistics counter for the interested.
62 volatile u_long alarm_overflow;
64 #define MINUTE 60
65 #define HOUR (60*60)
67 u_long current_time;
70 * Stats. Number of overflows and number of calls to transmit().
72 u_long timer_timereset;
73 u_long timer_overflows;
74 u_long timer_xmtcalls;
76 #if defined(VMS)
77 static int vmstimer[2]; /* time for next timer AST */
78 static int vmsinc[2]; /* timer increment */
79 #endif /* VMS */
81 #if defined SYS_WINNT
82 static HANDLE WaitableTimerHandle = NULL;
83 #else
84 static RETSIGTYPE alarming P((int));
85 #endif /* SYS_WINNT */
87 #if !defined(VMS)
88 # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
89 # ifndef HAVE_TIMER_SETTIME
90 struct itimerval itimer;
91 # else
92 static timer_t ntpd_timerid;
93 struct itimerspec itimer;
94 # endif /* HAVE_TIMER_SETTIME */
95 # endif /* SYS_WINNT */
96 #endif /* VMS */
99 * reinit_timer - reinitialize interval timer.
101 void
102 reinit_timer(void)
104 #if !defined(SYS_WINNT) && !defined(VMS)
105 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
106 timer_gettime(ntpd_timerid, &itimer);
107 if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
108 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
110 if (itimer.it_value.tv_nsec < 0 ) {
111 itimer.it_value.tv_nsec = 0;
113 if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
114 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
115 itimer.it_value.tv_nsec = 0;
117 itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
118 itimer.it_interval.tv_nsec = 0;
119 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
120 # else
121 getitimer(ITIMER_REAL, &itimer);
122 if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
123 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
125 if (itimer.it_value.tv_usec < 0 ) {
126 itimer.it_value.tv_usec = 0;
128 if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
129 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
130 itimer.it_value.tv_usec = 0;
132 itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
133 itimer.it_interval.tv_usec = 0;
134 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
135 # endif
136 # endif /* VMS */
140 * init_timer - initialize the timer data structures
142 void
143 init_timer(void)
145 # if defined SYS_WINNT & !defined(SYS_CYGWIN32)
146 HANDLE hToken = INVALID_HANDLE_VALUE;
147 TOKEN_PRIVILEGES tkp;
148 # endif /* SYS_WINNT */
151 * Initialize...
153 alarm_flag = 0;
154 alarm_overflow = 0;
155 adjust_timer = 1;
156 stats_timer = 0;
157 huffpuff_timer = 0;
158 interface_timer = 0;
159 current_time = 0;
160 timer_overflows = 0;
161 timer_xmtcalls = 0;
162 timer_timereset = 0;
164 #if !defined(SYS_WINNT)
166 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
167 * seconds from now and they continue on every 2**EVENT_TIMEOUT
168 * seconds.
170 # if !defined(VMS)
171 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
172 if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
173 # ifdef SYS_VXWORKS
174 ERROR
175 # else
177 # endif
180 fprintf (stderr, "timer create FAILED\n");
181 exit (0);
183 (void) signal_no_reset(SIGALRM, alarming);
184 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
185 itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
186 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
187 # else
188 (void) signal_no_reset(SIGALRM, alarming);
189 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
190 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
191 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
192 # endif
193 # else /* VMS */
194 vmsinc[0] = 10000000; /* 1 sec */
195 vmsinc[1] = 0;
196 lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
198 sys$gettim(&vmstimer); /* that's "now" as abstime */
200 lib$addx(&vmsinc, &vmstimer, &vmstimer);
201 sys$setimr(0, &vmstimer, alarming, alarming, 0);
202 # endif /* VMS */
203 #else /* SYS_WINNT */
204 _tzset();
207 * Get privileges needed for fiddling with the clock
210 /* get the current process token handle */
211 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
212 msyslog(LOG_ERR, "OpenProcessToken failed: %m");
213 exit(1);
215 /* get the LUID for system-time privilege. */
216 LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
217 tkp.PrivilegeCount = 1; /* one privilege to set */
218 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
219 /* get set-time privilege for this process. */
220 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
221 /* cannot test return value of AdjustTokenPrivileges. */
222 if (GetLastError() != ERROR_SUCCESS) {
223 msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
227 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
228 * Under Windows/NT,
231 WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
232 if (WaitableTimerHandle == NULL) {
233 msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
234 exit(1);
236 else {
237 DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
238 LARGE_INTEGER DueTime;
239 DueTime.QuadPart = Period * 10000i64;
240 if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
241 msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
242 exit(1);
246 #endif /* SYS_WINNT */
249 #if defined(SYS_WINNT)
250 extern HANDLE
251 get_timer_handle(void)
253 return WaitableTimerHandle;
255 #endif
258 * timer - dispatch anyone who needs to be
260 void
261 timer(void)
263 register struct peer *peer, *next_peer;
264 #ifdef OPENSSL
265 char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
266 #endif /* OPENSSL */
267 u_int n;
269 current_time += (1<<EVENT_TIMEOUT);
272 * Adjustment timeout first.
274 if (adjust_timer <= current_time) {
275 adjust_timer += 1;
276 adj_host_clock();
277 kod_proto();
278 #ifdef REFCLOCK
279 for (n = 0; n < NTP_HASH_SIZE; n++) {
280 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
281 next_peer = peer->next;
282 if (peer->flags & FLAG_REFCLOCK)
283 refclock_timer(peer);
286 #endif /* REFCLOCK */
290 * Now dispatch any peers whose event timer has expired. Be careful
291 * here, since the peer structure might go away as the result of
292 * the call.
294 for (n = 0; n < NTP_HASH_SIZE; n++) {
295 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
296 next_peer = peer->next;
297 if (peer->action && peer->nextaction <= current_time)
298 peer->action(peer);
299 if (peer->nextdate <= current_time) {
300 #ifdef REFCLOCK
301 if (peer->flags & FLAG_REFCLOCK)
302 refclock_transmit(peer);
303 else
304 transmit(peer);
305 #else /* REFCLOCK */
306 transmit(peer);
307 #endif /* REFCLOCK */
313 * Garbage collect expired keys.
315 if (keys_timer <= current_time) {
316 keys_timer += MINUTE;
317 auth_agekeys();
321 * Huff-n'-puff filter
323 if (huffpuff_timer <= current_time) {
324 huffpuff_timer += HUFFPUFF;
325 huffpuff();
328 #ifdef OPENSSL
330 * Garbage collect old keys and generate new private value
332 if (revoke_timer <= current_time) {
333 revoke_timer += RANDPOLL(sys_revoke);
334 expire_all();
335 sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
336 record_crypto_stats(NULL, statstr);
337 #ifdef DEBUG
338 if (debug)
339 printf("timer: %s\n", statstr);
340 #endif
342 #endif /* OPENSSL */
345 * interface update timer
347 if (interface_interval && interface_timer <= current_time) {
349 timer_interfacetimeout(current_time + interface_interval);
350 DPRINTF(1, ("timer: interface update\n"));
351 interface_update(NULL, NULL);
355 * Finally, periodically write stats.
357 if (stats_timer <= current_time) {
358 if (stats_timer != 0)
359 write_stats();
360 stats_timer += stats_write_period;
365 #ifndef SYS_WINNT
367 * alarming - tell the world we've been alarmed
369 static RETSIGTYPE
370 alarming(
371 int sig
374 #if !defined(VMS)
375 if (initializing)
376 return;
377 if (alarm_flag)
378 alarm_overflow++;
379 else
380 alarm_flag++;
381 #else /* VMS AST routine */
382 if (!initializing) {
383 if (alarm_flag) alarm_overflow++;
384 else alarm_flag = 1; /* increment is no good */
386 lib$addx(&vmsinc,&vmstimer,&vmstimer);
387 sys$setimr(0,&vmstimer,alarming,alarming,0);
388 #endif /* VMS */
390 #endif /* SYS_WINNT */
392 void
393 timer_interfacetimeout(u_long timeout)
395 interface_timer = timeout;
400 * timer_clr_stats - clear timer module stat counters
402 void
403 timer_clr_stats(void)
405 timer_overflows = 0;
406 timer_xmtcalls = 0;
407 timer_timereset = current_time;