]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/ntpd/ntp_timer.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / ntpd / ntp_timer.c
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 volatile int interface_interval = 300;     /* update interface every 5 minutes as default */
38           
39 /*
40  * Alarm flag.  The mainline code imports this.
41  */
42 volatile int alarm_flag;
43
44 /*
45  * The counters
46  */
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 */
52 #ifdef OPENSSL
53 static  u_long revoke_timer;            /* keys revoke timer */
54 u_char  sys_revoke = KEY_REVOKE;        /* keys revoke timeout (log2 s) */
55 #endif /* OPENSSL */
56
57 /*
58  * Statistics counter for the interested.
59  */
60 volatile u_long alarm_overflow;
61
62 #define MINUTE  60
63 #define HOUR    (60*60)
64
65 u_long current_time;
66
67 /*
68  * Stats.  Number of overflows and number of calls to transmit().
69  */
70 u_long timer_timereset;
71 u_long timer_overflows;
72 u_long timer_xmtcalls;
73
74 #if defined(VMS)
75 static int vmstimer[2];         /* time for next timer AST */
76 static int vmsinc[2];           /* timer increment */
77 #endif /* VMS */
78
79 #if defined SYS_WINNT
80 static HANDLE WaitableTimerHandle = NULL;
81 #else
82 static  RETSIGTYPE alarming P((int));
83 #endif /* SYS_WINNT */
84
85 #if !defined(VMS)
86 # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
87 #  ifndef HAVE_TIMER_SETTIME
88         struct itimerval itimer;
89 #  else 
90         static timer_t ntpd_timerid;
91         struct itimerspec itimer;
92 #  endif /* HAVE_TIMER_SETTIME */
93 # endif /* SYS_WINNT */
94 #endif /* VMS */
95
96 /*
97  * reinit_timer - reinitialize interval timer.
98  */
99 void 
100 reinit_timer(void)
101 {
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);
107         }
108         if (itimer.it_value.tv_nsec < 0 ) {
109                 itimer.it_value.tv_nsec = 0;
110         }
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;
114         }
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);
118 #  else
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);
122         }
123         if (itimer.it_value.tv_usec < 0 ) {
124                 itimer.it_value.tv_usec = 0;
125         }
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;
129         }
130         itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
131         itimer.it_interval.tv_usec = 0;
132         setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
133 #  endif
134 # endif /* VMS */
135 }
136
137 /*
138  * init_timer - initialize the timer data structures
139  */
140 void
141 init_timer(void)
142 {
143 # if defined SYS_WINNT & !defined(SYS_CYGWIN32)
144         HANDLE hToken = INVALID_HANDLE_VALUE;
145         TOKEN_PRIVILEGES tkp;
146 # endif /* SYS_WINNT */
147
148         /*
149          * Initialize...
150          */
151         alarm_flag = 0;
152         alarm_overflow = 0;
153         adjust_timer = 1;
154         stats_timer = 0;
155         huffpuff_timer = 0;
156         interface_timer = 0;
157         current_time = 0;
158         timer_overflows = 0;
159         timer_xmtcalls = 0;
160         timer_timereset = 0;
161
162 #if !defined(SYS_WINNT)
163         /*
164          * Set up the alarm interrupt.  The first comes 2**EVENT_TIMEOUT
165          * seconds from now and they continue on every 2**EVENT_TIMEOUT
166          * seconds.
167          */
168 # if !defined(VMS)
169 #  if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
170         if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
171 #       ifdef SYS_VXWORKS
172                 ERROR
173 #       else
174                 -1
175 #       endif
176            )
177         {
178                 fprintf (stderr, "timer create FAILED\n");
179                 exit (0);
180         }
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);
185 #  else
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);
190 #  endif
191 # else /* VMS */
192         vmsinc[0] = 10000000;           /* 1 sec */
193         vmsinc[1] = 0;
194         lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
195
196         sys$gettim(&vmstimer);  /* that's "now" as abstime */
197
198         lib$addx(&vmsinc, &vmstimer, &vmstimer);
199         sys$setimr(0, &vmstimer, alarming, alarming, 0);
200 # endif /* VMS */
201 #else /* SYS_WINNT */
202         _tzset();
203
204         /*
205          * Get privileges needed for fiddling with the clock
206          */
207
208         /* get the current process token handle */
209         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
210                 msyslog(LOG_ERR, "OpenProcessToken failed: %m");
211                 exit(1);
212         }
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");
222         }
223
224         /*
225          * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
226          * Under Windows/NT, 
227          */
228
229         WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
230         if (WaitableTimerHandle == NULL) {
231                 msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
232                 exit(1);
233         }
234         else {
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");
240                         exit(1);
241                 }
242         }
243
244 #endif /* SYS_WINNT */
245 }
246
247 #if defined(SYS_WINNT)
248 extern HANDLE 
249 get_timer_handle(void)
250 {
251         return WaitableTimerHandle;
252 }
253 #endif
254
255 /*
256  * timer - dispatch anyone who needs to be
257  */
258 void
259 timer(void)
260 {
261         register struct peer *peer, *next_peer;
262 #ifdef OPENSSL
263         char    statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
264 #endif /* OPENSSL */
265         u_int n;
266
267         current_time += (1<<EVENT_TIMEOUT);
268
269         /*
270          * Adjustment timeout first.
271          */
272         if (adjust_timer <= current_time) {
273                 adjust_timer += 1;
274                 adj_host_clock();
275                 kod_proto();
276 #ifdef REFCLOCK
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);
282                         }
283                 }
284 #endif /* REFCLOCK */
285         }
286
287         /*
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
290          * the call.
291          */
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)
296                                 peer->action(peer);
297                         if (peer->nextdate <= current_time) {
298 #ifdef REFCLOCK
299                                 if (peer->flags & FLAG_REFCLOCK)
300                                         refclock_transmit(peer);
301                                 else
302                                         transmit(peer);
303 #else /* REFCLOCK */
304                                 transmit(peer);
305 #endif /* REFCLOCK */
306                         }
307                 }
308         }
309
310         /*
311          * Garbage collect expired keys.
312          */
313         if (keys_timer <= current_time) {
314                 keys_timer += MINUTE;
315                 auth_agekeys();
316         }
317
318         /*
319          * Huff-n'-puff filter
320          */
321         if (huffpuff_timer <= current_time) {
322                 huffpuff_timer += HUFFPUFF;
323                 huffpuff();
324         }
325
326 #ifdef OPENSSL
327         /*
328          * Garbage collect old keys and generate new private value
329          */
330         if (revoke_timer <= current_time) {
331                 revoke_timer += RANDPOLL(sys_revoke);
332                 expire_all();
333                 sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
334                 record_crypto_stats(NULL, statstr);
335 #ifdef DEBUG
336                 if (debug)
337                         printf("timer: %s\n", statstr);
338 #endif
339         }
340 #endif /* OPENSSL */
341
342         /*
343          * interface update timer
344          */
345         if (interface_interval && interface_timer <= current_time) {
346
347                 timer_interfacetimeout(current_time + interface_interval);
348                 DPRINTF(1, ("timer: interface update\n"));
349                 interface_update(NULL, NULL);
350         }
351         
352         /*
353          * Finally, periodically write stats.
354          */
355         if (stats_timer <= current_time) {
356              if (stats_timer != 0)
357                   write_stats();
358              stats_timer += stats_write_period;
359         }
360 }
361
362
363 #ifndef SYS_WINNT
364 /*
365  * alarming - tell the world we've been alarmed
366  */
367 static RETSIGTYPE
368 alarming(
369         int sig
370         )
371 {
372 #if !defined(VMS)
373         if (initializing)
374                 return;
375         if (alarm_flag)
376                 alarm_overflow++;
377         else
378                 alarm_flag++;
379 #else /* VMS AST routine */
380         if (!initializing) {
381                 if (alarm_flag) alarm_overflow++;
382                 else alarm_flag = 1;    /* increment is no good */
383         }
384         lib$addx(&vmsinc,&vmstimer,&vmstimer);
385         sys$setimr(0,&vmstimer,alarming,alarming,0);
386 #endif /* VMS */
387 }
388 #endif /* SYS_WINNT */
389
390 void
391 timer_interfacetimeout(u_long timeout)
392 {
393         interface_timer = timeout;
394 }
395
396
397 /*
398  * timer_clr_stats - clear timer module stat counters
399  */
400 void
401 timer_clr_stats(void)
402 {
403         timer_overflows = 0;
404         timer_xmtcalls = 0;
405         timer_timereset = current_time;
406 }
407