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 408