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