Annotation of embedaddon/ntp/ntpd/ntp_timer.c, revision 1.1.1.1
1.1 misho 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 KERNEL_PLL
27: #include "ntp_syscall.h"
28: #endif /* KERNEL_PLL */
29:
30: #ifdef OPENSSL
31: #include <openssl/rand.h>
32: #endif /* OPENSSL */
33:
34: /*
35: * These routines provide support for the event timer. The timer is
36: * implemented by an interrupt routine which sets a flag once every
37: * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
38: * is called when the mainline code gets around to seeing the flag.
39: * The timer routine dispatches the clock adjustment code if its time
40: * has come, then searches the timer queue for expiries which are
41: * dispatched to the transmit procedure. Finally, we call the hourly
42: * procedure to do cleanup and print a message.
43: */
44: volatile int interface_interval = 300; /* update interface every 5 minutes as default */
45:
46: /*
47: * Alarm flag. The mainline code imports this.
48: */
49: volatile int alarm_flag;
50:
51: /*
52: * The counters and timeouts
53: */
54: static u_long interface_timer; /* interface update timer */
55: static u_long adjust_timer; /* second timer */
56: static u_long stats_timer; /* stats timer */
57: static u_long huffpuff_timer; /* huff-n'-puff timer */
58: u_long leapsec; /* leapseconds countdown */
59: l_fp sys_time; /* current system time */
60: #ifdef OPENSSL
61: static u_long revoke_timer; /* keys revoke timer */
62: static u_long keys_timer; /* session key timer */
63: u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
64: u_long sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
65: #endif /* OPENSSL */
66:
67: /*
68: * Statistics counter for the interested.
69: */
70: volatile u_long alarm_overflow;
71:
72: #define MINUTE 60
73: #define HOUR (60 * MINUTE)
74: #define DAY (24 * HOUR)
75:
76: u_long current_time; /* seconds since startup */
77:
78: /*
79: * Stats. Number of overflows and number of calls to transmit().
80: */
81: u_long timer_timereset;
82: u_long timer_overflows;
83: u_long timer_xmtcalls;
84:
85: #if defined(VMS)
86: static int vmstimer[2]; /* time for next timer AST */
87: static int vmsinc[2]; /* timer increment */
88: #endif /* VMS */
89:
90: #if defined SYS_WINNT
91: static HANDLE WaitableTimerHandle = NULL;
92: #else
93: static RETSIGTYPE alarming (int);
94: #endif /* SYS_WINNT */
95:
96: #if !defined(VMS)
97: # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
98: # ifndef HAVE_TIMER_SETTIME
99: struct itimerval itimer;
100: # else
101: static timer_t ntpd_timerid;
102: struct itimerspec itimer;
103: # endif /* HAVE_TIMER_SETTIME */
104: # endif /* SYS_WINNT */
105: #endif /* VMS */
106:
107: /*
108: * reinit_timer - reinitialize interval timer.
109: */
110: void
111: reinit_timer(void)
112: {
113: #if !defined(SYS_WINNT) && !defined(VMS)
114: # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
115: timer_gettime(ntpd_timerid, &itimer);
116: if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
117: itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
118: }
119: if (itimer.it_value.tv_nsec < 0 ) {
120: itimer.it_value.tv_nsec = 0;
121: }
122: if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
123: itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
124: itimer.it_value.tv_nsec = 0;
125: }
126: itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
127: itimer.it_interval.tv_nsec = 0;
128: timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
129: # else
130: getitimer(ITIMER_REAL, &itimer);
131: if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
132: itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
133: }
134: if (itimer.it_value.tv_usec < 0 ) {
135: itimer.it_value.tv_usec = 0;
136: }
137: if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
138: itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
139: itimer.it_value.tv_usec = 0;
140: }
141: itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
142: itimer.it_interval.tv_usec = 0;
143: setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
144: # endif
145: # endif /* VMS */
146: }
147:
148: /*
149: * init_timer - initialize the timer data structures
150: */
151: void
152: init_timer(void)
153: {
154: /*
155: * Initialize...
156: */
157: alarm_flag = 0;
158: alarm_overflow = 0;
159: adjust_timer = 1;
160: stats_timer = 0;
161: huffpuff_timer = 0;
162: interface_timer = 0;
163: current_time = 0;
164: timer_overflows = 0;
165: timer_xmtcalls = 0;
166: timer_timereset = 0;
167:
168: #if !defined(SYS_WINNT)
169: /*
170: * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
171: * seconds from now and they continue on every 2**EVENT_TIMEOUT
172: * seconds.
173: */
174: # if !defined(VMS)
175: # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
176: if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
177: # ifdef SYS_VXWORKS
178: ERROR
179: # else
180: -1
181: # endif
182: )
183: {
184: fprintf (stderr, "timer create FAILED\n");
185: exit (0);
186: }
187: (void) signal_no_reset(SIGALRM, alarming);
188: itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
189: itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
190: timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
191: # else
192: (void) signal_no_reset(SIGALRM, alarming);
193: itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
194: itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
195: setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
196: # endif
197: # else /* VMS */
198: vmsinc[0] = 10000000; /* 1 sec */
199: vmsinc[1] = 0;
200: lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
201:
202: sys$gettim(&vmstimer); /* that's "now" as abstime */
203:
204: lib$addx(&vmsinc, &vmstimer, &vmstimer);
205: sys$setimr(0, &vmstimer, alarming, alarming, 0);
206: # endif /* VMS */
207: #else /* SYS_WINNT */
208: /*
209: * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
210: * Under Windows/NT,
211: */
212:
213: WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
214: if (WaitableTimerHandle == NULL) {
215: msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
216: exit(1);
217: }
218: else {
219: DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
220: LARGE_INTEGER DueTime;
221: DueTime.QuadPart = Period * 10000i64;
222: if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
223: msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
224: exit(1);
225: }
226: }
227:
228: #endif /* SYS_WINNT */
229: }
230:
231: #if defined(SYS_WINNT)
232: extern HANDLE
233: get_timer_handle(void)
234: {
235: return WaitableTimerHandle;
236: }
237: #endif
238:
239: /*
240: * timer - event timer
241: */
242: void
243: timer(void)
244: {
245: register struct peer *peer, *next_peer;
246: u_int n;
247:
248: /*
249: * The basic timerevent is one second. This is used to adjust
250: * the system clock in time and frequency, implement the
251: * kiss-o'-deatch function and implement the association
252: * polling function..
253: */
254: current_time++;
255: get_systime(&sys_time);
256: if (adjust_timer <= current_time) {
257: adjust_timer += 1;
258: adj_host_clock();
259: #ifdef REFCLOCK
260: for (n = 0; n < NTP_HASH_SIZE; n++) {
261: for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
262: next_peer = peer->next;
263: if (peer->flags & FLAG_REFCLOCK)
264: refclock_timer(peer);
265: }
266: }
267: #endif /* REFCLOCK */
268: }
269:
270: /*
271: * Now dispatch any peers whose event timer has expired. Be
272: * careful here, since the peer structure might go away as the
273: * result of the call.
274: */
275: for (n = 0; n < NTP_HASH_SIZE; n++) {
276: for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
277: next_peer = peer->next;
278: if (peer->action && peer->nextaction <=
279: current_time)
280: peer->action(peer);
281:
282: /*
283: * Restrain the non-burst packet rate not more
284: * than one packet every 16 seconds. This is
285: * usually tripped using iburst and minpoll of
286: * 128 s or less.
287: */
288: if (peer->throttle > 0)
289: peer->throttle--;
290: if (peer->nextdate <= current_time) {
291: #ifdef REFCLOCK
292: if (peer->flags & FLAG_REFCLOCK)
293: refclock_transmit(peer);
294: else
295: transmit(peer);
296: #else /* REFCLOCK */
297: transmit(peer);
298: #endif /* REFCLOCK */
299: }
300: }
301: }
302:
303: /*
304: * Orphan mode is active when enabled and when no servers less
305: * than the orphan stratum are available. A server with no other
306: * synchronization source is an orphan. It shows offset zero and
307: * reference ID the loopback address.
308: */
309: if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL) {
310: if (sys_leap == LEAP_NOTINSYNC) {
311: sys_leap = LEAP_NOWARNING;
312: #ifdef OPENSSL
313: if (crypto_flags)
314: crypto_update();
315: #endif /* OPENSSL */
316: }
317: sys_stratum = (u_char)sys_orphan;
318: if (sys_stratum > 1)
319: sys_refid = htonl(LOOPBACKADR);
320: else
321: memcpy(&sys_refid, "LOOP", 4);
322: sys_offset = 0;
323: sys_rootdelay = 0;
324: sys_rootdisp = 0;
325: }
326:
327: /*
328: * Leapseconds. If a leap is pending, decrement the time
329: * remaining. If less than one day remains, set the leap bits.
330: * When no time remains, clear the leap bits and increment the
331: * TAI. If kernel suppport is not available, do the leap
332: * crudely. Note a leap cannot be pending unless the clock is
333: * set.
334: */
335: if (leapsec > 0) {
336: leapsec--;
337: if (leapsec == 0) {
338: sys_leap = LEAP_NOWARNING;
339: sys_tai = leap_tai;
340: #ifdef KERNEL_PLL
341: if (!(pll_control && kern_enable))
342: step_systime(-1.0);
343: #else /* KERNEL_PLL */
344: #ifndef SYS_WINNT /* WinNT port has its own leap second handling */
345: step_systime(-1.0);
346: #endif /* SYS_WINNT */
347: #endif /* KERNEL_PLL */
348: report_event(EVNT_LEAP, NULL, NULL);
349: } else {
350: if (leapsec < DAY)
351: sys_leap = LEAP_ADDSECOND;
352: if (leap_tai > 0)
353: sys_tai = leap_tai - 1;
354: }
355: }
356:
357: /*
358: * Update huff-n'-puff filter.
359: */
360: if (huffpuff_timer <= current_time) {
361: huffpuff_timer += HUFFPUFF;
362: huffpuff();
363: }
364:
365: #ifdef OPENSSL
366: /*
367: * Garbage collect expired keys.
368: */
369: if (keys_timer <= current_time) {
370: keys_timer += 1 << sys_automax;
371: auth_agekeys();
372: }
373:
374: /*
375: * Garbage collect key list and generate new private value. The
376: * timer runs only after initial synchronization and fires about
377: * once per day.
378: */
379: if (revoke_timer <= current_time && sys_leap !=
380: LEAP_NOTINSYNC) {
381: revoke_timer += 1 << sys_revoke;
382: RAND_bytes((u_char *)&sys_private, 4);
383: }
384: #endif /* OPENSSL */
385:
386: /*
387: * Interface update timer
388: */
389: if (interface_interval && interface_timer <= current_time) {
390:
391: timer_interfacetimeout(current_time +
392: interface_interval);
393: DPRINTF(2, ("timer: interface update\n"));
394: interface_update(NULL, NULL);
395: }
396:
397: /*
398: * Finally, write hourly stats.
399: */
400: if (stats_timer <= current_time) {
401: stats_timer += HOUR;
402: write_stats();
403: if (sys_tai != 0 && sys_time.l_ui > leap_expire)
404: report_event(EVNT_LEAPVAL, NULL, NULL);
405: }
406: }
407:
408:
409: #ifndef SYS_WINNT
410: /*
411: * alarming - tell the world we've been alarmed
412: */
413: static RETSIGTYPE
414: alarming(
415: int sig
416: )
417: {
418: #if !defined(VMS)
419: if (initializing)
420: return;
421: if (alarm_flag)
422: alarm_overflow++;
423: else
424: alarm_flag++;
425: #else /* VMS AST routine */
426: if (!initializing) {
427: if (alarm_flag) alarm_overflow++;
428: else alarm_flag = 1; /* increment is no good */
429: }
430: lib$addx(&vmsinc,&vmstimer,&vmstimer);
431: sys$setimr(0,&vmstimer,alarming,alarming,0);
432: #endif /* VMS */
433: }
434: #endif /* SYS_WINNT */
435:
436: void
437: timer_interfacetimeout(u_long timeout)
438: {
439: interface_timer = timeout;
440: }
441:
442:
443: /*
444: * timer_clr_stats - clear timer module stat counters
445: */
446: void
447: timer_clr_stats(void)
448: {
449: timer_overflows = 0;
450: timer_xmtcalls = 0;
451: timer_timereset = current_time;
452: }
453:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>