/contrib/ntp/ntpd/ntp_timer.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 407 lines · 283 code · 42 blank · 82 comment · 60 complexity · 11a832ddbdc6c696ad9a46d0f21b0a01 MD5 · raw file

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