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