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