Annotation of embedaddon/ntp/ntpd/ntp_util.c, revision 1.1.1.1
1.1 misho 1: /*
2: * ntp_util.c - stuff I didn't have any other place for
3: */
4: #ifdef HAVE_CONFIG_H
5: # include <config.h>
6: #endif
7:
8: #include "ntpd.h"
9: #include "ntp_io.h"
10: #include "ntp_unixtime.h"
11: #include "ntp_filegen.h"
12: #include "ntp_if.h"
13: #include "ntp_stdlib.h"
14: #include "ntp_assert.h"
15:
16: #include <stdio.h>
17: #include <ctype.h>
18: #include <sys/types.h>
19: #ifdef HAVE_SYS_IOCTL_H
20: # include <sys/ioctl.h>
21: #endif
22:
23: #ifdef HAVE_IEEEFP_H
24: # include <ieeefp.h>
25: #endif
26: #ifdef HAVE_MATH_H
27: # include <math.h>
28: #endif
29:
30: #ifdef DOSYNCTODR
31: # if !defined(VMS)
32: # include <sys/resource.h>
33: # endif /* VMS */
34: #endif
35:
36: #if defined(VMS)
37: # include <descrip.h>
38: #endif /* VMS */
39:
40: /*
41: * Defines used by the leapseconds stuff
42: */
43: #define MAX_TAI 100 /* max TAI offset (s) */
44: #define L_DAY 86400UL /* seconds per day */
45: #define L_YEAR (L_DAY * 365) /* days per year */
46: #define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */
47: #define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */
48: #define L_CENT (L_4YEAR * 25) /* days per century */
49:
50: /*
51: * This contains odds and ends, including the hourly stats, various
52: * configuration items, leapseconds stuff, etc.
53: */
54: /*
55: * File names
56: */
57: static char *key_file_name; /* keys file name */
58: char *leapseconds_file_name; /* leapseconds file name */
59: char *stats_drift_file; /* frequency file name */
60: static char *stats_temp_file; /* temp frequency file name */
61: double wander_resid; /* wander threshold */
62: double wander_threshold = 1e-7; /* initial wander threshold */
63: int drift_file_sw; /* clock update switch */
64:
65: /*
66: * Statistics file stuff
67: */
68: #ifndef NTP_VAR
69: # ifndef SYS_WINNT
70: # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */
71: # else
72: # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */
73: # endif /* SYS_WINNT */
74: #endif
75:
76: #ifndef MAXPATHLEN
77: # define MAXPATHLEN 256
78: #endif
79:
80: #ifdef DEBUG_TIMING
81: static FILEGEN timingstats;
82: #endif
83: #ifdef OPENSSL
84: static FILEGEN cryptostats;
85: #endif /* OPENSSL */
86:
87: static char statsdir[MAXPATHLEN] = NTP_VAR;
88: static FILEGEN peerstats;
89: static FILEGEN loopstats;
90: static FILEGEN clockstats;
91: static FILEGEN rawstats;
92: static FILEGEN sysstats;
93: static FILEGEN protostats;
94:
95: /*
96: * This controls whether stats are written to the fileset. Provided
97: * so that ntpdc can turn off stats when the file system fills up.
98: */
99: int stats_control;
100:
101: /*
102: * Initial frequency offset later passed to the loopfilter.
103: */
104: double old_drift = 1e9; /* current frequency */
105: static double prev_drift_comp; /* last frequency update */
106:
107: /*
108: * Static prototypes
109: */
110: static int leap_file(FILE *);
111: static void record_sys_stats(void);
112:
113: /*
114: * Prototypes
115: */
116: #ifdef DEBUG
117: void uninit_util(void);
118: #endif
119:
120:
121: /*
122: * uninit_util - free memory allocated by init_util
123: */
124: #ifdef DEBUG
125: void
126: uninit_util(void)
127: {
128: #if defined(_MSC_VER) && defined (_DEBUG)
129: _CrtCheckMemory();
130: #endif
131: if (stats_drift_file) {
132: free(stats_drift_file);
133: free(stats_temp_file);
134: stats_drift_file = NULL;
135: stats_temp_file = NULL;
136: }
137: if (key_file_name) {
138: free(key_file_name);
139: key_file_name = NULL;
140: }
141: filegen_unregister("peerstats");
142: filegen_unregister("loopstats");
143: filegen_unregister("clockstats");
144: filegen_unregister("rawstats");
145: filegen_unregister("sysstats");
146: filegen_unregister("protostats");
147: #ifdef OPENSSL
148: filegen_unregister("cryptostats");
149: #endif /* OPENSSL */
150: #ifdef DEBUG_TIMING
151: filegen_unregister("timingstats");
152: #endif /* DEBUG_TIMING */
153:
154: #if defined(_MSC_VER) && defined (_DEBUG)
155: _CrtCheckMemory();
156: #endif
157: }
158: #endif /* DEBUG */
159:
160:
161: /*
162: * init_util - initialize the utilities (ntpd included)
163: */
164: void
165: init_util(void)
166: {
167: stats_drift_file = NULL;
168: stats_temp_file = NULL;
169: key_file_name = NULL;
170: filegen_register(statsdir, "peerstats", &peerstats);
171: filegen_register(statsdir, "loopstats", &loopstats);
172: filegen_register(statsdir, "clockstats", &clockstats);
173: filegen_register(statsdir, "rawstats", &rawstats);
174: filegen_register(statsdir, "sysstats", &sysstats);
175: filegen_register(statsdir, "protostats", &protostats);
176: #ifdef OPENSSL
177: filegen_register(statsdir, "cryptostats", &cryptostats);
178: #endif /* OPENSSL */
179: #ifdef DEBUG_TIMING
180: filegen_register(statsdir, "timingstats", &timingstats);
181: #endif /* DEBUG_TIMING */
182: #ifdef DEBUG
183: atexit(uninit_util);
184: #endif /* DEBUG */
185: }
186:
187:
188: /*
189: * hourly_stats - print some interesting stats
190: */
191: void
192: write_stats(void)
193: {
194: FILE *fp;
195: double ftemp;
196: #ifdef DOSYNCTODR
197: struct timeval tv;
198: #if !defined(VMS)
199: int prio_set;
200: #endif
201: #ifdef HAVE_GETCLOCK
202: struct timespec ts;
203: #endif
204: int o_prio;
205:
206: /*
207: * Sometimes having a Sun can be a drag.
208: *
209: * The kernel variable dosynctodr controls whether the system's
210: * soft clock is kept in sync with the battery clock. If it
211: * is zero, then the soft clock is not synced, and the battery
212: * clock is simply left to rot. That means that when the system
213: * reboots, the battery clock (which has probably gone wacky)
214: * sets the soft clock. That means ntpd starts off with a very
215: * confused idea of what time it is. It then takes a large
216: * amount of time to figure out just how wacky the battery clock
217: * has made things drift, etc, etc. The solution is to make the
218: * battery clock sync up to system time. The way to do THAT is
219: * to simply set the time of day to the current time of day, but
220: * as quickly as possible. This may, or may not be a sensible
221: * thing to do.
222: *
223: * CAVEAT: settimeofday() steps the sun clock by about 800 us,
224: * so setting DOSYNCTODR seems a bad idea in the
225: * case of us resolution
226: */
227:
228: #if !defined(VMS)
229: /*
230: * (prr) getpriority returns -1 on error, but -1 is also a valid
231: * return value (!), so instead we have to zero errno before the
232: * call and check it for non-zero afterwards.
233: */
234: errno = 0;
235: prio_set = 0;
236: o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */
237:
238: /*
239: * (prr) if getpriority succeeded, call setpriority to raise
240: * scheduling priority as high as possible. If that succeeds
241: * as well, set the prio_set flag so we remember to reset
242: * priority to its previous value below. Note that on Solaris
243: * 2.6 (and beyond?), both getpriority and setpriority will fail
244: * with ESRCH, because sched_setscheduler (called from main) put
245: * us in the real-time scheduling class which setpriority
246: * doesn't know about. Being in the real-time class is better
247: * than anything setpriority can do, anyhow, so this error is
248: * silently ignored.
249: */
250: if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0))
251: prio_set = 1; /* overdrive */
252: #endif /* VMS */
253: #ifdef HAVE_GETCLOCK
254: (void) getclock(TIMEOFDAY, &ts);
255: tv.tv_sec = ts.tv_sec;
256: tv.tv_usec = ts.tv_nsec / 1000;
257: #else /* not HAVE_GETCLOCK */
258: GETTIMEOFDAY(&tv,(struct timezone *)NULL);
259: #endif /* not HAVE_GETCLOCK */
260: if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0)
261: msyslog(LOG_ERR, "can't sync battery time: %m");
262: #if !defined(VMS)
263: if (prio_set)
264: setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
265: #endif /* VMS */
266: #endif /* DOSYNCTODR */
267: record_sys_stats();
268: ftemp = fabs(prev_drift_comp - drift_comp);
269: prev_drift_comp = drift_comp;
270: if (ftemp > clock_phi)
271: return;
272:
273: if (stats_drift_file != 0 && drift_file_sw) {
274:
275: /*
276: * When the frequency file is written, initialize the
277: * wander threshold to a configured initial value.
278: * Thereafter reduce it by a factor of 0.5. When it
279: * drops below the frequency wander, write the frequency
280: * file. This adapts to the prevailing wander yet
281: * minimizes the file writes.
282: */
283: drift_file_sw = FALSE;
284: wander_resid *= 0.5;
285: #ifdef DEBUG
286: if (debug)
287: printf("write_stats: wander %.6lf thresh %.6lf, freq %.6lf\n",
288: clock_stability * 1e6, wander_resid * 1e6,
289: drift_comp * 1e6);
290: #endif
291: if (sys_leap != LEAP_NOTINSYNC && clock_stability >
292: wander_resid) {
293: wander_resid = wander_threshold;
294: if ((fp = fopen(stats_temp_file, "w")) == NULL)
295: {
296: msyslog(LOG_ERR,
297: "frequency file %s: %m",
298: stats_temp_file);
299: return;
300: }
301: fprintf(fp, "%.3f\n", drift_comp * 1e6);
302: (void)fclose(fp);
303: /* atomic */
304: #ifdef SYS_WINNT
305: if (_unlink(stats_drift_file)) /* rename semantics differ under NT */
306: msyslog(LOG_WARNING,
307: "Unable to remove prior drift file %s, %m",
308: stats_drift_file);
309: #endif /* SYS_WINNT */
310:
311: #ifndef NO_RENAME
312: if (rename(stats_temp_file, stats_drift_file))
313: msyslog(LOG_WARNING,
314: "Unable to rename temp drift file %s to %s, %m",
315: stats_temp_file, stats_drift_file);
316: #else
317: /* we have no rename NFS of ftp in use */
318: if ((fp = fopen(stats_drift_file, "w")) ==
319: NULL) {
320: msyslog(LOG_ERR,
321: "frequency file %s: %m",
322: stats_drift_file);
323: return;
324: }
325: #endif
326:
327: #if defined(VMS)
328: /* PURGE */
329: {
330: $DESCRIPTOR(oldvers,";-1");
331: struct dsc$descriptor driftdsc = {
332: strlen(stats_drift_file), 0, 0,
333: stats_drift_file };
334: while(lib$delete_file(&oldvers,
335: &driftdsc) & 1);
336: }
337: #endif
338: } else {
339: /* XXX: Log a message at INFO level */
340: }
341: }
342: }
343:
344:
345: /*
346: * stats_config - configure the stats operation
347: */
348: void
349: stats_config(
350: int item,
351: const char *invalue /* only one type so far */
352: )
353: {
354: FILE *fp;
355: const char *value;
356: int len;
357: char tbuf[80];
358: char str1[20], str2[20];
359: #ifndef VMS
360: const char temp_ext[] = ".TEMP";
361: #else
362: const char temp_ext[] = "-TEMP";
363: #endif
364:
365: /*
366: * Expand environment strings under Windows NT, since the
367: * command interpreter doesn't do this, the program must.
368: */
369: #ifdef SYS_WINNT
370: char newvalue[MAX_PATH], parameter[MAX_PATH];
371:
372: if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
373: switch(item) {
374: case STATS_FREQ_FILE:
375: strcpy(parameter,"STATS_FREQ_FILE");
376: break;
377:
378: case STATS_LEAP_FILE:
379: strcpy(parameter,"STATS_LEAP_FILE");
380: break;
381:
382: case STATS_STATSDIR:
383: strcpy(parameter,"STATS_STATSDIR");
384: break;
385:
386: case STATS_PID_FILE:
387: strcpy(parameter,"STATS_PID_FILE");
388: break;
389:
390: default:
391: strcpy(parameter,"UNKNOWN");
392: break;
393: }
394: value = invalue;
395: msyslog(LOG_ERR,
396: "ExpandEnvironmentStrings(%s) failed: %m\n",
397: parameter);
398: } else {
399: value = newvalue;
400: }
401: #else
402: value = invalue;
403: #endif /* SYS_WINNT */
404:
405: switch(item) {
406:
407: /*
408: * Open and read frequency file.
409: */
410: case STATS_FREQ_FILE:
411: if (!value || (len = strlen(value)) == 0)
412: break;
413:
414: stats_drift_file = erealloc(stats_drift_file, len + 1);
415: stats_temp_file = erealloc(stats_temp_file,
416: len + sizeof(".TEMP"));
417:
418: memcpy(stats_drift_file, value, (unsigned)(len+1));
419: memcpy(stats_temp_file, value, (unsigned)len);
420: memcpy(stats_temp_file + len, temp_ext,
421: sizeof(temp_ext));
422:
423: /*
424: * Open drift file and read frequency. If the file is
425: * missing or contains errors, tell the loop to reset.
426: */
427: if ((fp = fopen(stats_drift_file, "r")) == NULL)
428: break;
429:
430: if (fscanf(fp, "%lf", &old_drift) != 1) {
431: msyslog(LOG_ERR,
432: "format error frequency file %s",
433: stats_drift_file);
434: fclose(fp);
435: break;
436:
437: }
438: fclose(fp);
439: old_drift /= 1e6;
440: prev_drift_comp = old_drift;
441: break;
442:
443: /*
444: * Specify statistics directory.
445: */
446: case STATS_STATSDIR:
447:
448: /*
449: * HMS: the following test is insufficient:
450: * - value may be missing the DIR_SEP
451: * - we still need the filename after it
452: */
453: if (strlen(value) >= sizeof(statsdir)) {
454: msyslog(LOG_ERR,
455: "statsdir too long (>%d, sigh)",
456: (int)sizeof(statsdir) - 1);
457: } else {
458: l_fp now;
459: int add_dir_sep;
460: int value_l = strlen(value);
461:
462: /* Add a DIR_SEP unless we already have one. */
463: if (value_l == 0)
464: add_dir_sep = 0;
465: else
466: add_dir_sep = (DIR_SEP !=
467: value[value_l - 1]);
468:
469: if (add_dir_sep)
470: snprintf(statsdir, sizeof(statsdir),
471: "%s%c", value, DIR_SEP);
472: else
473: snprintf(statsdir, sizeof(statsdir),
474: "%s", value);
475:
476: get_systime(&now);
477: if(peerstats.prefix == &statsdir[0] &&
478: peerstats.fp != NULL) {
479: fclose(peerstats.fp);
480: peerstats.fp = NULL;
481: filegen_setup(&peerstats, now.l_ui);
482: }
483: if(loopstats.prefix == &statsdir[0] &&
484: loopstats.fp != NULL) {
485: fclose(loopstats.fp);
486: loopstats.fp = NULL;
487: filegen_setup(&loopstats, now.l_ui);
488: }
489: if(clockstats.prefix == &statsdir[0] &&
490: clockstats.fp != NULL) {
491: fclose(clockstats.fp);
492: clockstats.fp = NULL;
493: filegen_setup(&clockstats, now.l_ui);
494: }
495: if(rawstats.prefix == &statsdir[0] &&
496: rawstats.fp != NULL) {
497: fclose(rawstats.fp);
498: rawstats.fp = NULL;
499: filegen_setup(&rawstats, now.l_ui);
500: }
501: if(sysstats.prefix == &statsdir[0] &&
502: sysstats.fp != NULL) {
503: fclose(sysstats.fp);
504: sysstats.fp = NULL;
505: filegen_setup(&sysstats, now.l_ui);
506: }
507: if(protostats.prefix == &statsdir[0] &&
508: protostats.fp != NULL) {
509: fclose(protostats.fp);
510: protostats.fp = NULL;
511: filegen_setup(&protostats, now.l_ui);
512: }
513: #ifdef OPENSSL
514: if(cryptostats.prefix == &statsdir[0] &&
515: cryptostats.fp != NULL) {
516: fclose(cryptostats.fp);
517: cryptostats.fp = NULL;
518: filegen_setup(&cryptostats, now.l_ui);
519: }
520: #endif /* OPENSSL */
521: #ifdef DEBUG_TIMING
522: if(timingstats.prefix == &statsdir[0] &&
523: timingstats.fp != NULL) {
524: fclose(timingstats.fp);
525: timingstats.fp = NULL;
526: filegen_setup(&timingstats, now.l_ui);
527: }
528: #endif /* DEBUG_TIMING */
529: }
530: break;
531:
532: /*
533: * Open pid file.
534: */
535: case STATS_PID_FILE:
536: if ((fp = fopen(value, "w")) == NULL) {
537: msyslog(LOG_ERR, "pid file %s: %m",
538: value);
539: break;
540: }
541: fprintf(fp, "%d", (int)getpid());
542: fclose(fp);;
543: break;
544:
545: /*
546: * Read leapseconds file.
547: */
548: case STATS_LEAP_FILE:
549: if ((fp = fopen(value, "r")) == NULL) {
550: msyslog(LOG_ERR, "leapseconds file %s: %m",
551: value);
552: break;
553: }
554:
555: if (leap_file(fp) < 0) {
556: msyslog(LOG_ERR,
557: "format error leapseconds file %s",
558: value);
559: } else {
560: strcpy(str1, fstostr(leap_sec));
561: strcpy(str2, fstostr(leap_expire));
562: snprintf(tbuf, sizeof(tbuf),
563: "%d leap %s expire %s", leap_tai, str1,
564: str2);
565: report_event(EVNT_TAI, NULL, tbuf);
566: }
567: fclose(fp);
568: break;
569:
570: default:
571: /* oh well */
572: break;
573: }
574: }
575:
576:
577: /*
578: * record_peer_stats - write peer statistics to file
579: *
580: * file format:
581: * day (MJD)
582: * time (s past UTC midnight)
583: * IP address
584: * status word (hex)
585: * offset
586: * delay
587: * dispersion
588: * jitter
589: */
590: void
591: record_peer_stats(
592: sockaddr_u *addr,
593: int status,
594: double offset, /* offset */
595: double delay, /* delay */
596: double dispersion, /* dispersion */
597: double jitter /* jitter */
598: )
599: {
600: l_fp now;
601: u_long day;
602:
603: if (!stats_control)
604: return;
605:
606: get_systime(&now);
607: filegen_setup(&peerstats, now.l_ui);
608: day = now.l_ui / 86400 + MJD_1900;
609: now.l_ui %= 86400;
610: if (peerstats.fp != NULL) {
611: fprintf(peerstats.fp,
612: "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day,
613: ulfptoa(&now, 3), stoa(addr), status, offset,
614: delay, dispersion, jitter);
615: fflush(peerstats.fp);
616: }
617: }
618:
619:
620: /*
621: * record_loop_stats - write loop filter statistics to file
622: *
623: * file format:
624: * day (MJD)
625: * time (s past midnight)
626: * offset
627: * frequency (PPM)
628: * jitter
629: * wnder (PPM)
630: * time constant (log2)
631: */
632: void
633: record_loop_stats(
634: double offset, /* offset */
635: double freq, /* frequency (PPM) */
636: double jitter, /* jitter */
637: double wander, /* wander (PPM) */
638: int spoll
639: )
640: {
641: l_fp now;
642: u_long day;
643:
644: if (!stats_control)
645: return;
646:
647: get_systime(&now);
648: filegen_setup(&loopstats, now.l_ui);
649: day = now.l_ui / 86400 + MJD_1900;
650: now.l_ui %= 86400;
651: if (loopstats.fp != NULL) {
652: fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n",
653: day, ulfptoa(&now, 3), offset, freq * 1e6, jitter,
654: wander * 1e6, spoll);
655: fflush(loopstats.fp);
656: }
657: }
658:
659:
660: /*
661: * record_clock_stats - write clock statistics to file
662: *
663: * file format:
664: * day (MJD)
665: * time (s past midnight)
666: * IP address
667: * text message
668: */
669: void
670: record_clock_stats(
671: sockaddr_u *addr,
672: const char *text /* timecode string */
673: )
674: {
675: l_fp now;
676: u_long day;
677:
678: if (!stats_control)
679: return;
680:
681: get_systime(&now);
682: filegen_setup(&clockstats, now.l_ui);
683: day = now.l_ui / 86400 + MJD_1900;
684: now.l_ui %= 86400;
685: if (clockstats.fp != NULL) {
686: fprintf(clockstats.fp, "%lu %s %s %s\n", day,
687: ulfptoa(&now, 3), stoa(addr), text);
688: fflush(clockstats.fp);
689: }
690: }
691:
692:
693: /*
694: * record_raw_stats - write raw timestamps to file
695: *
696: * file format
697: * day (MJD)
698: * time (s past midnight)
699: * peer ip address
700: * IP address
701: * t1 t2 t3 t4 timestamps
702: */
703: void
704: record_raw_stats(
705: sockaddr_u *srcadr,
706: sockaddr_u *dstadr,
707: l_fp *t1, /* originate timestamp */
708: l_fp *t2, /* receive timestamp */
709: l_fp *t3, /* transmit timestamp */
710: l_fp *t4 /* destination timestamp */
711: )
712: {
713: l_fp now;
714: u_long day;
715:
716: if (!stats_control)
717: return;
718:
719: get_systime(&now);
720: filegen_setup(&rawstats, now.l_ui);
721: day = now.l_ui / 86400 + MJD_1900;
722: now.l_ui %= 86400;
723: if (rawstats.fp != NULL) {
724: fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n", day,
725: ulfptoa(&now, 3), stoa(srcadr), dstadr ?
726: stoa(dstadr) : "-", ulfptoa(t1, 9), ulfptoa(t2, 9),
727: ulfptoa(t3, 9), ulfptoa(t4, 9));
728: fflush(rawstats.fp);
729: }
730: }
731:
732:
733: /*
734: * record_sys_stats - write system statistics to file
735: *
736: * file format
737: * day (MJD)
738: * time (s past midnight)
739: * time since reset
740: * packets recieved
741: * packets for this host
742: * current version
743: * old version
744: * access denied
745: * bad length or format
746: * bad authentication
747: * declined
748: * rate exceeded
749: * KoD sent
750: */
751: void
752: record_sys_stats(void)
753: {
754: l_fp now;
755: u_long day;
756:
757: if (!stats_control)
758: return;
759:
760: get_systime(&now);
761: filegen_setup(&sysstats, now.l_ui);
762: day = now.l_ui / 86400 + MJD_1900;
763: now.l_ui %= 86400;
764: if (sysstats.fp != NULL) {
765: fprintf(sysstats.fp,
766: "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
767: day, ulfptoa(&now, 3), current_time - sys_stattime,
768: sys_received, sys_processed, sys_newversion,
769: sys_oldversion, sys_restricted, sys_badlength,
770: sys_badauth, sys_declined, sys_limitrejected,
771: sys_kodsent);
772: fflush(sysstats.fp);
773: proto_clr_stats();
774: }
775: }
776:
777:
778: /*
779: * record_proto_stats - write system statistics to file
780: *
781: * file format
782: * day (MJD)
783: * time (s past midnight)
784: * text message
785: */
786: void
787: record_proto_stats(
788: char *str /* text string */
789: )
790: {
791: l_fp now;
792: u_long day;
793:
794: if (!stats_control)
795: return;
796:
797: get_systime(&now);
798: filegen_setup(&protostats, now.l_ui);
799: day = now.l_ui / 86400 + MJD_1900;
800: now.l_ui %= 86400;
801: if (protostats.fp != NULL) {
802: fprintf(protostats.fp, "%lu %s %s\n", day,
803: ulfptoa(&now, 3), str);
804: fflush(protostats.fp);
805: }
806: }
807:
808:
809: #ifdef OPENSSL
810: /*
811: * record_crypto_stats - write crypto statistics to file
812: *
813: * file format:
814: * day (mjd)
815: * time (s past midnight)
816: * peer ip address
817: * text message
818: */
819: void
820: record_crypto_stats(
821: sockaddr_u *addr,
822: const char *text /* text message */
823: )
824: {
825: l_fp now;
826: u_long day;
827:
828: if (!stats_control)
829: return;
830:
831: get_systime(&now);
832: filegen_setup(&cryptostats, now.l_ui);
833: day = now.l_ui / 86400 + MJD_1900;
834: now.l_ui %= 86400;
835: if (cryptostats.fp != NULL) {
836: if (addr == NULL)
837: fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n",
838: day, ulfptoa(&now, 3), text);
839: else
840: fprintf(cryptostats.fp, "%lu %s %s %s\n",
841: day, ulfptoa(&now, 3), stoa(addr), text);
842: fflush(cryptostats.fp);
843: }
844: }
845: #endif /* OPENSSL */
846:
847:
848: #ifdef DEBUG_TIMING
849: /*
850: * record_timing_stats - write timing statistics to file
851: *
852: * file format:
853: * day (mjd)
854: * time (s past midnight)
855: * text message
856: */
857: void
858: record_timing_stats(
859: const char *text /* text message */
860: )
861: {
862: static unsigned int flshcnt;
863: l_fp now;
864: u_long day;
865:
866: if (!stats_control)
867: return;
868:
869: get_systime(&now);
870: filegen_setup(&timingstats, now.l_ui);
871: day = now.l_ui / 86400 + MJD_1900;
872: now.l_ui %= 86400;
873: if (timingstats.fp != NULL) {
874: fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now,
875: 3), text);
876: if (++flshcnt % 100 == 0)
877: fflush(timingstats.fp);
878: }
879: }
880: #endif
881:
882:
883: /*
884: * leap_file - read leapseconds file
885: *
886: * Read the ERTS leapsecond file in NIST text format and extract the
887: * NTP seconds of the latest leap and TAI offset after the leap.
888: */
889: static int
890: leap_file(
891: FILE *fp /* file handle */
892: )
893: {
894: char buf[NTP_MAXSTRLEN]; /* file line buffer */
895: u_long leap; /* NTP time at leap */
896: u_long expire; /* NTP time when file expires */
897: int offset; /* TAI offset at leap (s) */
898: int i;
899:
900: /*
901: * Read and parse the leapseconds file. Empty lines and comments
902: * are ignored. A line beginning with #@ contains the file
903: * expiration time in NTP seconds. Other lines begin with two
904: * integers followed by junk or comments. The first integer is
905: * the NTP seconds at the leap, the second is the TAI offset
906: * after the leap.
907: */
908: offset = 0;
909: leap = 0;
910: expire = 0;
911: i = 10;
912: while (fgets(buf, NTP_MAXSTRLEN - 1, fp) != NULL) {
913: if (strlen(buf) < 1)
914: continue;
915:
916: if (buf[0] == '#') {
917: if (strlen(buf) < 3)
918: continue;
919:
920: /*
921: * Note the '@' flag was used only in the 2006
922: * table; previious to that the flag was '$'.
923: */
924: if (buf[1] == '@' || buf[1] == '$') {
925: if (sscanf(&buf[2], "%lu", &expire) !=
926: 1)
927: return (-1);
928:
929: continue;
930: }
931: }
932: if (sscanf(buf, "%lu %d", &leap, &offset) == 2) {
933:
934: /*
935: * Valid offsets must increase by one for each
936: * leap.
937: */
938: if (i++ != offset)
939: return (-1);
940: }
941: }
942:
943: /*
944: * There must be at least one leap.
945: */
946: if (i == 10)
947: return (-1);
948:
949: leap_tai = offset;
950: leap_sec = leap;
951: leap_expire = expire;
952: return (0);
953: }
954:
955:
956: /*
957: * leap_month - returns seconds until the end of the month.
958: */
959: u_long
960: leap_month(
961: u_long sec /* current NTP second */
962: )
963: {
964: u_long ltemp;
965: u_long *ptr;
966: u_long year[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,
967: 31};
968: u_long lyear[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30,
969: 31};
970:
971: /*
972: * Find current leap cycle.
973: */
974: ltemp = sec;
975: while (ltemp >= L_CENT)
976: ltemp -= L_CENT;
977: while (ltemp >= L_4YEAR)
978: ltemp -= L_4YEAR;
979:
980: /*
981: * We are within four years of the target. If in leap year, use
982: * leap year month table; otherwise, use year month table.
983: */
984: if (ltemp < L_LYEAR) {
985: ptr = lyear;
986: } else {
987: ptr = year;
988: ltemp -= L_LYEAR;
989: while (ltemp >= L_YEAR)
990: ltemp -= L_YEAR;
991: }
992:
993: /*
994: * We are within one year of the target. Find the month of the
995: * leap.
996: */
997: while (ltemp >= *ptr * L_DAY)
998: ltemp -= *ptr++ * L_DAY;
999:
1000: /*
1001: * The result is the number of seconds until the end of the
1002: * month when the leap is to occur.
1003: */
1004: return (*ptr * L_DAY - ltemp - L_DAY);
1005: }
1006:
1007:
1008: /*
1009: * getauthkeys - read the authentication keys from the specified file
1010: */
1011: void
1012: getauthkeys(
1013: const char *keyfile
1014: )
1015: {
1016: int len;
1017:
1018: len = strlen(keyfile);
1019: if (!len)
1020: return;
1021:
1022: #ifndef SYS_WINNT
1023: key_file_name = erealloc(key_file_name, len + 1);
1024: memmove(key_file_name, keyfile, len + 1);
1025: #else
1026: key_file_name = erealloc(key_file_name, _MAX_PATH);
1027: if (len + 1 > _MAX_PATH)
1028: return;
1029: if (!ExpandEnvironmentStrings(keyfile, key_file_name,
1030: _MAX_PATH)) {
1031: msyslog(LOG_ERR,
1032: "ExpandEnvironmentStrings(KEY_FILE) failed: %m");
1033: strncpy(key_file_name, keyfile, _MAX_PATH);
1034: }
1035: #endif /* SYS_WINNT */
1036:
1037: authreadkeys(key_file_name);
1038: }
1039:
1040:
1041: /*
1042: * rereadkeys - read the authentication key file over again.
1043: */
1044: void
1045: rereadkeys(void)
1046: {
1047: if (NULL != key_file_name)
1048: authreadkeys(key_file_name);
1049: }
1050:
1051:
1052: /*
1053: * sock_hash - hash a sockaddr_u structure
1054: */
1055: u_short
1056: sock_hash(
1057: sockaddr_u *addr
1058: )
1059: {
1060: u_int hashVal;
1061: u_int j;
1062: size_t len;
1063: u_char *pch;
1064: hashVal = 0;
1065: len = 0;
1066:
1067: /*
1068: * We can't just hash the whole thing because there are hidden
1069: * fields in sockaddr_in6 that might be filled in by recvfrom(),
1070: * so just use the family, port and address.
1071: */
1072: pch = (u_char *)&AF(addr);
1073: hashVal = 37 * hashVal + *pch;
1074: if (sizeof(AF(addr)) > 1) {
1075: pch++;
1076: hashVal = 37 * hashVal + *pch;
1077: }
1078: switch(AF(addr)) {
1079: case AF_INET:
1080: pch = (u_char *)&SOCK_ADDR4(addr);
1081: len = sizeof(SOCK_ADDR4(addr));
1082: break;
1083:
1084: case AF_INET6:
1085: pch = (u_char *)&SOCK_ADDR6(addr);
1086: len = sizeof(SOCK_ADDR6(addr));
1087: break;
1088: }
1089:
1090: for (j = 0; j < len ; j++)
1091: hashVal = 37 * hashVal + pch[j];
1092:
1093: hashVal = hashVal & NTP_HASH_MASK;
1094:
1095: return (u_short)hashVal;
1096: }
1097:
1098:
1099: #if notyet
1100: /*
1101: * ntp_exit - document explicitly that ntpd has exited
1102: */
1103: void
1104: ntp_exit(int retval)
1105: {
1106: msyslog(LOG_ERR, "EXITING with return code %d", retval);
1107: exit(retval);
1108: }
1109: #endif
1110:
1111: /*
1112: * fstostr - prettyprint NTP seconds
1113: */
1114: char * fstostr(
1115: time_t ntp_stamp
1116: )
1117: {
1118: static char str[20];
1119: struct tm * tm;
1120: time_t unix_stamp;
1121:
1122: unix_stamp = ntp_stamp - JAN_1970;
1123: tm = gmtime(&unix_stamp);
1124: if (NULL != tm)
1125: snprintf(str, sizeof(str),
1126: "%04d%02d%02d%02d%02d",
1127: tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1128: tm->tm_hour, tm->tm_min);
1129: else
1130: strcpy(str, "gmtime() error");
1131:
1132: return str;
1133: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>