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 /* 38 * Alarm flag. The mainline code imports this. 39 */ 40 volatile int alarm_flag; 41 42 /* 43 * The counters 44 */ 45 static u_long adjust_timer; /* second timer */ 46 static u_long keys_timer; /* minute timer */ 47 static u_long hourly_timer; /* hour timer */ 48 static u_long huffpuff_timer; /* huff-n'-puff timer */ 49 #ifdef OPENSSL 50 static u_long revoke_timer; /* keys revoke timer */ 51 u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */ 52 #endif /* OPENSSL */ 53 54 /* 55 * Statistics counter for the interested. 56 */ 57 volatile u_long alarm_overflow; 58 59 #define MINUTE 60 60 #define HOUR (60*60) 61 62 u_long current_time; 63 64 /* 65 * Stats. Number of overflows and number of calls to transmit(). 66 */ 67 u_long timer_timereset; 68 u_long timer_overflows; 69 u_long timer_xmtcalls; 70 71 #if defined(VMS) 72 static int vmstimer[2]; /* time for next timer AST */ 73 static int vmsinc[2]; /* timer increment */ 74 #endif /* VMS */ 75 76 #if defined SYS_WINNT 77 static HANDLE WaitableTimerHandle = NULL; 78 #else 79 static RETSIGTYPE alarming P((int)); 80 #endif /* SYS_WINNT */ 81 82 #if !defined(VMS) 83 # if !defined SYS_WINNT || defined(SYS_CYGWIN32) 84 # ifndef HAVE_TIMER_SETTIME 85 struct itimerval itimer; 86 # else 87 static timer_t ntpd_timerid; 88 struct itimerspec itimer; 89 # endif /* HAVE_TIMER_SETTIME */ 90 # endif /* SYS_WINNT */ 91 #endif /* VMS */ 92 93 /* 94 * reinit_timer - reinitialize interval timer. 95 */ 96 void 97 reinit_timer(void) 98 { 99 #if !defined(SYS_WINNT) && !defined(VMS) 100 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) 101 timer_gettime(ntpd_timerid, &itimer); 102 if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) { 103 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 104 } 105 if (itimer.it_value.tv_nsec < 0 ) { 106 itimer.it_value.tv_nsec = 0; 107 } 108 if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) { 109 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 110 itimer.it_value.tv_nsec = 0; 111 } 112 itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT); 113 itimer.it_interval.tv_nsec = 0; 114 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL); 115 # else 116 getitimer(ITIMER_REAL, &itimer); 117 if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) { 118 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 119 } 120 if (itimer.it_value.tv_usec < 0 ) { 121 itimer.it_value.tv_usec = 0; 122 } 123 if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) { 124 itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 125 itimer.it_value.tv_usec = 0; 126 } 127 itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT); 128 itimer.it_interval.tv_usec = 0; 129 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); 130 # endif 131 # endif /* VMS */ 132 } 133 134 /* 135 * init_timer - initialize the timer data structures 136 */ 137 void 138 init_timer(void) 139 { 140 # if defined SYS_WINNT & !defined(SYS_CYGWIN32) 141 HANDLE hToken; 142 TOKEN_PRIVILEGES tkp; 143 # endif /* SYS_WINNT */ 144 145 /* 146 * Initialize... 147 */ 148 alarm_flag = 0; 149 alarm_overflow = 0; 150 adjust_timer = 1; 151 hourly_timer = HOUR; 152 huffpuff_timer = 0; 153 current_time = 0; 154 timer_overflows = 0; 155 timer_xmtcalls = 0; 156 timer_timereset = 0; 157 158 #if !defined(SYS_WINNT) 159 /* 160 * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT 161 * seconds from now and they continue on every 2**EVENT_TIMEOUT 162 * seconds. 163 */ 164 # if !defined(VMS) 165 # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) 166 if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) == 167 # ifdef SYS_VXWORKS 168 ERROR 169 # else 170 -1 171 # endif 172 ) 173 { 174 fprintf (stderr, "timer create FAILED\n"); 175 exit (0); 176 } 177 (void) signal_no_reset(SIGALRM, alarming); 178 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 179 itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0; 180 timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL); 181 # else 182 (void) signal_no_reset(SIGALRM, alarming); 183 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT); 184 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0; 185 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); 186 # endif 187 # else /* VMS */ 188 vmsinc[0] = 10000000; /* 1 sec */ 189 vmsinc[1] = 0; 190 lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); 191 192 sys$gettim(&vmstimer); /* that's "now" as abstime */ 193 194 lib$addx(&vmsinc, &vmstimer, &vmstimer); 195 sys$setimr(0, &vmstimer, alarming, alarming, 0); 196 # endif /* VMS */ 197 #else /* SYS_WINNT */ 198 _tzset(); 199 200 /* 201 * Get privileges needed for fiddling with the clock 202 */ 203 204 /* get the current process token handle */ 205 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { 206 msyslog(LOG_ERR, "OpenProcessToken failed: %m"); 207 exit(1); 208 } 209 /* get the LUID for system-time privilege. */ 210 LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); 211 tkp.PrivilegeCount = 1; /* one privilege to set */ 212 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 213 /* get set-time privilege for this process. */ 214 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); 215 /* cannot test return value of AdjustTokenPrivileges. */ 216 if (GetLastError() != ERROR_SUCCESS) { 217 msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); 218 } 219 220 /* 221 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds 222 * Under Windows/NT, 223 */ 224 225 WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); 226 if (WaitableTimerHandle == NULL) { 227 msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); 228 exit(1); 229 } 230 else { 231 DWORD Period = (1<<EVENT_TIMEOUT) * 1000; 232 LARGE_INTEGER DueTime; 233 DueTime.QuadPart = Period * 10000i64; 234 if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) { 235 msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); 236 exit(1); 237 } 238 } 239 240 #endif /* SYS_WINNT */ 241 } 242 243 #if defined(SYS_WINNT) 244 extern HANDLE 245 get_timer_handle(void) 246 { 247 return WaitableTimerHandle; 248 } 249 #endif 250 251 /* 252 * timer - dispatch anyone who needs to be 253 */ 254 void 255 timer(void) 256 { 257 register struct peer *peer, *next_peer; 258 #ifdef OPENSSL 259 char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ 260 #endif /* OPENSSL */ 261 u_int n; 262 263 current_time += (1<<EVENT_TIMEOUT); 264 265 /* 266 * Adjustment timeout first. 267 */ 268 if (adjust_timer <= current_time) { 269 adjust_timer += 1; 270 adj_host_clock(); 271 kod_proto(); 272 } 273 274 /* 275 * Now dispatch any peers whose event timer has expired. Be careful 276 * here, since the peer structure might go away as the result of 277 * the call. 278 */ 279 for (n = 0; n < HASH_SIZE; n++) { 280 for (peer = peer_hash[n]; peer != 0; peer = next_peer) { 281 next_peer = peer->next; 282 if (peer->action && peer->nextaction <= current_time) 283 peer->action(peer); 284 if (peer->nextdate <= current_time) { 285 #ifdef REFCLOCK 286 if (peer->flags & FLAG_REFCLOCK) 287 refclock_transmit(peer); 288 else 289 transmit(peer); 290 #else /* REFCLOCK */ 291 transmit(peer); 292 #endif /* REFCLOCK */ 293 } 294 } 295 } 296 297 /* 298 * Garbage collect expired keys. 299 */ 300 if (keys_timer <= current_time) { 301 keys_timer += MINUTE; 302 auth_agekeys(); 303 } 304 305 /* 306 * Huff-n'-puff filter 307 */ 308 if (huffpuff_timer <= current_time) { 309 huffpuff_timer += HUFFPUFF; 310 huffpuff(); 311 } 312 313 #ifdef OPENSSL 314 /* 315 * Garbage collect old keys and generate new private value 316 */ 317 if (revoke_timer <= current_time) { 318 revoke_timer += RANDPOLL(sys_revoke); 319 expire_all(); 320 sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp)); 321 record_crypto_stats(NULL, statstr); 322 #ifdef DEBUG 323 if (debug) 324 printf("timer: %s\n", statstr); 325 #endif 326 } 327 #endif /* OPENSSL */ 328 329 /* 330 * Finally, call the hourly routine. 331 */ 332 if (hourly_timer <= current_time) { 333 hourly_timer += HOUR; 334 hourly_stats(); 335 } 336 } 337 338 339 #ifndef SYS_WINNT 340 /* 341 * alarming - tell the world we've been alarmed 342 */ 343 static RETSIGTYPE 344 alarming( 345 int sig 346 ) 347 { 348 #if !defined(VMS) 349 if (initializing) 350 return; 351 if (alarm_flag) 352 alarm_overflow++; 353 else 354 alarm_flag++; 355 #else /* VMS AST routine */ 356 if (!initializing) { 357 if (alarm_flag) alarm_overflow++; 358 else alarm_flag = 1; /* increment is no good */ 359 } 360 lib$addx(&vmsinc,&vmstimer,&vmstimer); 361 sys$setimr(0,&vmstimer,alarming,alarming,0); 362 #endif /* VMS */ 363 } 364 #endif /* SYS_WINNT */ 365 366 367 /* 368 * timer_clr_stats - clear timer module stat counters 369 */ 370 void 371 timer_clr_stats(void) 372 { 373 timer_overflows = 0; 374 timer_xmtcalls = 0; 375 timer_timereset = current_time; 376 } 377 378