Deleted Added
sdiff udiff text old ( 106163 ) new ( 132451 )
full compact
1/*
2 * ntp_timer.c - event timer support routines
3 */
4#ifdef HAVE_CONFIG_H
5# include <config.h>
6#endif
7
8#include "ntp_machine.h"
9#include "ntpd.h"
10#include "ntp_stdlib.h"
11
12#include <stdio.h>
13#include <signal.h>
14#ifdef HAVE_SYS_SIGNAL_H
15# include <sys/signal.h>
16#endif
17#ifdef HAVE_UNISTD_H
18# include <unistd.h>
19#endif
20
21#if defined(HAVE_IO_COMPLETION_PORT)
22# include "ntp_iocompletionport.h"
23# include "ntp_timer.h"
24#endif
25
26/*
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.
35 */
36
37/*
38 * Alarm flag. The mainline code imports this.
39 */
40volatile int alarm_flag;
41
42/*
43 * The counters
44 */
45static u_long adjust_timer; /* second timer */
46static u_long keys_timer; /* minute timer */
47static u_long hourly_timer; /* hour timer */
48static u_long huffpuff_timer; /* huff-n'-puff timer */
49#ifdef OPENSSL
50static u_long revoke_timer; /* keys revoke timer */
51u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
52#endif /* OPENSSL */
53
54/*
55 * Statistics counter for the interested.
56 */
57volatile u_long alarm_overflow;
58
59#define MINUTE 60
60#define HOUR (60*60)
61
62u_long current_time;
63
64/*
65 * Stats. Number of overflows and number of calls to transmit().
66 */
67u_long timer_timereset;
68u_long timer_overflows;
69u_long timer_xmtcalls;
70
71#if defined(VMS)
72static int vmstimer[2]; /* time for next timer AST */
73static int vmsinc[2]; /* timer increment */
74#endif /* VMS */
75
76#if defined SYS_WINNT
77static HANDLE WaitableTimerHandle = NULL;
78#else
79static RETSIGTYPE alarming P((int));
80#endif /* SYS_WINNT */
81
82#if !defined(VMS)
83# if !defined SYS_WINNT || defined(SYS_CYGWIN32)
84# ifndef HAVE_TIMER_SETTIME
85 struct itimerval itimer;
86# else
87 static timer_t ntpd_timerid;
88 struct itimerspec itimer;
89# endif /* HAVE_TIMER_SETTIME */
90# endif /* SYS_WINNT */
91#endif /* VMS */
92
93/*
94 * reinit_timer - reinitialize interval timer.
95 */
96void
97reinit_timer(void)
98{
99#if !defined(SYS_WINNT) && !defined(VMS)
100# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
101 timer_gettime(ntpd_timerid, &itimer);
102 if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
103 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
104 }
105 if (itimer.it_value.tv_nsec < 0 ) {
106 itimer.it_value.tv_nsec = 0;
107 }
108 if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
109 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
110 itimer.it_value.tv_nsec = 0;
111 }
112 itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
113 itimer.it_interval.tv_nsec = 0;
114 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
115# else
116 getitimer(ITIMER_REAL, &itimer);
117 if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
118 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
119 }
120 if (itimer.it_value.tv_usec < 0 ) {
121 itimer.it_value.tv_usec = 0;
122 }
123 if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
124 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
125 itimer.it_value.tv_usec = 0;
126 }
127 itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
128 itimer.it_interval.tv_usec = 0;
129 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
130# endif
131# endif /* VMS */
132}
133
134/*
135 * init_timer - initialize the timer data structures
136 */
137void
138init_timer(void)
139{
140# if defined SYS_WINNT & !defined(SYS_CYGWIN32)
141 HANDLE hToken;
142 TOKEN_PRIVILEGES tkp;
143# endif /* SYS_WINNT */
144
145 /*
146 * Initialize...
147 */
148 alarm_flag = 0;
149 alarm_overflow = 0;
150 adjust_timer = 1;
151 hourly_timer = HOUR;
152 huffpuff_timer = 0;
153 current_time = 0;
154 timer_overflows = 0;
155 timer_xmtcalls = 0;
156 timer_timereset = 0;
157
158#if !defined(SYS_WINNT)
159 /*
160 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
161 * seconds from now and they continue on every 2**EVENT_TIMEOUT
162 * seconds.
163 */
164# if !defined(VMS)
165# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
166 if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
167# ifdef SYS_VXWORKS
168 ERROR
169# else
170 -1
171# endif
172 )
173 {
174 fprintf (stderr, "timer create FAILED\n");
175 exit (0);
176 }
177 (void) signal_no_reset(SIGALRM, alarming);
178 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
179 itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
180 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
181# else
182 (void) signal_no_reset(SIGALRM, alarming);
183 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
184 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
185 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
186# endif
187# else /* VMS */
188 vmsinc[0] = 10000000; /* 1 sec */
189 vmsinc[1] = 0;
190 lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
191
192 sys$gettim(&vmstimer); /* that's "now" as abstime */
193
194 lib$addx(&vmsinc, &vmstimer, &vmstimer);
195 sys$setimr(0, &vmstimer, alarming, alarming, 0);
196# endif /* VMS */
197#else /* SYS_WINNT */
198 _tzset();
199
200 /*
201 * Get privileges needed for fiddling with the clock
202 */
203
204 /* get the current process token handle */
205 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
206 msyslog(LOG_ERR, "OpenProcessToken failed: %m");
207 exit(1);
208 }
209 /* get the LUID for system-time privilege. */
210 LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
211 tkp.PrivilegeCount = 1; /* one privilege to set */
212 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
213 /* get set-time privilege for this process. */
214 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
215 /* cannot test return value of AdjustTokenPrivileges. */
216 if (GetLastError() != ERROR_SUCCESS) {
217 msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
218 }
219
220 /*
221 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
222 * Under Windows/NT,
223 */
224
225 WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
226 if (WaitableTimerHandle == NULL) {
227 msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
228 exit(1);
229 }
230 else {
231 DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
232 LARGE_INTEGER DueTime;
233 DueTime.QuadPart = Period * 10000i64;
234 if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
235 msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
236 exit(1);
237 }
238 }
239
240#endif /* SYS_WINNT */
241}
242
243#if defined(SYS_WINNT)
244extern HANDLE
245get_timer_handle(void)
246{
247 return WaitableTimerHandle;
248}
249#endif
250
251/*
252 * timer - dispatch anyone who needs to be
253 */
254void
255timer(void)
256{
257 register struct peer *peer, *next_peer;
258#ifdef OPENSSL
259 char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
260#endif /* OPENSSL */
261 u_int n;
262
263 current_time += (1<<EVENT_TIMEOUT);
264
265 /*
266 * Adjustment timeout first.
267 */
268 if (adjust_timer <= current_time) {
269 adjust_timer += 1;
270 adj_host_clock();
271 kod_proto();
272 }
273
274 /*
275 * Now dispatch any peers whose event timer has expired. Be careful
276 * here, since the peer structure might go away as the result of
277 * the call.
278 */
279 for (n = 0; n < HASH_SIZE; n++) {
280 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
281 next_peer = peer->next;
282 if (peer->action && peer->nextaction <= current_time)
283 peer->action(peer);
284 if (peer->nextdate <= current_time) {
285#ifdef REFCLOCK
286 if (peer->flags & FLAG_REFCLOCK)
287 refclock_transmit(peer);
288 else
289 transmit(peer);
290#else /* REFCLOCK */
291 transmit(peer);
292#endif /* REFCLOCK */
293 }
294 }
295 }
296
297 /*
298 * Garbage collect expired keys.
299 */
300 if (keys_timer <= current_time) {
301 keys_timer += MINUTE;
302 auth_agekeys();
303 }
304
305 /*
306 * Huff-n'-puff filter
307 */
308 if (huffpuff_timer <= current_time) {
309 huffpuff_timer += HUFFPUFF;
310 huffpuff();
311 }
312
313#ifdef OPENSSL
314 /*
315 * Garbage collect old keys and generate new private value
316 */
317 if (revoke_timer <= current_time) {
318 revoke_timer += RANDPOLL(sys_revoke);
319 expire_all();
320 sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
321 record_crypto_stats(NULL, statstr);
322#ifdef DEBUG
323 if (debug)
324 printf("timer: %s\n", statstr);
325#endif
326 }
327#endif /* OPENSSL */
328
329 /*
330 * Finally, call the hourly routine.
331 */
332 if (hourly_timer <= current_time) {
333 hourly_timer += HOUR;
334 hourly_stats();
335 }
336}
337
338
339#ifndef SYS_WINNT
340/*
341 * alarming - tell the world we've been alarmed
342 */
343static RETSIGTYPE
344alarming(
345 int sig
346 )
347{
348#if !defined(VMS)
349 if (initializing)
350 return;
351 if (alarm_flag)
352 alarm_overflow++;
353 else
354 alarm_flag++;
355#else /* VMS AST routine */
356 if (!initializing) {
357 if (alarm_flag) alarm_overflow++;
358 else alarm_flag = 1; /* increment is no good */
359 }
360 lib$addx(&vmsinc,&vmstimer,&vmstimer);
361 sys$setimr(0,&vmstimer,alarming,alarming,0);
362#endif /* VMS */
363}
364#endif /* SYS_WINNT */
365
366
367/*
368 * timer_clr_stats - clear timer module stat counters
369 */
370void
371timer_clr_stats(void)
372{
373 timer_overflows = 0;
374 timer_xmtcalls = 0;
375 timer_timereset = current_time;
376}
377