⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 systime.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
字号:
/* * systime -- routines to fiddle a UNIX clock. * * ATTENTION: Get approval from Dave Mills on all changes to this file! * */#include "ntp_machine.h"#include "ntp_fp.h"#include "ntp_syslog.h"#include "ntp_unixtime.h"#include "ntp_stdlib.h"#include "ntp_random.h"#ifdef SIM#include "ntpsim.h"#endif /*SIM */#ifdef HAVE_SYS_PARAM_H# include <sys/param.h>#endif#ifdef HAVE_UTMP_H# include <utmp.h>#endif /* HAVE_UTMP_H */#ifdef HAVE_UTMPX_H# include <utmpx.h>#endif /* HAVE_UTMPX_H *//* * These routines (get_systime, step_systime, adj_systime) implement an * interface between the system independent NTP clock and the Unix * system clock in various architectures and operating systems. * * Time is a precious quantity in these routines and every effort is * made to minimize errors by always rounding toward zero and amortizing * adjustment residues. By default the adjustment quantum is 1 us for * the usual Unix tickadj() system call, but this can be increased if * necessary by the tick configuration command. For instance, when the * adjtime() quantum is a clock tick for a 100-Hz clock, the quantum * should be 10 ms. */#if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCKdouble	sys_tick = 10e-3;	/* 10 ms tickadj() */#elsedouble	sys_tick = 1e-6;	/* 1 us tickadj() */#endifdouble	sys_residual = 0;	/* adjustment residue (s) */#ifndef SIM/* * get_systime - return system time in NTP timestamp format. */voidget_systime(	l_fp *now		/* system time */	){	double dtemp;#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)	struct timespec ts;	/* seconds and nanoseconds */	/*	 * Convert Unix clock from seconds and nanoseconds to seconds.	 * The bottom is only two bits down, so no need for fuzz.	 */# ifdef HAVE_CLOCK_GETTIME	clock_gettime(CLOCK_REALTIME, &ts);# else	getclock(TIMEOFDAY, &ts);# endif	now->l_i = ts.tv_sec + JAN_1970;	dtemp = ts.tv_nsec / 1e9;#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */	struct timeval tv;	/* seconds and microseconds */	/*	 * Convert Unix clock from seconds and microseconds to seconds.	 * Add in unbiased random fuzz beneath the microsecond.	 */	GETTIMEOFDAY(&tv, NULL);	now->l_i = tv.tv_sec + JAN_1970;	/* ntp_random() produces 31 bits (always nonnegative) */	dtemp = (tv.tv_usec + ntp_random() / FRAC - .5) / 1e6;#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */	/*	 * Renormalize to seconds past 1900 and fraction.	 */	dtemp += sys_residual;	if (dtemp >= 1) {		dtemp -= 1;		now->l_i++;	} else if (dtemp < 0) {		dtemp += 1;		now->l_i--;	}	dtemp *= FRAC;	now->l_uf = (u_int32)dtemp;}/* * adj_systime - adjust system time by the argument. */#if !defined SYS_WINNTint				/* 0 okay, 1 error */adj_systime(	double now		/* adjustment (s) */	){	struct timeval adjtv;	/* new adjustment */	struct timeval oadjtv;	/* residual adjustment */	double	dtemp;	long	ticks;	int	isneg = 0;	/*	 * Most Unix adjtime() implementations adjust the system clock	 * in microsecond quanta, but some adjust in 10-ms quanta. We	 * carefully round the adjustment to the nearest quantum, then	 * adjust in quanta and keep the residue for later.	 */	dtemp = now + sys_residual;	if (dtemp < 0) {		isneg = 1;		dtemp = -dtemp;	}	adjtv.tv_sec = (long)dtemp;	dtemp -= adjtv.tv_sec;	ticks = (long)(dtemp / sys_tick + .5);	adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);	dtemp -= adjtv.tv_usec / 1e6;	sys_residual = dtemp;	/*	 * Convert to signed seconds and microseconds for the Unix	 * adjtime() system call. Note we purposely lose the adjtime()	 * leftover.	 */	if (isneg) {		adjtv.tv_sec = -adjtv.tv_sec;		adjtv.tv_usec = -adjtv.tv_usec;		sys_residual = -sys_residual;	}	if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {		if (adjtime(&adjtv, &oadjtv) < 0) {			msyslog(LOG_ERR, "adj_systime: %m");			return (0);		}	}	return (1);}#endif/* * step_systime - step the system clock. */intstep_systime(	double now	){	struct timeval timetv, adjtv, oldtimetv;	int isneg = 0;	double dtemp;#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)	struct timespec ts;#endif	dtemp = sys_residual + now;	if (dtemp < 0) {		isneg = 1;		dtemp = - dtemp;		adjtv.tv_sec = (int32)dtemp;		adjtv.tv_usec = (u_int32)((dtemp -		    (double)adjtv.tv_sec) * 1e6 + .5);	} else {		adjtv.tv_sec = (int32)dtemp;		adjtv.tv_usec = (u_int32)((dtemp -		    (double)adjtv.tv_sec) * 1e6 + .5);	}#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)#ifdef HAVE_CLOCK_GETTIME	(void) clock_gettime(CLOCK_REALTIME, &ts);#else	(void) getclock(TIMEOFDAY, &ts);#endif	timetv.tv_sec = ts.tv_sec;	timetv.tv_usec = ts.tv_nsec / 1000;#else /*  not HAVE_GETCLOCK */	(void) GETTIMEOFDAY(&timetv, (struct timezone *)0);#endif /* not HAVE_GETCLOCK */	oldtimetv = timetv;#ifdef DEBUG	if (debug)		printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);#endif	if (isneg) {		timetv.tv_sec -= adjtv.tv_sec;		timetv.tv_usec -= adjtv.tv_usec;		if (timetv.tv_usec < 0) {			timetv.tv_sec--;			timetv.tv_usec += 1000000;		}	} else {		timetv.tv_sec += adjtv.tv_sec;		timetv.tv_usec += adjtv.tv_usec;		if (timetv.tv_usec >= 1000000) {			timetv.tv_sec++;			timetv.tv_usec -= 1000000;		}	}	if (ntp_set_tod(&timetv, NULL) != 0) {		msyslog(LOG_ERR, "step-systime: %m");		return (0);	}	sys_residual = 0;#ifdef NEED_HPUX_ADJTIME	/*	 * CHECKME: is this correct when called by ntpdate?????	 */	_clear_adjtime();#endif	/*	 * FreeBSD, for example, has:	 * struct utmp {	 *	   char    ut_line[UT_LINESIZE];	 *	   char    ut_name[UT_NAMESIZE];	 *	   char    ut_host[UT_HOSTSIZE];	 *	   long    ut_time;	 * };	 * and appends line="|", name="date", host="", time for the OLD	 * and appends line="{", name="date", host="", time for the NEW	 * to _PATH_WTMP .	 *	 * Some OSes have utmp, some have utmpx.	 */	/*	 * Write old and new time entries in utmp and wtmp if step	 * adjustment is greater than one second.	 *	 * This might become even Uglier...	 */	if (oldtimetv.tv_sec != timetv.tv_sec)	{#ifdef HAVE_UTMP_H		struct utmp ut;#endif#ifdef HAVE_UTMPX_H		struct utmpx utx;#endif#ifdef HAVE_UTMP_H		memset((char *)&ut, 0, sizeof(ut));#endif#ifdef HAVE_UTMPX_H		memset((char *)&utx, 0, sizeof(utx));#endif		/* UTMP */#ifdef UPDATE_UTMP# ifdef HAVE_PUTUTLINE		ut.ut_type = OLD_TIME;		(void)strcpy(ut.ut_line, OTIME_MSG);		ut.ut_time = oldtimetv.tv_sec;		pututline(&ut);		setutent();		ut.ut_type = NEW_TIME;		(void)strcpy(ut.ut_line, NTIME_MSG);		ut.ut_time = timetv.tv_sec;		pututline(&ut);		endutent();# else /* not HAVE_PUTUTLINE */# endif /* not HAVE_PUTUTLINE */#endif /* UPDATE_UTMP */		/* UTMPX */#ifdef UPDATE_UTMPX# ifdef HAVE_PUTUTXLINE		utx.ut_type = OLD_TIME;		(void)strcpy(utx.ut_line, OTIME_MSG);		utx.ut_tv = oldtimetv;		pututxline(&utx);		setutxent();		utx.ut_type = NEW_TIME;		(void)strcpy(utx.ut_line, NTIME_MSG);		utx.ut_tv = timetv;		pututxline(&utx);		endutxent();# else /* not HAVE_PUTUTXLINE */# endif /* not HAVE_PUTUTXLINE */#endif /* UPDATE_UTMPX */		/* WTMP */#ifdef UPDATE_WTMP# ifdef HAVE_PUTUTLINE		utmpname(WTMP_FILE);		ut.ut_type = OLD_TIME;		(void)strcpy(ut.ut_line, OTIME_MSG);		ut.ut_time = oldtimetv.tv_sec;		pututline(&ut);		ut.ut_type = NEW_TIME;		(void)strcpy(ut.ut_line, NTIME_MSG);		ut.ut_time = timetv.tv_sec;		pututline(&ut);		endutent();# else /* not HAVE_PUTUTLINE */# endif /* not HAVE_PUTUTLINE */#endif /* UPDATE_WTMP */		/* WTMPX */#ifdef UPDATE_WTMPX# ifdef HAVE_PUTUTXLINE		utx.ut_type = OLD_TIME;		utx.ut_tv = oldtimetv;		(void)strcpy(utx.ut_line, OTIME_MSG);#  ifdef HAVE_UPDWTMPX		updwtmpx(WTMPX_FILE, &utx);#  else /* not HAVE_UPDWTMPX */#  endif /* not HAVE_UPDWTMPX */# else /* not HAVE_PUTUTXLINE */# endif /* not HAVE_PUTUTXLINE */# ifdef HAVE_PUTUTXLINE		utx.ut_type = NEW_TIME;		utx.ut_tv = timetv;		(void)strcpy(utx.ut_line, NTIME_MSG);#  ifdef HAVE_UPDWTMPX		updwtmpx(WTMPX_FILE, &utx);#  else /* not HAVE_UPDWTMPX */#  endif /* not HAVE_UPDWTMPX */# else /* not HAVE_PUTUTXLINE */# endif /* not HAVE_PUTUTXLINE */#endif /* UPDATE_WTMPX */	}	return (1);}#else /* SIM *//* * Clock routines for the simulator - Harish Nair, with help *//* * get_systime - return the system time in NTP timestamp format  */voidget_systime(        l_fp *now		/* current system time in l_fp */        ){	/*	 * To fool the code that determines the local clock precision,	 * we advance the clock a minimum of 200 nanoseconds on every	 * clock read. This is appropriate for a typical modern machine	 * with nanosecond clocks. Note we make no attempt here to	 * simulate reading error, since the error is so small. This may	 * change when the need comes to implement picosecond clocks.	 */	if (ntp_node.ntp_time == ntp_node.last_time)		ntp_node.ntp_time += 200e-9;	ntp_node.last_time = ntp_node.ntp_time;	DTOLFP(ntp_node.ntp_time, now);}  /* * adj_systime - advance or retard the system clock exactly like the * real thng. */int				/* always succeeds */adj_systime(        double now		/* time adjustment (s) */        ){	struct timeval adjtv;	/* new adjustment */	double	dtemp;	long	ticks;	int	isneg = 0;	/*	 * Most Unix adjtime() implementations adjust the system clock	 * in microsecond quanta, but some adjust in 10-ms quanta. We	 * carefully round the adjustment to the nearest quantum, then	 * adjust in quanta and keep the residue for later.	 */	dtemp = now + sys_residual;	if (dtemp < 0) {		isneg = 1;		dtemp = -dtemp;	}	adjtv.tv_sec = (long)dtemp;	dtemp -= adjtv.tv_sec;	ticks = (long)(dtemp / sys_tick + .5);	adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);	dtemp -= adjtv.tv_usec / 1e6;	sys_residual = dtemp;	/*	 * Convert to signed seconds and microseconds for the Unix	 * adjtime() system call. Note we purposely lose the adjtime()	 * leftover.	 */	if (isneg) {		adjtv.tv_sec = -adjtv.tv_sec;		adjtv.tv_usec = -adjtv.tv_usec;		sys_residual = -sys_residual;	}	ntp_node.adj = now;	return (1);}  /* * step_systime - step the system clock. We are religious here. */int				/* always succeeds */step_systime(        double now		/* step adjustment (s) */        ){#ifdef DEBUG	if (debug)		printf("step_systime: time %.6f adj %.6f\n",		   ntp_node.ntp_time, now);#endif	ntp_node.ntp_time += now;	return (1);}/* * node_clock - update the clocks */int				/* always succeeds */node_clock(	Node *n,		/* global node pointer */	double t		/* node time */	){	double	dtemp;	/*	 * Advance client clock (ntp_time). Advance server clock	 * (clk_time) adjusted for systematic and random frequency	 * errors. The random error is a random walk computed as the	 * integral of samples from a Gaussian distribution.	 */	dtemp = t - n->ntp_time;	n->time = t;	n->ntp_time += dtemp;	n->ferr += gauss(0, dtemp * n->fnse);	n->clk_time += dtemp * (1 + n->ferr);	/*	 * Perform the adjtime() function. If the adjustment completed	 * in the previous interval, amortize the entire amount; if not,	 * carry the leftover to the next interval.	 */	dtemp *= n->slew;	if (dtemp < fabs(n->adj)) {		if (n->adj < 0) {			n->adj += dtemp;			n->ntp_time -= dtemp;		} else {			n->adj -= dtemp;			n->ntp_time += dtemp;		}	} else {		n->ntp_time += n->adj;		n->adj = 0;	}        return (0);} /* * gauss() - returns samples from a gaussion distribution */double				/* Gaussian sample */gauss(	double m,		/* sample mean */	double s		/* sample standard deviation (sigma) */	){        double q1, q2;	/*	 * Roll a sample from a Gaussian distribution with mean m and	 * standard deviation s. For m = 0, s = 1, mean(y) = 0,	 * std(y) = 1.	 */	if (s == 0)		return (m);        while ((q1 = drand48()) == 0);        q2 = drand48();        return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2));} /* * poisson() - returns samples from a network delay distribution */double				/* delay sample (s) */poisson(	double m,		/* fixed propagation delay (s) */	double s		/* exponential parameter (mu) */	){        double q1;	/*	 * Roll a sample from a composite distribution with propagation	 * delay m and exponential distribution time with parameter s.	 * For m = 0, s = 1, mean(y) = std(y) = 1.	 */	if (s == 0)		return (m);        while ((q1 = drand48()) == 0);        return (m - s * log(q1 * s));}#endif /* SIM */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -