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#ifdef PUBKEY
27#include "ntp_crypto.h"
28#endif /* PUBKEY */
29
30/*
31 * These routines provide support for the event timer. The timer is
32 * implemented by an interrupt routine which sets a flag once every
33 * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
34 * is called when the mainline code gets around to seeing the flag.
35 * The timer routine dispatches the clock adjustment code if its time
36 * has come, then searches the timer queue for expiries which are
37 * dispatched to the transmit procedure. Finally, we call the hourly
38 * procedure to do cleanup and print a message.
39 */
40
41/*
42 * Alarm flag. The mainline code imports this.
43 */
44volatile int alarm_flag;
45
46/*
47 * The counters
48 */
49static u_long adjust_timer; /* second timer */
50static u_long keys_timer; /* minute timer */
51static u_long hourly_timer; /* hour timer */
52static u_long huffpuff_timer; /* huff-n'-puff timer */
53#ifdef AUTOKEY
54static u_long revoke_timer; /* keys revoke timer */
55u_long sys_revoke = 1 << KEY_REVOKE; /* keys revoke timeout */
56#endif /* AUTOKEY */
57
58/*
59 * Statistics counter for the interested.
60 */
61volatile u_long alarm_overflow;
62
63#define MINUTE 60
64#define HOUR (60*60)
65
66u_long current_time;
67
68/*
69 * Stats. Number of overflows and number of calls to transmit().
70 */
71u_long timer_timereset;
72u_long timer_overflows;
73u_long timer_xmtcalls;
74
75#if defined(VMS)
76static int vmstimer[2]; /* time for next timer AST */
77static int vmsinc[2]; /* timer increment */
78#endif /* VMS */
79
80#if defined SYS_WINNT
81static HANDLE WaitableTimerHandle = NULL;
82#else
83static RETSIGTYPE alarming P((int));
84#endif /* SYS_WINNT */
85
86
87/*
88 * init_timer - initialize the timer data structures
89 */
90void
91init_timer(void)
92{
93#if !defined(VMS)
94# if !defined SYS_WINNT || defined(SYS_CYGWIN32)
95# ifndef HAVE_TIMER_SETTIME
96 struct itimerval itimer;
97# else
98 static timer_t ntpd_timerid; /* should be global if we ever want */
99 /* to kill timer without rebooting ... */
100 struct itimerspec itimer;
101# endif /* HAVE_TIMER_SETTIME */
102# else /* SYS_WINNT */
103 HANDLE hToken;
104 TOKEN_PRIVILEGES tkp;
105# endif /* SYS_WINNT */
106#endif /* !VMS */
107
108 /*
109 * Initialize...
110 */
111 alarm_flag = 0;
112 alarm_overflow = 0;
113 adjust_timer = 1;
114 hourly_timer = HOUR;
115 huffpuff_timer = 0;
116 current_time = 0;
117 timer_overflows = 0;
118 timer_xmtcalls = 0;
119 timer_timereset = 0;
120
121#if !defined(SYS_WINNT)
122 /*
123 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
124 * seconds from now and they continue on every 2**EVENT_TIMEOUT
125 * seconds.
126 */
127# if !defined(VMS)
128# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
129 if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
130# ifdef SYS_VXWORKS
131 ERROR
132# else
133 -1
134# endif
135 )
136 {
137 fprintf (stderr, "timer create FAILED\n");
138 exit (0);
139 }
140 (void) signal_no_reset(SIGALRM, alarming);
141 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
142 itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
143 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
144# else
145 (void) signal_no_reset(SIGALRM, alarming);
146 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
147 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
148 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
149# endif
150# else /* VMS */
151 vmsinc[0] = 10000000; /* 1 sec */
152 vmsinc[1] = 0;
153 lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
154
155 sys$gettim(&vmstimer); /* that's "now" as abstime */
156
157 lib$addx(&vmsinc, &vmstimer, &vmstimer);
158 sys$setimr(0, &vmstimer, alarming, alarming, 0);
159# endif /* VMS */
160#else /* SYS_WINNT */
161 _tzset();
162
163 /*
164 * Get privileges needed for fiddling with the clock
165 */
166
167 /* get the current process token handle */
168 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
169 msyslog(LOG_ERR, "OpenProcessToken failed: %m");
170 exit(1);
171 }
172 /* get the LUID for system-time privilege. */
173 LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
174 tkp.PrivilegeCount = 1; /* one privilege to set */
175 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
176 /* get set-time privilege for this process. */
177 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
178 /* cannot test return value of AdjustTokenPrivileges. */
179 if (GetLastError() != ERROR_SUCCESS) {
180 msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
181 }
182
183 /*
184 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
185 * Under Windows/NT,
186 */
187
188 WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
189 if (WaitableTimerHandle == NULL) {
190 msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
191 exit(1);
192 }
193 else {
194 DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
195 LARGE_INTEGER DueTime;
196 DueTime.QuadPart = Period * 10000i64;
197 if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
198 msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
199 exit(1);
200 }
201 }
202
203#endif /* SYS_WINNT */
204}
205
206#if defined(SYS_WINNT)
207extern HANDLE
208get_timer_handle(void)
209{
210 return WaitableTimerHandle;
211}
212#endif
213
214/*
215 * timer - dispatch anyone who needs to be
216 */
217void
218timer(void)
219{
220 register struct peer *peer, *next_peer;
221 u_int n;
222
223 current_time += (1<<EVENT_TIMEOUT);
224
225 /*
226 * Adjustment timeout first.
227 */
228 if (adjust_timer <= current_time) {
229 adjust_timer += 1;
230 adj_host_clock();
231 }
232
233 /*
234 * Now dispatch any peers whose event timer has expired. Be careful
235 * here, since the peer structure might go away as the result of
236 * the call.
237 */
238 for (n = 0; n < HASH_SIZE; n++) {
239 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
240 next_peer = peer->next;
241 if (peer->action && peer->nextaction <= current_time)
242 peer->action(peer);
243 if (peer->nextdate <= current_time) {
244#ifdef REFCLOCK
245 if (peer->flags & FLAG_REFCLOCK)
246 refclock_transmit(peer);
247 else
248 transmit(peer);
249#else /* REFCLOCK */
250 transmit(peer);
251#endif /* REFCLOCK */
252 }
253 }
254 }
255
256 /*
257 * Garbage collect expired keys.
258 */
259 if (keys_timer <= current_time) {
260 keys_timer += MINUTE;
261 auth_agekeys();
262 }
263
264 /*
265 * Huff-n'-puff filter
266 */
267 if (huffpuff_timer <= current_time) {
268 huffpuff_timer += HUFFPUFF;
269 huffpuff();
270 }
271
272#ifdef AUTOKEY
273 /*
274 * Garbage collect old keys and generate new private value
275 */
276 if (revoke_timer <= current_time) {
277 revoke_timer += sys_revoke;
278 expire_all();
279#ifdef DEBUG
280 if (debug)
281 printf("key expire: at %lu next %lu\n",
282 current_time, revoke_timer);
283#endif
284 }
285#endif /* AUTOKEY */
286
287 /*
288 * Finally, call the hourly routine.
289 */
290 if (hourly_timer <= current_time) {
291 hourly_timer += HOUR;
292 hourly_stats();
293 }
294}
295
296
297#ifndef SYS_WINNT
298/*
299 * alarming - tell the world we've been alarmed
300 */
301static RETSIGTYPE
302alarming(
303 int sig
304 )
305{
306#if !defined(VMS)
307 if (initializing)
308 return;
309 if (alarm_flag)
310 alarm_overflow++;
311 else
312 alarm_flag++;
313#else /* VMS AST routine */
314 if (!initializing) {
315 if (alarm_flag) alarm_overflow++;
316 else alarm_flag = 1; /* increment is no good */
317 }
318 lib$addx(&vmsinc,&vmstimer,&vmstimer);
319 sys$setimr(0,&vmstimer,alarming,alarming,0);
320#endif /* VMS */
321}
322#endif /* SYS_WINNT */
323
324
325/*
326 * timer_clr_stats - clear timer module stat counters
327 */
328void
329timer_clr_stats(void)
330{
331 timer_overflows = 0;
332 timer_xmtcalls = 0;
333 timer_timereset = current_time;
334}
335