/src/ntp-dev/ntpd/ntp_timer.c
Line | Count | Source (jump to first uncovered line) |
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 | | #include "ntp_calendar.h" |
12 | | #include "ntp_leapsec.h" |
13 | | |
14 | | #if defined(HAVE_IO_COMPLETION_PORT) |
15 | | # include "ntp_iocompletionport.h" |
16 | | # include "ntp_timer.h" |
17 | | #endif |
18 | | |
19 | | #include <stdio.h> |
20 | | #include <signal.h> |
21 | | #ifdef HAVE_SYS_SIGNAL_H |
22 | | # include <sys/signal.h> |
23 | | #endif |
24 | | #ifdef HAVE_UNISTD_H |
25 | | # include <unistd.h> |
26 | | #endif |
27 | | |
28 | | #ifdef KERNEL_PLL |
29 | | #include "ntp_syscall.h" |
30 | | #endif /* KERNEL_PLL */ |
31 | | |
32 | | #ifdef AUTOKEY |
33 | | #include <openssl/rand.h> |
34 | | #endif /* AUTOKEY */ |
35 | | |
36 | | |
37 | | /* TC_ERR represents the timer_create() error return value. */ |
38 | | #ifdef SYS_VXWORKS |
39 | | #define TC_ERR ERROR |
40 | | #else |
41 | | #define TC_ERR (-1) |
42 | | #endif |
43 | | |
44 | | |
45 | | static void check_leapsec(u_int32, const time_t*, int/*BOOL*/); |
46 | | |
47 | | /* |
48 | | * These routines provide support for the event timer. The timer is |
49 | | * implemented by an interrupt routine which sets a flag once every |
50 | | * second, and a timer routine which is called when the mainline code |
51 | | * gets around to seeing the flag. The timer routine dispatches the |
52 | | * clock adjustment code if its time has come, then searches the timer |
53 | | * queue for expiries which are dispatched to the transmit procedure. |
54 | | * Finally, we call the hourly procedure to do cleanup and print a |
55 | | * message. |
56 | | */ |
57 | | volatile int interface_interval; /* init_io() sets def. 300s */ |
58 | | |
59 | | /* |
60 | | * Initializing flag. All async routines watch this and only do their |
61 | | * thing when it is clear. |
62 | | */ |
63 | | int initializing; |
64 | | |
65 | | /* |
66 | | * Alarm flag. The mainline code imports this. |
67 | | */ |
68 | | volatile int alarm_flag; |
69 | | |
70 | | /* |
71 | | * The counters and timeouts |
72 | | */ |
73 | | static u_long interface_timer; /* interface update timer */ |
74 | | static u_long adjust_timer; /* second timer */ |
75 | | static u_long stats_timer; /* stats timer */ |
76 | | static u_long leapf_timer; /* Report leapfile problems once/day */ |
77 | | static u_long huffpuff_timer; /* huff-n'-puff timer */ |
78 | | static u_long worker_idle_timer;/* next check for idle intres */ |
79 | | u_long leapsec; /* seconds to next leap (proximity class) */ |
80 | | int leapdif; /* TAI difference step at next leap second*/ |
81 | | u_long orphwait; /* orphan wait time */ |
82 | | #ifdef AUTOKEY |
83 | | static u_long revoke_timer; /* keys revoke timer */ |
84 | | static u_long keys_timer; /* session key timer */ |
85 | | u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ |
86 | | u_char sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */ |
87 | | #endif /* AUTOKEY */ |
88 | | |
89 | | /* |
90 | | * Statistics counter for the interested. |
91 | | */ |
92 | | volatile u_long alarm_overflow; |
93 | | |
94 | | u_long current_time; /* seconds since startup */ |
95 | | |
96 | | /* |
97 | | * Stats. Number of overflows and number of calls to transmit(). |
98 | | */ |
99 | | u_long timer_timereset; |
100 | | u_long timer_overflows; |
101 | | u_long timer_xmtcalls; |
102 | | |
103 | | #if defined(VMS) |
104 | | static int vmstimer[2]; /* time for next timer AST */ |
105 | | static int vmsinc[2]; /* timer increment */ |
106 | | #endif /* VMS */ |
107 | | |
108 | | #ifdef SYS_WINNT |
109 | | HANDLE WaitableTimerHandle; |
110 | | #else |
111 | | static RETSIGTYPE alarming (int); |
112 | | #endif /* SYS_WINNT */ |
113 | | |
114 | | #if !defined(VMS) |
115 | | # if !defined SYS_WINNT || defined(SYS_CYGWIN32) |
116 | | # ifdef HAVE_TIMER_CREATE |
117 | | static timer_t timer_id; |
118 | | typedef struct itimerspec intervaltimer; |
119 | | # define itv_frac tv_nsec |
120 | | # else |
121 | | typedef struct itimerval intervaltimer; |
122 | 2 | # define itv_frac tv_usec |
123 | | # endif |
124 | | intervaltimer itimer; |
125 | | # endif |
126 | | #endif |
127 | | |
128 | | #if !defined(SYS_WINNT) && !defined(VMS) |
129 | | void set_timer_or_die(const intervaltimer *); |
130 | | #endif |
131 | | |
132 | | |
133 | | #if !defined(SYS_WINNT) && !defined(VMS) |
134 | | void |
135 | | set_timer_or_die( |
136 | | const intervaltimer * ptimer |
137 | | ) |
138 | 1 | { |
139 | 1 | const char * setfunc; |
140 | 1 | int rc; |
141 | | |
142 | | # ifdef HAVE_TIMER_CREATE |
143 | | setfunc = "timer_settime"; |
144 | | rc = timer_settime(timer_id, 0, &itimer, NULL); |
145 | | # else |
146 | 1 | setfunc = "setitimer"; |
147 | 1 | rc = setitimer(ITIMER_REAL, &itimer, NULL); |
148 | 1 | # endif |
149 | 1 | if (-1 == rc) { |
150 | 0 | msyslog(LOG_ERR, "interval timer %s failed, %m", |
151 | 0 | setfunc); |
152 | 0 | exit(1); |
153 | 0 | } |
154 | 1 | } |
155 | | #endif /* !SYS_WINNT && !VMS */ |
156 | | |
157 | | |
158 | | /* |
159 | | * reinit_timer - reinitialize interval timer after a clock step. |
160 | | */ |
161 | | void |
162 | | reinit_timer(void) |
163 | 0 | { |
164 | 0 | #if !defined(SYS_WINNT) && !defined(VMS) |
165 | 0 | ZERO(itimer); |
166 | | # ifdef HAVE_TIMER_CREATE |
167 | | timer_gettime(timer_id, &itimer); |
168 | | # else |
169 | 0 | getitimer(ITIMER_REAL, &itimer); |
170 | 0 | # endif |
171 | 0 | if (itimer.it_value.tv_sec < 0 || |
172 | 0 | itimer.it_value.tv_sec > (1 << EVENT_TIMEOUT)) |
173 | 0 | itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); |
174 | 0 | if (itimer.it_value.itv_frac < 0) |
175 | 0 | itimer.it_value.itv_frac = 0; |
176 | 0 | if (0 == itimer.it_value.tv_sec && |
177 | 0 | 0 == itimer.it_value.itv_frac) |
178 | 0 | itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); |
179 | 0 | itimer.it_interval.tv_sec = (1 << EVENT_TIMEOUT); |
180 | 0 | itimer.it_interval.itv_frac = 0; |
181 | 0 | set_timer_or_die(&itimer); |
182 | 0 | # endif /* VMS */ |
183 | 0 | } |
184 | | |
185 | | |
186 | | /* |
187 | | * init_timer - initialize the timer data structures |
188 | | */ |
189 | | void |
190 | | init_timer(void) |
191 | 1 | { |
192 | | /* |
193 | | * Initialize... |
194 | | */ |
195 | 1 | alarm_flag = FALSE; |
196 | 1 | alarm_overflow = 0; |
197 | 1 | adjust_timer = 1; |
198 | 1 | stats_timer = SECSPERHR; |
199 | 1 | leapf_timer = SECSPERDAY; |
200 | 1 | huffpuff_timer = 0; |
201 | 1 | interface_timer = 0; |
202 | 1 | current_time = 0; |
203 | 1 | timer_overflows = 0; |
204 | 1 | timer_xmtcalls = 0; |
205 | 1 | timer_timereset = 0; |
206 | | |
207 | 1 | #ifndef SYS_WINNT |
208 | | /* |
209 | | * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT |
210 | | * seconds from now and they continue on every 2**EVENT_TIMEOUT |
211 | | * seconds. |
212 | | */ |
213 | 1 | # ifndef VMS |
214 | | # ifdef HAVE_TIMER_CREATE |
215 | | if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) { |
216 | | msyslog(LOG_ERR, "timer_create failed, %m"); |
217 | | exit(1); |
218 | | } |
219 | | # endif |
220 | 1 | signal_no_reset(SIGALRM, alarming); |
221 | 1 | itimer.it_interval.tv_sec = |
222 | 1 | itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); |
223 | 1 | itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0; |
224 | 1 | set_timer_or_die(&itimer); |
225 | | # else /* VMS follows */ |
226 | | vmsinc[0] = 10000000; /* 1 sec */ |
227 | | vmsinc[1] = 0; |
228 | | lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); |
229 | | |
230 | | sys$gettim(&vmstimer); /* that's "now" as abstime */ |
231 | | |
232 | | lib$addx(&vmsinc, &vmstimer, &vmstimer); |
233 | | sys$setimr(0, &vmstimer, alarming, alarming, 0); |
234 | | # endif /* VMS */ |
235 | | #else /* SYS_WINNT follows */ |
236 | | /* |
237 | | * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds |
238 | | * Under Windows/NT, |
239 | | */ |
240 | | |
241 | | WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); |
242 | | if (WaitableTimerHandle == NULL) { |
243 | | msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); |
244 | | exit(1); |
245 | | } |
246 | | else { |
247 | | DWORD Period; |
248 | | LARGE_INTEGER DueTime; |
249 | | BOOL rc; |
250 | | |
251 | | Period = (1 << EVENT_TIMEOUT) * 1000; |
252 | | DueTime.QuadPart = Period * 10000i64; |
253 | | rc = SetWaitableTimer(WaitableTimerHandle, &DueTime, |
254 | | Period, NULL, NULL, FALSE); |
255 | | if (!rc) { |
256 | | msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); |
257 | | exit(1); |
258 | | } |
259 | | } |
260 | | |
261 | | #endif /* SYS_WINNT */ |
262 | 1 | } |
263 | | |
264 | | |
265 | | /* |
266 | | * intres_timeout_req(s) is invoked in the parent to schedule an idle |
267 | | * timeout to fire in s seconds, if not reset earlier by a call to |
268 | | * intres_timeout_req(0), which clears any pending timeout. When the |
269 | | * timeout expires, worker_idle_timer_fired() is invoked (again, in the |
270 | | * parent). |
271 | | * |
272 | | * sntp and ntpd each provide implementations adapted to their timers. |
273 | | */ |
274 | | void |
275 | | intres_timeout_req( |
276 | | u_int seconds /* 0 cancels */ |
277 | | ) |
278 | 0 | { |
279 | | #if defined(HAVE_DROPROOT) && defined(NEED_EARLY_FORK) |
280 | | if (droproot) { |
281 | | worker_idle_timer = 0; |
282 | | return; |
283 | | } |
284 | | #endif |
285 | 0 | if (0 == seconds) { |
286 | 0 | worker_idle_timer = 0; |
287 | 0 | return; |
288 | 0 | } |
289 | 0 | worker_idle_timer = current_time + seconds; |
290 | 0 | } |
291 | | |
292 | | |
293 | | /* |
294 | | * timer - event timer |
295 | | */ |
296 | | void |
297 | | timer(void) |
298 | 0 | { |
299 | 0 | struct peer * p; |
300 | 0 | struct peer * next_peer; |
301 | 0 | l_fp now; |
302 | 0 | time_t tnow; |
303 | | |
304 | | /* |
305 | | * The basic timerevent is one second. This is used to adjust the |
306 | | * system clock in time and frequency, implement the kiss-o'-death |
307 | | * function and the association polling function. |
308 | | */ |
309 | 0 | current_time++; |
310 | 0 | if (adjust_timer <= current_time) { |
311 | 0 | adjust_timer += 1; |
312 | 0 | adj_host_clock(); |
313 | 0 | #ifdef REFCLOCK |
314 | 0 | for (p = peer_list; p != NULL; p = next_peer) { |
315 | 0 | next_peer = p->p_link; |
316 | 0 | if (FLAG_REFCLOCK & p->flags) |
317 | 0 | refclock_timer(p); |
318 | 0 | } |
319 | 0 | #endif /* REFCLOCK */ |
320 | 0 | } |
321 | | |
322 | | /* |
323 | | * Now dispatch any peers whose event timer has expired. Be |
324 | | * careful here, since the peer structure might go away as the |
325 | | * result of the call. |
326 | | */ |
327 | 0 | for (p = peer_list; p != NULL; p = next_peer) { |
328 | 0 | next_peer = p->p_link; |
329 | | |
330 | | /* |
331 | | * Restrain the non-burst packet rate not more |
332 | | * than one packet every 16 seconds. This is |
333 | | * usually tripped using iburst and minpoll of |
334 | | * 128 s or less. |
335 | | */ |
336 | 0 | if (p->throttle > 0) |
337 | 0 | p->throttle--; |
338 | 0 | if (p->nextdate <= current_time) { |
339 | 0 | #ifdef REFCLOCK |
340 | 0 | if (FLAG_REFCLOCK & p->flags) |
341 | 0 | refclock_transmit(p); |
342 | 0 | else |
343 | 0 | #endif /* REFCLOCK */ |
344 | 0 | transmit(p); |
345 | 0 | } |
346 | 0 | } |
347 | | |
348 | | /* |
349 | | * Orphan mode is active when enabled and when no servers less |
350 | | * than the orphan stratum are available. A server with no other |
351 | | * synchronization source is an orphan. It shows offset zero and |
352 | | * reference ID the loopback address. |
353 | | */ |
354 | 0 | if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL && |
355 | 0 | current_time > orphwait) { |
356 | 0 | if (sys_leap == LEAP_NOTINSYNC) { |
357 | 0 | set_sys_leap(LEAP_NOWARNING); |
358 | | #ifdef AUTOKEY |
359 | | if (crypto_flags) |
360 | | crypto_update(); |
361 | | #endif /* AUTOKEY */ |
362 | 0 | } |
363 | 0 | sys_stratum = (u_char)sys_orphan; |
364 | 0 | if (sys_stratum > 1) |
365 | 0 | sys_refid = htonl(LOOPBACKADR); |
366 | 0 | else |
367 | 0 | memcpy(&sys_refid, "LOOP", 4); |
368 | 0 | sys_offset = 0; |
369 | 0 | sys_rootdelay = 0; |
370 | 0 | sys_rootdisp = 0; |
371 | 0 | } |
372 | |
|
373 | 0 | get_systime(&now); |
374 | 0 | time(&tnow); |
375 | | |
376 | | /* |
377 | | * Leapseconds. Get time and defer to worker if either something |
378 | | * is imminent or every 8th second. |
379 | | */ |
380 | 0 | if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7)) |
381 | 0 | check_leapsec(now.l_ui, &tnow, |
382 | 0 | (sys_leap == LEAP_NOTINSYNC)); |
383 | 0 | if (sys_leap != LEAP_NOTINSYNC) { |
384 | 0 | if (leapsec >= LSPROX_ANNOUNCE && leapdif) { |
385 | 0 | if (leapdif > 0) |
386 | 0 | set_sys_leap(LEAP_ADDSECOND); |
387 | 0 | else |
388 | 0 | set_sys_leap(LEAP_DELSECOND); |
389 | 0 | } else { |
390 | 0 | set_sys_leap(LEAP_NOWARNING); |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | /* |
395 | | * Update huff-n'-puff filter. |
396 | | */ |
397 | 0 | if (huffpuff_timer <= current_time) { |
398 | 0 | huffpuff_timer += HUFFPUFF; |
399 | 0 | huffpuff(); |
400 | 0 | } |
401 | |
|
402 | | #ifdef AUTOKEY |
403 | | /* |
404 | | * Garbage collect expired keys. |
405 | | */ |
406 | | if (keys_timer <= current_time) { |
407 | | keys_timer += (1UL << sys_automax); |
408 | | auth_agekeys(); |
409 | | } |
410 | | |
411 | | /* |
412 | | * Generate new private value. This causes all associations |
413 | | * to regenerate cookies. |
414 | | */ |
415 | | if (revoke_timer && revoke_timer <= current_time) { |
416 | | revoke_timer += (1UL << sys_revoke); |
417 | | RAND_bytes((u_char *)&sys_private, 4); |
418 | | } |
419 | | #endif /* AUTOKEY */ |
420 | | |
421 | | /* |
422 | | * Interface update timer |
423 | | */ |
424 | 0 | if (interface_interval && interface_timer <= current_time) { |
425 | 0 | timer_interfacetimeout(current_time + |
426 | 0 | interface_interval); |
427 | 0 | DPRINTF(2, ("timer: interface update\n")); |
428 | 0 | interface_update(NULL, NULL); |
429 | 0 | } |
430 | |
|
431 | 0 | if (worker_idle_timer && worker_idle_timer <= current_time) |
432 | 0 | worker_idle_timer_fired(); |
433 | | |
434 | | /* |
435 | | * Finally, write hourly stats and do the hourly |
436 | | * and daily leapfile checks. |
437 | | */ |
438 | 0 | if (stats_timer <= current_time) { |
439 | 0 | stats_timer += SECSPERHR; |
440 | 0 | write_stats(); |
441 | 0 | if (leapf_timer <= current_time) { |
442 | 0 | leapf_timer += SECSPERDAY; |
443 | 0 | check_leap_file(TRUE, now.l_ui, &tnow); |
444 | 0 | } else { |
445 | 0 | check_leap_file(FALSE, now.l_ui, &tnow); |
446 | 0 | } |
447 | 0 | } |
448 | 0 | } |
449 | | |
450 | | |
451 | | #ifndef SYS_WINNT |
452 | | /* |
453 | | * alarming - tell the world we've been alarmed |
454 | | */ |
455 | | static RETSIGTYPE |
456 | | alarming( |
457 | | int sig |
458 | | ) |
459 | 0 | { |
460 | 0 | # ifdef DEBUG |
461 | 0 | const char *msg = "alarming: initializing TRUE\n"; |
462 | 0 | # endif |
463 | |
|
464 | 0 | if (!initializing) { |
465 | 0 | if (alarm_flag) { |
466 | 0 | alarm_overflow++; |
467 | 0 | # ifdef DEBUG |
468 | 0 | msg = "alarming: overflow\n"; |
469 | 0 | # endif |
470 | 0 | } else { |
471 | 0 | # ifndef VMS |
472 | 0 | alarm_flag++; |
473 | | # else |
474 | | /* VMS AST routine, increment is no good */ |
475 | | alarm_flag = 1; |
476 | | # endif |
477 | 0 | # ifdef DEBUG |
478 | 0 | msg = "alarming: normal\n"; |
479 | 0 | # endif |
480 | 0 | } |
481 | 0 | } |
482 | | # ifdef VMS |
483 | | lib$addx(&vmsinc, &vmstimer, &vmstimer); |
484 | | sys$setimr(0, &vmstimer, alarming, alarming, 0); |
485 | | # endif |
486 | 0 | # ifdef DEBUG |
487 | 0 | if (debug >= 4) |
488 | 0 | (void)(-1 == write(1, msg, strlen(msg))); |
489 | 0 | # endif |
490 | 0 | } |
491 | | #endif /* SYS_WINNT */ |
492 | | |
493 | | |
494 | | void |
495 | | timer_interfacetimeout(u_long timeout) |
496 | 0 | { |
497 | 0 | interface_timer = timeout; |
498 | 0 | } |
499 | | |
500 | | |
501 | | /* |
502 | | * timer_clr_stats - clear timer module stat counters |
503 | | */ |
504 | | void |
505 | | timer_clr_stats(void) |
506 | 0 | { |
507 | 0 | timer_overflows = 0; |
508 | 0 | timer_xmtcalls = 0; |
509 | 0 | timer_timereset = current_time; |
510 | 0 | } |
511 | | |
512 | | |
513 | | static void |
514 | 0 | check_leap_sec_in_progress( const leap_result_t *lsdata ) { |
515 | 0 | int prv_leap_sec_in_progress = leap_sec_in_progress; |
516 | 0 | leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3); |
517 | | |
518 | | /* if changed we may have to update the leap status sent to clients */ |
519 | 0 | if (leap_sec_in_progress != prv_leap_sec_in_progress) |
520 | 0 | set_sys_leap(sys_leap); |
521 | 0 | } |
522 | | |
523 | | |
524 | | static void |
525 | | check_leapsec( |
526 | | u_int32 now , |
527 | | const time_t * tpiv , |
528 | | int/*BOOL*/ reset) |
529 | 0 | { |
530 | 0 | static const char leapmsg_p_step[] = |
531 | 0 | "Positive leap second, stepped backward."; |
532 | 0 | static const char leapmsg_p_slew[] = |
533 | 0 | "Positive leap second, no step correction. " |
534 | 0 | "System clock will be inaccurate for a long time."; |
535 | |
|
536 | 0 | static const char leapmsg_n_step[] = |
537 | 0 | "Negative leap second, stepped forward."; |
538 | 0 | static const char leapmsg_n_slew[] = |
539 | 0 | "Negative leap second, no step correction. " |
540 | 0 | "System clock will be inaccurate for a long time."; |
541 | |
|
542 | 0 | leap_result_t lsdata; |
543 | 0 | u_int32 lsprox; |
544 | | #ifdef AUTOKEY |
545 | | int/*BOOL*/ update_autokey = FALSE; |
546 | | #endif |
547 | |
|
548 | 0 | #ifndef SYS_WINNT /* WinNT port has its own leap second handling */ |
549 | 0 | # ifdef KERNEL_PLL |
550 | 0 | leapsec_electric(pll_control && kern_enable); |
551 | | # else |
552 | | leapsec_electric(0); |
553 | | # endif |
554 | 0 | #endif |
555 | | #ifdef LEAP_SMEAR |
556 | | leap_smear.enabled = leap_smear_intv != 0; |
557 | | #endif |
558 | 0 | if (reset) { |
559 | 0 | lsprox = LSPROX_NOWARN; |
560 | 0 | leapsec_reset_frame(); |
561 | 0 | memset(&lsdata, 0, sizeof(lsdata)); |
562 | 0 | } else { |
563 | 0 | int fired; |
564 | |
|
565 | 0 | fired = leapsec_query(&lsdata, now, tpiv); |
566 | |
|
567 | 0 | DPRINTF(3, ("*** leapsec_query: fired %i, now %u (0x%08X), tai_diff %i, ddist %u\n", |
568 | 0 | fired, now, now, lsdata.tai_diff, lsdata.ddist)); |
569 | |
|
570 | | #ifdef LEAP_SMEAR |
571 | | leap_smear.in_progress = 0; |
572 | | leap_smear.doffset = 0.0; |
573 | | |
574 | | if (leap_smear.enabled) { |
575 | | if (lsdata.tai_diff) { |
576 | | if (leap_smear.interval == 0) { |
577 | | leap_smear.interval = leap_smear_intv; |
578 | | leap_smear.intv_end = lsdata.ttime.Q_s; |
579 | | leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval; |
580 | | DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n", |
581 | | leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end)); |
582 | | } |
583 | | } else { |
584 | | if (leap_smear.interval) |
585 | | DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n")); |
586 | | leap_smear.interval = 0; |
587 | | } |
588 | | |
589 | | if (leap_smear.interval) { |
590 | | double dtemp = now; |
591 | | if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) { |
592 | | double leap_smear_time = dtemp - leap_smear.intv_start; |
593 | | /* |
594 | | * For now we just do a linear interpolation over the smear interval |
595 | | */ |
596 | | #if 0 |
597 | | // linear interpolation |
598 | | leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval); |
599 | | #else |
600 | | // Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0 |
601 | | leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0; |
602 | | #endif |
603 | | /* |
604 | | * TODO see if we're inside an inserted leap second, so we need to compute |
605 | | * leap_smear.doffset = 1.0 - leap_smear.doffset |
606 | | */ |
607 | | leap_smear.in_progress = 1; |
608 | | #if 0 && defined( DEBUG ) |
609 | | msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", |
610 | | leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, |
611 | | now, leap_smear_time, leap_smear.doffset); |
612 | | #else |
613 | | DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", |
614 | | leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, |
615 | | now, leap_smear_time, leap_smear.doffset)); |
616 | | #endif |
617 | | |
618 | | } |
619 | | } |
620 | | } |
621 | | else |
622 | | leap_smear.interval = 0; |
623 | | |
624 | | /* |
625 | | * Update the current leap smear offset, eventually 0.0 if outside smear interval. |
626 | | */ |
627 | | DTOLFP(leap_smear.doffset, &leap_smear.offset); |
628 | | |
629 | | #endif /* LEAP_SMEAR */ |
630 | |
|
631 | 0 | if (fired) { |
632 | | /* Full hit. Eventually step the clock, but always |
633 | | * announce the leap event has happened. |
634 | | */ |
635 | 0 | const char *leapmsg = NULL; |
636 | 0 | double lswarp = lsdata.warped; |
637 | 0 | if (lswarp < 0.0) { |
638 | 0 | if (clock_max_back > 0.0 && |
639 | 0 | clock_max_back < -lswarp) { |
640 | 0 | step_systime(lswarp); |
641 | 0 | leapmsg = leapmsg_p_step; |
642 | 0 | } else { |
643 | 0 | leapmsg = leapmsg_p_slew; |
644 | 0 | } |
645 | 0 | } else if (lswarp > 0.0) { |
646 | 0 | if (clock_max_fwd > 0.0 && |
647 | 0 | clock_max_fwd < lswarp) { |
648 | 0 | step_systime(lswarp); |
649 | 0 | leapmsg = leapmsg_n_step; |
650 | 0 | } else { |
651 | 0 | leapmsg = leapmsg_n_slew; |
652 | 0 | } |
653 | 0 | } |
654 | 0 | if (leapmsg) |
655 | 0 | msyslog(LOG_NOTICE, "%s", leapmsg); |
656 | 0 | report_event(EVNT_LEAP, NULL, NULL); |
657 | | #ifdef AUTOKEY |
658 | | update_autokey = TRUE; |
659 | | #endif |
660 | 0 | lsprox = LSPROX_NOWARN; |
661 | 0 | leapsec = LSPROX_NOWARN; |
662 | 0 | sys_tai = lsdata.tai_offs; |
663 | 0 | } else { |
664 | | #ifdef AUTOKEY |
665 | | update_autokey = (sys_tai != (u_int)lsdata.tai_offs); |
666 | | #endif |
667 | 0 | lsprox = lsdata.proximity; |
668 | 0 | sys_tai = lsdata.tai_offs; |
669 | 0 | } |
670 | 0 | } |
671 | | |
672 | | /* We guard against panic alarming during the red alert phase. |
673 | | * Strange and evil things might happen if we go from stone cold |
674 | | * to piping hot in one step. If things are already that wobbly, |
675 | | * we let the normal clock correction take over, even if a jump |
676 | | * is involved. |
677 | | * Also make sure the alarming events are edge-triggered, that is, |
678 | | * ceated only when the threshold is crossed. |
679 | | */ |
680 | 0 | if ( (leapsec > 0 || lsprox < LSPROX_ALERT) |
681 | 0 | && leapsec < lsprox ) { |
682 | 0 | if ( leapsec < LSPROX_SCHEDULE |
683 | 0 | && lsprox >= LSPROX_SCHEDULE) { |
684 | 0 | if (lsdata.dynamic) |
685 | 0 | report_event(PEVNT_ARMED, sys_peer, NULL); |
686 | 0 | else |
687 | 0 | report_event(EVNT_ARMED, NULL, NULL); |
688 | 0 | } |
689 | 0 | leapsec = lsprox; |
690 | 0 | } |
691 | 0 | if (leapsec > lsprox) { |
692 | 0 | if ( leapsec >= LSPROX_SCHEDULE |
693 | 0 | && lsprox < LSPROX_SCHEDULE) { |
694 | 0 | report_event(EVNT_DISARMED, NULL, NULL); |
695 | 0 | } |
696 | 0 | leapsec = lsprox; |
697 | 0 | } |
698 | |
|
699 | 0 | if (leapsec >= LSPROX_SCHEDULE) |
700 | 0 | leapdif = lsdata.tai_diff; |
701 | 0 | else |
702 | 0 | leapdif = 0; |
703 | |
|
704 | 0 | check_leap_sec_in_progress(&lsdata); |
705 | |
|
706 | | #ifdef AUTOKEY |
707 | | if (update_autokey) |
708 | | crypto_update_taichange(); |
709 | | #endif |
710 | 0 | } |