154359Sroberto/*
254359Sroberto * ntp_util.c - stuff I didn't have any other place for
354359Sroberto */
482498Sroberto
554359Sroberto#ifdef HAVE_CONFIG_H
682498Sroberto# include <config.h>
754359Sroberto#endif
854359Sroberto
954359Sroberto#include "ntpd.h"
1054359Sroberto#include "ntp_io.h"
1154359Sroberto#include "ntp_unixtime.h"
1254359Sroberto#include "ntp_filegen.h"
1354359Sroberto#include "ntp_if.h"
1454359Sroberto#include "ntp_stdlib.h"
1554359Sroberto
1682498Sroberto#include <stdio.h>
1782498Sroberto#include <ctype.h>
1882498Sroberto#include <sys/types.h>
1982498Sroberto#ifdef HAVE_SYS_IOCTL_H
2082498Sroberto# include <sys/ioctl.h>
2182498Sroberto#endif
2282498Sroberto
2382498Sroberto#ifdef HAVE_IEEEFP_H
2482498Sroberto# include <ieeefp.h>
2582498Sroberto#endif
2682498Sroberto#ifdef HAVE_MATH_H
2782498Sroberto# include <math.h>
2882498Sroberto#endif
2982498Sroberto
3054359Sroberto#ifdef  DOSYNCTODR
31182007Sroberto# if !defined(VMS)
32182007Sroberto#  include <sys/resource.h>
33182007Sroberto# endif /* VMS */
3454359Sroberto#endif
3554359Sroberto
3654359Sroberto#if defined(VMS)
37182007Sroberto# include <descrip.h>
3854359Sroberto#endif /* VMS */
3954359Sroberto
4054359Sroberto/*
4154359Sroberto * This contains odds and ends.  Right now the only thing you'll find
42132451Sroberto * in here is the hourly stats printer and some code to support
43132451Sroberto * rereading the keys file, but I may eventually put other things in
44132451Sroberto * here such as code to do something with the leap bits.
4554359Sroberto */
4654359Sroberto/*
4754359Sroberto * Name of the keys file
4854359Sroberto */
4954359Srobertostatic	char *key_file_name;
5054359Sroberto
5154359Sroberto/*
5254359Sroberto * The name of the drift_comp file and the temporary.
5354359Sroberto */
5454359Srobertostatic	char *stats_drift_file;
5554359Srobertostatic	char *stats_temp_file;
56182007Srobertoint stats_write_period = 3600;	/* # of seconds between writes. */
57182007Srobertodouble stats_write_tolerance = 0;
58182007Srobertostatic double prev_drift_comp = 99999.;
5954359Sroberto
6054359Sroberto/*
6154359Sroberto * Statistics file stuff
6254359Sroberto */
6354359Sroberto#ifndef NTP_VAR
64182007Sroberto# ifndef SYS_WINNT
65182007Sroberto#  define NTP_VAR "/var/NTP/"		/* NOTE the trailing '/' */
66182007Sroberto# else
67182007Sroberto#  define NTP_VAR "c:\\var\\ntp\\"		/* NOTE the trailing '\\' */
68182007Sroberto# endif /* SYS_WINNT */
6954359Sroberto#endif
7054359Sroberto
7154359Sroberto#ifndef MAXPATHLEN
72182007Sroberto# define MAXPATHLEN 256
7354359Sroberto#endif
7454359Sroberto
7554359Srobertostatic	char statsdir[MAXPATHLEN] = NTP_VAR;
7654359Sroberto
7754359Srobertostatic FILEGEN peerstats;
7854359Srobertostatic FILEGEN loopstats;
7954359Srobertostatic FILEGEN clockstats;
8054359Srobertostatic FILEGEN rawstats;
81132451Srobertostatic FILEGEN sysstats;
82182007Sroberto#ifdef DEBUG_TIMING
83182007Srobertostatic FILEGEN timingstats;
84182007Sroberto#endif
85132451Sroberto#ifdef OPENSSL
86132451Srobertostatic FILEGEN cryptostats;
87132451Sroberto#endif /* OPENSSL */
8854359Sroberto
8954359Sroberto/*
9054359Sroberto * This controls whether stats are written to the fileset. Provided
9154359Sroberto * so that ntpdc can turn off stats when the file system fills up.
9254359Sroberto */
9354359Srobertoint stats_control;
9454359Sroberto
9554359Sroberto/*
96182007Sroberto * Initial frequency offset later passed to the loopfilter.
97182007Sroberto */
98182007Srobertodouble	old_drift;
99182007Sroberto
100182007Sroberto/*
10154359Sroberto * init_util - initialize the utilities
10254359Sroberto */
10354359Srobertovoid
10454359Srobertoinit_util(void)
10554359Sroberto{
10654359Sroberto	stats_drift_file = 0;
10754359Sroberto	stats_temp_file = 0;
10854359Sroberto	key_file_name = 0;
10954359Sroberto
110182007Sroberto	filegen_register(&statsdir[0], "peerstats", &peerstats);
111132451Sroberto
112182007Sroberto	filegen_register(&statsdir[0], "loopstats", &loopstats);
11354359Sroberto
114182007Sroberto	filegen_register(&statsdir[0], "clockstats", &clockstats);
11554359Sroberto
116182007Sroberto	filegen_register(&statsdir[0], "rawstats", &rawstats);
11754359Sroberto
118182007Sroberto	filegen_register(&statsdir[0], "sysstats", &sysstats);
119132451Sroberto
120132451Sroberto#ifdef OPENSSL
121182007Sroberto	filegen_register(&statsdir[0], "cryptostats", &cryptostats);
122132451Sroberto#endif /* OPENSSL */
123132451Sroberto
124182007Sroberto#ifdef DEBUG_TIMING
125182007Sroberto	filegen_register(&statsdir[0], "timingstats", &timingstats);
126182007Sroberto#endif
12754359Sroberto}
12854359Sroberto
12954359Sroberto
13054359Sroberto/*
13154359Sroberto * hourly_stats - print some interesting stats
13254359Sroberto */
13354359Srobertovoid
134182007Srobertowrite_stats(void)
13554359Sroberto{
13654359Sroberto	FILE *fp;
13754359Sroberto
13854359Sroberto#ifdef DOSYNCTODR
13954359Sroberto	struct timeval tv;
14054359Sroberto#if !defined(VMS)
14154359Sroberto	int prio_set;
14254359Sroberto#endif
14354359Sroberto#ifdef HAVE_GETCLOCK
14454359Sroberto        struct timespec ts;
14554359Sroberto#endif
14654359Sroberto	int o_prio;
14754359Sroberto
14854359Sroberto	/*
14954359Sroberto	 * Sometimes having a Sun can be a drag.
15054359Sroberto	 *
15154359Sroberto	 * The kernel variable dosynctodr controls whether the system's
15254359Sroberto	 * soft clock is kept in sync with the battery clock. If it
15354359Sroberto	 * is zero, then the soft clock is not synced, and the battery
15454359Sroberto	 * clock is simply left to rot. That means that when the system
15554359Sroberto	 * reboots, the battery clock (which has probably gone wacky)
15654359Sroberto	 * sets the soft clock. That means ntpd starts off with a very
15754359Sroberto	 * confused idea of what time it is. It then takes a large
15854359Sroberto	 * amount of time to figure out just how wacky the battery clock
15954359Sroberto	 * has made things drift, etc, etc. The solution is to make the
16054359Sroberto	 * battery clock sync up to system time. The way to do THAT is
16154359Sroberto	 * to simply set the time of day to the current time of day, but
16254359Sroberto	 * as quickly as possible. This may, or may not be a sensible
16354359Sroberto	 * thing to do.
16454359Sroberto	 *
16554359Sroberto	 * CAVEAT: settimeofday() steps the sun clock by about 800 us,
16654359Sroberto	 *         so setting DOSYNCTODR seems a bad idea in the
16754359Sroberto	 *         case of us resolution
16854359Sroberto	 */
16954359Sroberto
17054359Sroberto#if !defined(VMS)
17154359Sroberto	/* (prr) getpriority returns -1 on error, but -1 is also a valid
172132451Sroberto	 * return value (!), so instead we have to zero errno before the
173132451Sroberto	 * call and check it for non-zero afterwards.
17454359Sroberto	 */
17554359Sroberto	errno = 0;
17654359Sroberto	prio_set = 0;
17754359Sroberto	o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */
17854359Sroberto
179132451Sroberto	/*
180132451Sroberto	 * (prr) if getpriority succeeded, call setpriority to raise
18154359Sroberto	 * scheduling priority as high as possible.  If that succeeds
18254359Sroberto	 * as well, set the prio_set flag so we remember to reset
183132451Sroberto	 * priority to its previous value below.  Note that on Solaris
184132451Sroberto	 * 2.6 (and beyond?), both getpriority and setpriority will fail
185132451Sroberto	 * with ESRCH, because sched_setscheduler (called from main) put
186132451Sroberto	 * us in the real-time scheduling class which setpriority
187132451Sroberto	 * doesn't know about. Being in the real-time class is better
188132451Sroberto	 * than anything setpriority can do, anyhow, so this error is
189132451Sroberto	 * silently ignored.
19054359Sroberto	 */
19154359Sroberto	if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0))
192132451Sroberto		prio_set = 1;	/* overdrive */
19354359Sroberto#endif /* VMS */
19454359Sroberto#ifdef HAVE_GETCLOCK
19554359Sroberto        (void) getclock(TIMEOFDAY, &ts);
19654359Sroberto        tv.tv_sec = ts.tv_sec;
19754359Sroberto        tv.tv_usec = ts.tv_nsec / 1000;
19854359Sroberto#else /*  not HAVE_GETCLOCK */
19954359Sroberto	GETTIMEOFDAY(&tv,(struct timezone *)NULL);
20054359Sroberto#endif /* not HAVE_GETCLOCK */
201132451Sroberto	if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) {
20254359Sroberto		msyslog(LOG_ERR, "can't sync battery time: %m");
20354359Sroberto	}
20454359Sroberto#if !defined(VMS)
20554359Sroberto	if (prio_set)
206132451Sroberto		setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
20754359Sroberto#endif /* VMS */
20854359Sroberto#endif /* DOSYNCTODR */
20954359Sroberto
21054359Sroberto	NLOG(NLOG_SYSSTATIST)
21154359Sroberto		msyslog(LOG_INFO,
21254359Sroberto		    "offset %.6f sec freq %.3f ppm error %.6f poll %d",
213132451Sroberto		    last_offset, drift_comp * 1e6, sys_jitter,
214132451Sroberto		    sys_poll);
21582498Sroberto
21654359Sroberto
217132451Sroberto	record_sys_stats();
218182007Sroberto	if ((u_long)(fabs(prev_drift_comp - drift_comp) * 1e9) <=
219182007Sroberto	    (u_long)(fabs(stats_write_tolerance * drift_comp) * 1e9)) {
220182007Sroberto	     return;
221182007Sroberto	}
222182007Sroberto	prev_drift_comp = drift_comp;
22354359Sroberto	if (stats_drift_file != 0) {
22454359Sroberto		if ((fp = fopen(stats_temp_file, "w")) == NULL) {
22554359Sroberto			msyslog(LOG_ERR, "can't open %s: %m",
22654359Sroberto			    stats_temp_file);
22754359Sroberto			return;
22854359Sroberto		}
22954359Sroberto		fprintf(fp, "%.3f\n", drift_comp * 1e6);
23054359Sroberto		(void)fclose(fp);
23154359Sroberto		/* atomic */
23254359Sroberto#ifdef SYS_WINNT
233132451Sroberto		(void) _unlink(stats_drift_file); /* rename semantics differ under NT */
23454359Sroberto#endif /* SYS_WINNT */
23554359Sroberto
23654359Sroberto#ifndef NO_RENAME
23754359Sroberto		(void) rename(stats_temp_file, stats_drift_file);
23854359Sroberto#else
239182007Sroberto		/* we have no rename NFS of ftp in use */
24054359Sroberto		if ((fp = fopen(stats_drift_file, "w")) == NULL) {
24154359Sroberto			msyslog(LOG_ERR, "can't open %s: %m",
24254359Sroberto			    stats_drift_file);
24354359Sroberto			return;
24454359Sroberto		}
24554359Sroberto
24654359Sroberto#endif
24754359Sroberto
24854359Sroberto#if defined(VMS)
24954359Sroberto		/* PURGE */
25054359Sroberto		{
25154359Sroberto			$DESCRIPTOR(oldvers,";-1");
25254359Sroberto			struct dsc$descriptor driftdsc = {
25354359Sroberto				strlen(stats_drift_file),0,0,stats_drift_file };
25454359Sroberto
25554359Sroberto			while(lib$delete_file(&oldvers,&driftdsc) & 1) ;
25654359Sroberto		}
25754359Sroberto#endif
25854359Sroberto	}
25954359Sroberto}
26054359Sroberto
26154359Sroberto
26254359Sroberto/*
26354359Sroberto * stats_config - configure the stats operation
26454359Sroberto */
26554359Srobertovoid
26654359Srobertostats_config(
26754359Sroberto	int item,
268182007Sroberto	const char *invalue	/* only one type so far */
26954359Sroberto	)
27054359Sroberto{
27154359Sroberto	FILE *fp;
272182007Sroberto	const char *value;
27354359Sroberto	int len;
27454359Sroberto
275132451Sroberto	/*
276132451Sroberto	 * Expand environment strings under Windows NT, since the
277132451Sroberto	 * command interpreter doesn't do this, the program must.
27854359Sroberto	 */
27954359Sroberto#ifdef SYS_WINNT
28054359Sroberto	char newvalue[MAX_PATH], parameter[MAX_PATH];
28154359Sroberto
282132451Sroberto	if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
28354359Sroberto 		switch(item) {
28454359Sroberto		    case STATS_FREQ_FILE:
28554359Sroberto			strcpy(parameter,"STATS_FREQ_FILE");
28654359Sroberto			break;
28754359Sroberto		    case STATS_STATSDIR:
28854359Sroberto			strcpy(parameter,"STATS_STATSDIR");
28954359Sroberto			break;
29054359Sroberto		    case STATS_PID_FILE:
29154359Sroberto			strcpy(parameter,"STATS_PID_FILE");
29254359Sroberto			break;
29354359Sroberto		    default:
29454359Sroberto			strcpy(parameter,"UNKNOWN");
29554359Sroberto			break;
29654359Sroberto		}
29754359Sroberto		value = invalue;
29854359Sroberto
29954359Sroberto		msyslog(LOG_ERR,
30054359Sroberto		    "ExpandEnvironmentStrings(%s) failed: %m\n", parameter);
301132451Sroberto	} else {
302132451Sroberto		value = newvalue;
30354359Sroberto	}
30454359Sroberto#else
30554359Sroberto	value = invalue;
30654359Sroberto#endif /* SYS_WINNT */
30754359Sroberto
30854359Sroberto	switch(item) {
30954359Sroberto	    case STATS_FREQ_FILE:
31054359Sroberto		if (stats_drift_file != 0) {
31154359Sroberto			(void) free(stats_drift_file);
31254359Sroberto			(void) free(stats_temp_file);
31354359Sroberto			stats_drift_file = 0;
31454359Sroberto			stats_temp_file = 0;
31554359Sroberto		}
31654359Sroberto
31754359Sroberto		if (value == 0 || (len = strlen(value)) == 0)
31854359Sroberto		    break;
31954359Sroberto
32054359Sroberto		stats_drift_file = (char*)emalloc((u_int)(len + 1));
32154359Sroberto#if !defined(VMS)
322132451Sroberto		stats_temp_file = (char*)emalloc((u_int)(len +
323132451Sroberto		    sizeof(".TEMP")));
32454359Sroberto#else
325132451Sroberto		stats_temp_file = (char*)emalloc((u_int)(len +
326132451Sroberto		    sizeof("-TEMP")));
32754359Sroberto#endif /* VMS */
32854359Sroberto		memmove(stats_drift_file, value, (unsigned)(len+1));
32954359Sroberto		memmove(stats_temp_file, value, (unsigned)len);
33054359Sroberto#if !defined(VMS)
331132451Sroberto		memmove(stats_temp_file + len, ".TEMP",
332132451Sroberto		    sizeof(".TEMP"));
33354359Sroberto#else
334132451Sroberto		memmove(stats_temp_file + len, "-TEMP",
335132451Sroberto		    sizeof("-TEMP"));
33654359Sroberto#endif /* VMS */
33754359Sroberto
33854359Sroberto		/*
339132451Sroberto		 * Open drift file and read frequency. If the file is
340132451Sroberto		 * missing or contains errors, tell the loop to reset.
34154359Sroberto		 */
34254359Sroberto		if ((fp = fopen(stats_drift_file, "r")) == NULL) {
343182007Sroberto			old_drift = 1e9;
34454359Sroberto			break;
34554359Sroberto		}
34654359Sroberto		if (fscanf(fp, "%lf", &old_drift) != 1) {
347132451Sroberto			msyslog(LOG_ERR, "Frequency format error in %s",
34854359Sroberto			    stats_drift_file);
349182007Sroberto			old_drift = 1e9;
350132451Sroberto			fclose(fp);
35154359Sroberto			break;
35254359Sroberto		}
353132451Sroberto		fclose(fp);
354182007Sroberto		prev_drift_comp = old_drift / 1e6;
355132451Sroberto		msyslog(LOG_INFO,
356132451Sroberto		    "frequency initialized %.3f PPM from %s",
357132451Sroberto			old_drift, stats_drift_file);
35854359Sroberto		break;
35954359Sroberto
36054359Sroberto	    case STATS_STATSDIR:
36154359Sroberto		if (strlen(value) >= sizeof(statsdir)) {
36254359Sroberto			msyslog(LOG_ERR,
36354359Sroberto			    "value for statsdir too long (>%d, sigh)",
36454359Sroberto			    (int)sizeof(statsdir)-1);
36554359Sroberto		} else {
36654359Sroberto			l_fp now;
36754359Sroberto
36854359Sroberto			get_systime(&now);
36954359Sroberto			strcpy(statsdir,value);
37054359Sroberto			if(peerstats.prefix == &statsdir[0] &&
37154359Sroberto			    peerstats.fp != NULL) {
37254359Sroberto				fclose(peerstats.fp);
37354359Sroberto				peerstats.fp = NULL;
37454359Sroberto				filegen_setup(&peerstats, now.l_ui);
37554359Sroberto			}
37654359Sroberto			if(loopstats.prefix == &statsdir[0] &&
37754359Sroberto			    loopstats.fp != NULL) {
37854359Sroberto				fclose(loopstats.fp);
37954359Sroberto				loopstats.fp = NULL;
38054359Sroberto				filegen_setup(&loopstats, now.l_ui);
38154359Sroberto			}
38254359Sroberto			if(clockstats.prefix == &statsdir[0] &&
38354359Sroberto			    clockstats.fp != NULL) {
38454359Sroberto				fclose(clockstats.fp);
38554359Sroberto				clockstats.fp = NULL;
38654359Sroberto				filegen_setup(&clockstats, now.l_ui);
38754359Sroberto			}
38854359Sroberto			if(rawstats.prefix == &statsdir[0] &&
38954359Sroberto			    rawstats.fp != NULL) {
39054359Sroberto				fclose(rawstats.fp);
39154359Sroberto				rawstats.fp = NULL;
39254359Sroberto				filegen_setup(&rawstats, now.l_ui);
39354359Sroberto			}
394132451Sroberto			if(sysstats.prefix == &statsdir[0] &&
395132451Sroberto			    sysstats.fp != NULL) {
396132451Sroberto				fclose(sysstats.fp);
397132451Sroberto				sysstats.fp = NULL;
398132451Sroberto				filegen_setup(&sysstats, now.l_ui);
399132451Sroberto			}
400132451Sroberto#ifdef OPENSSL
401132451Sroberto			if(cryptostats.prefix == &statsdir[0] &&
402132451Sroberto			    cryptostats.fp != NULL) {
403132451Sroberto				fclose(cryptostats.fp);
404132451Sroberto				cryptostats.fp = NULL;
405132451Sroberto				filegen_setup(&cryptostats, now.l_ui);
406132451Sroberto			}
407132451Sroberto#endif /* OPENSSL */
40854359Sroberto		}
40954359Sroberto		break;
41054359Sroberto
41154359Sroberto	    case STATS_PID_FILE:
41254359Sroberto		if ((fp = fopen(value, "w")) == NULL) {
41354359Sroberto			msyslog(LOG_ERR, "Can't open %s: %m", value);
41454359Sroberto			break;
41554359Sroberto		}
41654359Sroberto		fprintf(fp, "%d", (int) getpid());
41754359Sroberto		fclose(fp);;
41854359Sroberto		break;
41954359Sroberto
42054359Sroberto	    default:
42154359Sroberto		/* oh well */
42254359Sroberto		break;
42354359Sroberto	}
42454359Sroberto}
42554359Sroberto
42654359Sroberto/*
42754359Sroberto * record_peer_stats - write peer statistics to file
42854359Sroberto *
42954359Sroberto * file format:
43054359Sroberto * day (mjd)
43154359Sroberto * time (s past UTC midnight)
43254359Sroberto * peer (ip address)
43354359Sroberto * peer status word (hex)
43454359Sroberto * peer offset (s)
43554359Sroberto * peer delay (s)
43654359Sroberto * peer error bound (s)
43754359Sroberto * peer error (s)
43854359Sroberto*/
43954359Srobertovoid
44054359Srobertorecord_peer_stats(
441132451Sroberto	struct sockaddr_storage *addr,
442132451Sroberto	int	status,
443132451Sroberto	double	offset,
444132451Sroberto	double	delay,
445132451Sroberto	double	dispersion,
446132451Sroberto	double	skew
44754359Sroberto	)
44854359Sroberto{
449132451Sroberto	l_fp	now;
450132451Sroberto	u_long	day;
45154359Sroberto
45254359Sroberto	if (!stats_control)
45354359Sroberto		return;
45454359Sroberto
455132451Sroberto	get_systime(&now);
456132451Sroberto	filegen_setup(&peerstats, now.l_ui);
457132451Sroberto	day = now.l_ui / 86400 + MJD_1900;
458132451Sroberto	now.l_ui %= 86400;
45954359Sroberto	if (peerstats.fp != NULL) {
46054359Sroberto		fprintf(peerstats.fp,
461132451Sroberto		    "%lu %s %s %x %.9f %.9f %.9f %.9f\n",
462132451Sroberto		    day, ulfptoa(&now, 3), stoa(addr), status, offset,
46354359Sroberto		    delay, dispersion, skew);
46454359Sroberto		fflush(peerstats.fp);
46554359Sroberto	}
46654359Sroberto}
467182007Sroberto
46854359Sroberto/*
46954359Sroberto * record_loop_stats - write loop filter statistics to file
47054359Sroberto *
47154359Sroberto * file format:
47254359Sroberto * day (mjd)
47354359Sroberto * time (s past midnight)
47454359Sroberto * offset (s)
47554359Sroberto * frequency (approx ppm)
47654359Sroberto * time constant (log base 2)
47754359Sroberto */
47854359Srobertovoid
47982498Srobertorecord_loop_stats(
480132451Sroberto	double	offset,
481132451Sroberto	double	freq,
482132451Sroberto	double	jitter,
483132451Sroberto	double	stability,
484132451Sroberto	int spoll
48582498Sroberto	)
48654359Sroberto{
487132451Sroberto	l_fp	now;
488132451Sroberto	u_long	day;
48954359Sroberto
49054359Sroberto	if (!stats_control)
49154359Sroberto		return;
49254359Sroberto
493132451Sroberto	get_systime(&now);
494132451Sroberto	filegen_setup(&loopstats, now.l_ui);
495132451Sroberto	day = now.l_ui / 86400 + MJD_1900;
496132451Sroberto	now.l_ui %= 86400;
49754359Sroberto	if (loopstats.fp != NULL) {
498182007Sroberto		fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n",
499132451Sroberto		    day, ulfptoa(&now, 3), offset, freq * 1e6, jitter,
500132451Sroberto		    stability * 1e6, spoll);
50154359Sroberto		fflush(loopstats.fp);
50254359Sroberto	}
50354359Sroberto}
50454359Sroberto
50554359Sroberto/*
50654359Sroberto * record_clock_stats - write clock statistics to file
50754359Sroberto *
50854359Sroberto * file format:
50954359Sroberto * day (mjd)
51054359Sroberto * time (s past midnight)
51154359Sroberto * peer (ip address)
51254359Sroberto * text message
51354359Sroberto */
51454359Srobertovoid
51554359Srobertorecord_clock_stats(
516132451Sroberto	struct sockaddr_storage *addr,
51754359Sroberto	const char *text
51854359Sroberto	)
51954359Sroberto{
520132451Sroberto	l_fp	now;
521132451Sroberto	u_long	day;
52254359Sroberto
52354359Sroberto	if (!stats_control)
52454359Sroberto		return;
52554359Sroberto
526132451Sroberto	get_systime(&now);
527132451Sroberto	filegen_setup(&clockstats, now.l_ui);
528132451Sroberto	day = now.l_ui / 86400 + MJD_1900;
529132451Sroberto	now.l_ui %= 86400;
53054359Sroberto	if (clockstats.fp != NULL) {
531132451Sroberto		fprintf(clockstats.fp, "%lu %s %s %s\n",
532132451Sroberto		    day, ulfptoa(&now, 3), stoa(addr), text);
53354359Sroberto		fflush(clockstats.fp);
53454359Sroberto	}
53554359Sroberto}
53654359Sroberto
53754359Sroberto/*
53854359Sroberto * record_raw_stats - write raw timestamps to file
53954359Sroberto *
54054359Sroberto *
54154359Sroberto * file format
54254359Sroberto * time (s past midnight)
54354359Sroberto * peer ip address
54454359Sroberto * local ip address
54554359Sroberto * t1 t2 t3 t4 timestamps
54654359Sroberto */
54754359Srobertovoid
54854359Srobertorecord_raw_stats(
549132451Sroberto        struct sockaddr_storage *srcadr,
550132451Sroberto        struct sockaddr_storage *dstadr,
551132451Sroberto	l_fp	*t1,
552132451Sroberto	l_fp	*t2,
553132451Sroberto	l_fp	*t3,
554132451Sroberto	l_fp	*t4
55554359Sroberto	)
55654359Sroberto{
557132451Sroberto	l_fp	now;
558132451Sroberto	u_long	day;
55954359Sroberto
56054359Sroberto	if (!stats_control)
56154359Sroberto		return;
56254359Sroberto
563132451Sroberto	get_systime(&now);
564132451Sroberto	filegen_setup(&rawstats, now.l_ui);
565132451Sroberto	day = now.l_ui / 86400 + MJD_1900;
566132451Sroberto	now.l_ui %= 86400;
56754359Sroberto	if (rawstats.fp != NULL) {
568132451Sroberto                fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n",
569182007Sroberto			day, ulfptoa(&now, 3), stoa(srcadr), dstadr ? stoa(dstadr) : "-",
570182007Sroberto			ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9),
571182007Sroberto			ulfptoa(t4, 9));
57254359Sroberto		fflush(rawstats.fp);
57354359Sroberto	}
57454359Sroberto}
57554359Sroberto
576132451Sroberto
57754359Sroberto/*
578132451Sroberto * record_sys_stats - write system statistics to file
579132451Sroberto *
580132451Sroberto * file format
581132451Sroberto * time (s past midnight)
582132451Sroberto * time since startup (hr)
583132451Sroberto * packets recieved
584132451Sroberto * packets processed
585132451Sroberto * current version
586132451Sroberto * previous version
587132451Sroberto * bad version
588132451Sroberto * access denied
589132451Sroberto * bad length or format
590132451Sroberto * bad authentication
591132451Sroberto * rate exceeded
592132451Sroberto */
593132451Srobertovoid
594132451Srobertorecord_sys_stats(void)
595132451Sroberto{
596132451Sroberto	l_fp	now;
597132451Sroberto	u_long	day;
598132451Sroberto
599132451Sroberto	if (!stats_control)
600132451Sroberto		return;
601132451Sroberto
602132451Sroberto	get_systime(&now);
603132451Sroberto	filegen_setup(&sysstats, now.l_ui);
604132451Sroberto	day = now.l_ui / 86400 + MJD_1900;
605132451Sroberto	now.l_ui %= 86400;
606132451Sroberto	if (sysstats.fp != NULL) {
607132451Sroberto                fprintf(sysstats.fp,
608132451Sroberto		    "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
609132451Sroberto		    day, ulfptoa(&now, 3), sys_stattime / 3600,
610132451Sroberto		    sys_received, sys_processed, sys_newversionpkt,
611132451Sroberto		    sys_oldversionpkt, sys_unknownversion,
612132451Sroberto		    sys_restricted, sys_badlength, sys_badauth,
613132451Sroberto		    sys_limitrejected);
614132451Sroberto		fflush(sysstats.fp);
615132451Sroberto		proto_clr_stats();
616132451Sroberto	}
617132451Sroberto}
618132451Sroberto
619132451Sroberto
620132451Sroberto#ifdef OPENSSL
621132451Sroberto/*
622132451Sroberto * record_crypto_stats - write crypto statistics to file
623132451Sroberto *
624132451Sroberto * file format:
625132451Sroberto * day (mjd)
626132451Sroberto * time (s past midnight)
627132451Sroberto * peer (ip address)
628132451Sroberto * text message
629132451Sroberto */
630132451Srobertovoid
631132451Srobertorecord_crypto_stats(
632132451Sroberto	struct sockaddr_storage *addr,
633132451Sroberto	const char *text
634132451Sroberto	)
635132451Sroberto{
636132451Sroberto	l_fp	now;
637132451Sroberto	u_long	day;
638132451Sroberto
639132451Sroberto	if (!stats_control)
640132451Sroberto		return;
641132451Sroberto
642132451Sroberto	get_systime(&now);
643132451Sroberto	filegen_setup(&cryptostats, now.l_ui);
644132451Sroberto	day = now.l_ui / 86400 + MJD_1900;
645132451Sroberto	now.l_ui %= 86400;
646132451Sroberto	if (cryptostats.fp != NULL) {
647132451Sroberto		if (addr == NULL)
648132451Sroberto			fprintf(cryptostats.fp, "%lu %s %s\n",
649132451Sroberto			    day, ulfptoa(&now, 3), text);
650132451Sroberto		else
651132451Sroberto			fprintf(cryptostats.fp, "%lu %s %s %s\n",
652132451Sroberto			    day, ulfptoa(&now, 3), stoa(addr), text);
653132451Sroberto		fflush(cryptostats.fp);
654132451Sroberto	}
655132451Sroberto}
656132451Sroberto#endif /* OPENSSL */
657132451Sroberto
658182007Sroberto#ifdef DEBUG_TIMING
659182007Sroberto/*
660182007Sroberto * record_crypto_stats - write crypto statistics to file
661182007Sroberto *
662182007Sroberto * file format:
663182007Sroberto * day (mjd)
664182007Sroberto * time (s past midnight)
665182007Sroberto * text message
666182007Sroberto */
667182007Srobertovoid
668182007Srobertorecord_timing_stats(
669182007Sroberto	const char *text
670182007Sroberto	)
671182007Sroberto{
672182007Sroberto	static unsigned int flshcnt;
673182007Sroberto	l_fp	now;
674182007Sroberto	u_long	day;
675132451Sroberto
676182007Sroberto	if (!stats_control)
677182007Sroberto		return;
678182007Sroberto
679182007Sroberto	get_systime(&now);
680182007Sroberto	filegen_setup(&timingstats, now.l_ui);
681182007Sroberto	day = now.l_ui / 86400 + MJD_1900;
682182007Sroberto	now.l_ui %= 86400;
683182007Sroberto	if (timingstats.fp != NULL) {
684182007Sroberto		fprintf(timingstats.fp, "%lu %s %s\n",
685182007Sroberto			    day, lfptoa(&now, 3), text);
686182007Sroberto		if (++flshcnt % 100 == 0)
687182007Sroberto			fflush(timingstats.fp);
688182007Sroberto	}
689182007Sroberto}
690182007Sroberto#endif
691132451Sroberto/*
69254359Sroberto * getauthkeys - read the authentication keys from the specified file
69354359Sroberto */
69454359Srobertovoid
69554359Srobertogetauthkeys(
696182007Sroberto	const char *keyfile
69754359Sroberto	)
69854359Sroberto{
69954359Sroberto	int len;
70054359Sroberto
70154359Sroberto	len = strlen(keyfile);
70254359Sroberto	if (len == 0)
70354359Sroberto		return;
70454359Sroberto
70554359Sroberto	if (key_file_name != 0) {
70654359Sroberto		if (len > (int)strlen(key_file_name)) {
70754359Sroberto			(void) free(key_file_name);
70854359Sroberto			key_file_name = 0;
70954359Sroberto		}
71054359Sroberto	}
71154359Sroberto
71254359Sroberto	if (key_file_name == 0) {
71354359Sroberto#ifndef SYS_WINNT
71454359Sroberto		key_file_name = (char*)emalloc((u_int) (len + 1));
71554359Sroberto#else
71654359Sroberto		key_file_name = (char*)emalloc((u_int)  (MAXPATHLEN));
71754359Sroberto#endif
71854359Sroberto	}
71954359Sroberto#ifndef SYS_WINNT
72054359Sroberto 	memmove(key_file_name, keyfile, (unsigned)(len+1));
72154359Sroberto#else
72254359Sroberto	if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN))
72354359Sroberto	{
72454359Sroberto		msyslog(LOG_ERR,
72554359Sroberto		    "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n");
72654359Sroberto	}
72754359Sroberto#endif /* SYS_WINNT */
72854359Sroberto
72954359Sroberto	authreadkeys(key_file_name);
73054359Sroberto}
73154359Sroberto
73254359Sroberto
73354359Sroberto/*
73454359Sroberto * rereadkeys - read the authentication key file over again.
73554359Sroberto */
73654359Srobertovoid
73754359Srobertorereadkeys(void)
73854359Sroberto{
73954359Sroberto	if (key_file_name != 0)
74054359Sroberto	    authreadkeys(key_file_name);
74154359Sroberto}
742132451Sroberto
743132451Sroberto/*
744132451Sroberto * sock_hash - hash an sockaddr_storage structure
745132451Sroberto */
746132451Srobertoint
747132451Srobertosock_hash(
748132451Sroberto	struct sockaddr_storage *addr
749132451Sroberto	)
750132451Sroberto{
751132451Sroberto	int hashVal;
752132451Sroberto	int i;
753132451Sroberto	int len;
754132451Sroberto	char *ch;
755132451Sroberto
756132451Sroberto	hashVal = 0;
757132451Sroberto	len = 0;
758132451Sroberto	/*
759132451Sroberto	 * We can't just hash the whole thing because there are hidden
760132451Sroberto	 * fields in sockaddr_in6 that might be filled in by recvfrom(),
761132451Sroberto	 * so just use the family, port and address.
762132451Sroberto	 */
763132451Sroberto	ch = (char *)&addr->ss_family;
764132451Sroberto	hashVal = 37 * hashVal + (int)*ch;
765132451Sroberto	if (sizeof(addr->ss_family) > 1) {
766132451Sroberto		ch++;
767132451Sroberto		hashVal = 37 * hashVal + (int)*ch;
768132451Sroberto	}
769132451Sroberto	switch(addr->ss_family) {
770132451Sroberto	case AF_INET:
771132451Sroberto		ch = (char *)&((struct sockaddr_in *)addr)->sin_addr;
772132451Sroberto		len = sizeof(struct in_addr);
773132451Sroberto		break;
774132451Sroberto	case AF_INET6:
775132451Sroberto		ch = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr;
776132451Sroberto		len = sizeof(struct in6_addr);
777132451Sroberto		break;
778132451Sroberto	}
779132451Sroberto
780132451Sroberto	for (i = 0; i < len ; i++)
781132451Sroberto		hashVal = 37 * hashVal + (int)*(ch + i);
782132451Sroberto
783132451Sroberto	hashVal = hashVal % 128;  /* % MON_HASH_SIZE hardcoded */
784132451Sroberto
785132451Sroberto	if (hashVal < 0)
786132451Sroberto		hashVal += 128;
787132451Sroberto
788132451Sroberto	return hashVal;
789132451Sroberto}
790182007Sroberto
791182007Sroberto#if notyet
792182007Sroberto/*
793182007Sroberto * ntp_exit - document explicitly that ntpd has exited
794182007Sroberto */
795182007Srobertovoid
796182007Srobertontp_exit(int retval)
797182007Sroberto{
798182007Sroberto  msyslog(LOG_ERR, "EXITING with return code %d", retval);
799182007Sroberto  exit(retval);
800182007Sroberto}
801182007Sroberto#endif
802