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

📄 ntp_refclock.c

📁 Unix/Linux 网络时间协议版本3 Network Time Protocol Version 3 (NTP) distribution for Unix systems
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * ntp_refclock - processing support for reference clocks */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <sys/types.h>#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif /* HAVE_SYS_IOCTL_H */#include "ntpd.h"#include "ntp_io.h"#include "ntp_unixtime.h"#include "ntp_refclock.h"#include "ntp_stdlib.h"#ifdef REFCLOCK#ifdef TTYCLK#include <sys/clkdefs.h>#endif /* TTYCLK */#ifdef CHUCLK#include <sys/chudefs.h>#endif /* CHUCLK */#ifdef PPS#include <sys/ppsclock.h>#endif /* PPS *//* * Reference clock support is provided here by maintaining the fiction * that the clock is actually a peer. As no packets are exchanged with a * reference clock, however, we replace the transmit, receive and packet * procedures with separate code to simulate them. Routines * refclock_transmit() and refclock_receive() maintain the peer * variables in a state analogous to an actual peer and pass reference * clock data on through the filters. Routines refclock_peer() and * refclock_unpeer() are called to initialize and terminate reference * clock associations. A set of utility routines is included to open * serial devices, process sample data, edit input lines to extract * embedded timestamps and to peform various debugging functions. * * The main interface used by these routines is the refclockproc * structure, which contains for most drivers the decimal equivalants of * the year, day, month, hour, second and millisecond/microsecond * decoded from the ASCII timecode. Additional information includes the * receive timestamp, exception report, statistics tallies, etc. In * addition, there may be a driver-specific unit structure used for * local control of the device. * * The support routines are passed a pointer to the peer structure, * which is used for all peer-specific processing and contains a pointer * to the refclockproc structure, which in turn containes a pointer to * the unit structure, if used. In addition, some routines expect an * address in the dotted quad form 127.127.t.u, where t is the clock * type and u the unit. A table typeunit[type][unit] contains the peer * structure pointer for each configured clock type and unit. * * Most drivers support the 1-pps signal provided by some radios and * connected via a level converted described in the gadget directory. * The signal is captured using a separate, dedicated serial port and * the tty_clk line discipline/streams modules described in the kernel * directory. For the highest precision, the signal is captured using * the carrier-detect line of the same serial port using the ppsclock * streams module described in the ppsclock directory. */#define	REFCLOCKMAXDISPERSE (FP_SECOND/4) /* max sample dispersion */#define MAXUNIT		4	/* max units */#ifndef CLKLDISC#define CLKLDISC	10	/* XXX temp tty_clk line discipline */#endif#ifndef CHULDISC#define CHULDISC	10	/* XXX temp tty_chu line discipline */#endif/* * The refclock configuration table. Imported from refclock_conf */extern	struct	refclock *refclock_conf[];extern	u_char	num_refclock_conf;/* * Imported from the I/O module */extern	struct	interface *any_interface;extern	struct	interface *loopback_interface;/* * Imported from ntp_loopfilter module */extern	int	fdpps;		/* pps file descriptor */#ifdef PPSextern int pps_enable; 	/* pps enabled indicator (from ntp_loopfilter.c) */#endif /* PPS *//* * Imported from the timer module */extern	u_long	current_time;extern	struct	event timerqueue[];/* * Imported from the main and peer modules. We use the same algorithm * for spacing out timers at configuration time that the peer module * does. */extern	u_long	init_peer_starttime;extern	int	initializing;extern	int	debug;/* * Type/unit peer index. Used to find the peer structure for control and * debugging. When all clock drivers have been converted to new style, * this dissapears. */static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT];/* * Forward declarations */static int refclock_cmpl_fp P((const void *, const void *));/* * refclock_report - note the occurance of an event * * This routine presently just remembers the report and logs it, but * does nothing heroic for the trap handler. It tries to be a good * citizen and bothers the system log only if things change. */voidrefclock_report(peer, code)	struct peer *peer;	u_int code;{	struct refclockproc *pp;	if (!(pp = peer->procptr))		return;	if (code == CEVNT_BADREPLY)		pp->badformat++;	if (code == CEVNT_BADTIME)		pp->baddata++;	if (code == CEVNT_TIMEOUT)		pp->noreply++;	if (pp->currentstatus != code) {		pp->currentstatus = code;		pp->lastevent = code;		if (code == CEVNT_FAULT)		    NLOG(NLOG_CLOCKEVENT)		      msyslog(LOG_ERR,			     "clock %s fault '%s' (0x%02x)",			     refnumtoa(peer->srcadr.sin_addr.s_addr), ceventstr(code), code);		else {		    NLOG(NLOG_CLOCKEVENT)		      msyslog(LOG_INFO,			     "clock %s event '%s' (0x%02x)",			     refnumtoa(peer->srcadr.sin_addr.s_addr), ceventstr(code), code);		}	}}/* * init_refclock - initialize the reference clock drivers * * This routine calls each of the drivers in turn to initialize internal * variables, if necessary. Most drivers have nothing to say at this * point. */voidinit_refclock(){	int i, j;	for (i = 0; i < (int)num_refclock_conf; i++) {		if (refclock_conf[i]->clock_init != noentry)			(refclock_conf[i]->clock_init)();		for (j = 0; j < MAXUNIT; j++)			typeunit[i][j] = 0;	}}/* * refclock_newpeer - initialize and start a reference clock * * This routine allocates and initializes the interface structure which * supports a reference clock in the form of an ordinary NTP peer. A * driver-specific support routine completes the initialization, if * used. Default peer variables which identify the clock and establish * its reference ID and stratum are set here. It returns one if success * and zero if the clock address is invalid or already running, * insufficient resources are available or the driver declares a bum * rap. */intrefclock_newpeer(peer)	struct peer *peer;	/* peer structure pointer */{	struct refclockproc *pp;	u_char clktype;	int unit;	/*	 * Check for valid clock address. If already running, shut it	 * down first.	 */	if (!ISREFCLOCKADR(&peer->srcadr)) {		msyslog(LOG_ERR,		    "refclock_newpeer: clock address %s invalid",		    ntoa(&peer->srcadr));		return (0);	}	clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);	unit = REFCLOCKUNIT(&peer->srcadr);	if (clktype >= num_refclock_conf || unit > MAXUNIT ||	    refclock_conf[clktype]->clock_start == noentry) {		msyslog(LOG_ERR,		    "refclock_newpeer: clock type %d invalid\n",		    clktype);		return (0);	}	refclock_unpeer(peer);	/*	 * Allocate and initialize interface structure	 */	if (!(pp = (struct refclockproc *)	    emalloc(sizeof(struct refclockproc))))		return (0);	memset((char *)pp, 0, sizeof(struct refclockproc));	typeunit[clktype][unit] = peer;	peer->procptr = pp;	/*	 * Initialize structures	 */	peer->refclktype = clktype;	peer->refclkunit = unit;	peer->flags |= FLAG_REFCLOCK;	peer->event_timer.peer = peer;	peer->event_timer.event_handler = refclock_transmit;	pp->type = clktype;	pp->timestarted = current_time;	peer->stratum = STRATUM_REFCLOCK;	peer->refid = peer->srcadr.sin_addr.s_addr;	peer->maxpoll = peer->minpoll;	/*	 * Do driver dependent initialization	 */	if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {		free(pp);		return (0);	}	peer->hpoll = peer->minpoll;	peer->ppoll = peer->maxpoll;	if (peer->stratum <= 1)		peer->refid = pp->refid;	else		peer->refid = peer->srcadr.sin_addr.s_addr;	/*	 * Set up the timeout for polling and reachability determination	 */	if (initializing) {		init_peer_starttime += (1 << EVENT_TIMEOUT);		if (init_peer_starttime >= (u_long)(1 << peer->minpoll))			init_peer_starttime = (1 << EVENT_TIMEOUT);		peer->event_timer.event_time = init_peer_starttime;	} else {		peer->event_timer.event_time = current_time +		    (1 << peer->hpoll);	}	TIMER_ENQUEUE(timerqueue, &peer->event_timer);	return (1);}/* * refclock_unpeer - shut down a clock */voidrefclock_unpeer(peer)	struct peer *peer;	/* peer structure pointer */{	u_char clktype;	int unit;	/*	 * Wiggle the driver to release its resources, then give back	 * the interface structure.	 */	if (!peer->procptr)		return;	clktype = peer->refclktype;	unit = peer->refclkunit;	if (refclock_conf[clktype]->clock_shutdown != noentry)		(refclock_conf[clktype]->clock_shutdown)(unit, peer);	free(peer->procptr);	peer->procptr = 0;}/* * refclock_transmit - simulate the transmit procedure * * This routine implements the NTP transmit procedure for a reference * clock. This provides a mechanism to call the driver at the NTP poll * interval, as well as provides a reachability mechanism to detect a * broken radio or other madness. */voidrefclock_transmit(peer)	struct peer *peer;	/* peer structure pointer */{	struct refclockproc *pp;	u_char clktype;	int unit;	u_char opeer_reach;	pp = peer->procptr;	clktype = peer->refclktype;	unit = peer->refclkunit;	peer->sent++;	/*	 * The transmit procedure is supposed to freeze a timestamp.	 * Get one just for fun, and to tell when we last were here.	 */	get_systime(&peer->xmt);	/*	 * Fiddle reachability.	 */	opeer_reach = peer->reach;	peer->reach <<= 1;	if (peer->reach == 0) {		/*		 * Clear this one out. No need to redo selection since		 * this fellow will definitely be suffering from		 * dispersion madness.		 */		if (opeer_reach != 0) {			peer_clear(peer);			peer->timereachable = current_time;			report_event(EVNT_UNREACH, peer);		}	/*	 * Update reachability and poll variables	 */	} else if ((opeer_reach & 3) == 0) {		l_fp off;		if (peer->valid > 0)			peer->valid--;		L_CLR(&off);		clock_filter(peer, &off, 0, NTP_MAXDISPERSE);		if (peer->flags & FLAG_SYSPEER)			clock_select();	} else if (peer->valid < NTP_SHIFT)		peer->valid++;	/*	 * If he wants to be polled, do it. New style drivers do not use	 * the unit argument, since the fudge stuff is in the	 * refclockproc structure.	 */	if (refclock_conf[clktype]->clock_poll != noentry)		(refclock_conf[clktype]->clock_poll)(unit, peer);	/*	 * Finally, reset the timer	 */	peer->event_timer.event_time += (1 << peer->hpoll);	TIMER_ENQUEUE(timerqueue, &peer->event_timer);}/* * Compare two l_fp's - used with qsort() */static intrefclock_cmpl_fp(p1, p2)	register const void *p1, *p2;	/* l_fp to compare */{	if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2))		return (-1);	if (L_ISEQU((l_fp *)p1, (l_fp *)p2))		return (0);	return (1);}/* * refclock_process - process a pile of samples from the clock * * This routine converts the timecode in the form days, hours, miinutes, * seconds, milliseconds/microseconds to internal timestamp format. * Further processing is then delegated to refclock sample */intrefclock_process(pp, nstart, nskeep)	struct refclockproc *pp; /* peer structure pointer */	int nstart;		/* stages of median filter */	int nskeep;		/* stages after outlyer trim */{	l_fp offset;	/*	 * Compute the timecode timestamp from the days, hours, minutes,	 * seconds and milliseconds/microseconds of the timecode. Use	 * clocktime() for the aggregate seconds and the msec/usec for	 * the fraction, when present. Note that this code relies on the	 * filesystem time for the years and does not use the years of	 * the timecode.	 */	if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,	    pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) {#ifdef DEBUG            FILE*  fdToWrite = fopen("/tmp/ntp.out","w");            fprintf(fdToWrite,"Error in refclock_process clocktime \n");            fprintf(fdToWrite,"%d %d %d %d %d %u %u %d\n",                    pp->day, pp->hour, pp->minute, pp->second, GMT,                     pp->lastrec.l_ui, pp->yearstart, offset.l_ui);            fclose (fdToWrite);#endif		return (0);        }	if (pp->usec) {		TVUTOTSF(pp->usec, offset.l_uf);	} else {		MSUTOTSF(pp->msec, offset.l_uf);	}	L_ADD(&offset, &pp->fudgetime1);	pp->lastref = offset;	/* save last reference time */	/*	 * Include the configured fudgetime1 adjustment.	 */	L_SUB(&offset, &pp->lastrec); /* form true offset */	return refclock_sample(&offset, pp, nstart, nskeep);}/* * refclock_sample - process a pile of samples from the clock * * This routine converts the timecode in the form days, hours, miinutes, * seconds, milliseconds/microseconds to internal timestamp format. It * then calculates the difference from the receive timestamp and

⌨️ 快捷键说明

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