Exemplo n.º 1
0
/*
 * timepacket
 *
 * process a data packet
 */
static unsigned long
timepacket(
	register parse_t *parseio
	)
{
	register unsigned short format;
	register time_t t;
	unsigned long cvtrtc;		/* current conversion result */
	clocktime_t clock_time;

	memset((char *)&clock_time, 0, sizeof clock_time);
	format = parseio->parse_lformat;

	if (format == (unsigned short)~0)
		return CVT_NONE;

	switch ((cvtrtc = clockformats[format]->convert ?
		 clockformats[format]->convert((unsigned char *)parseio->parse_ldata, parseio->parse_ldsize, (struct format *)(clockformats[format]->data), &clock_time, parseio->parse_pdata) :
		 CVT_NONE) & CVT_MASK)
	{
	case CVT_FAIL:
		parseio->parse_badformat++;
		return cvtrtc;

	case CVT_NONE:
		/*
		 * too bad - pretend bad format
		 */
		parseio->parse_badformat++;
		return CVT_NONE;

	case CVT_OK:
		break;

	case CVT_SKIP:
		return CVT_NONE;

	default:
		/* shouldn't happen */
		msyslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"", clockformats[format]->name);
		return CVT_FAIL|cvtrtc;
	}

	if ((t = parse_to_unixtime(&clock_time, &cvtrtc)) == -1)
	{
		return CVT_FAIL|cvtrtc;
	}

	/*
	 * time stamp
	 */
	struct timespec ts = {t, clock_time.usecond * 1000};
	parseio->parse_dtime.parse_time.fp = tspec_stamp_to_lfp(ts);
	
	parseio->parse_dtime.parse_format       = format;

	return updatetimeinfo(parseio, clock_time.flags);
}
Exemplo n.º 2
0
static void
process_pps(
	peerT      * const peer ,
	json_ctx   * const jctx ,
	const l_fp * const rtime)
{
	clockprocT * const pp = peer->procptr;
	gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr;

	struct timespec ts;
		
	errno = 0;
	ts.tv_sec = (time_t)json_object_lookup_int(
		jctx, 0, "clock_sec");
	if (up->fl_nsec)
		ts.tv_nsec = json_object_lookup_int(
			jctx, 0, "clock_nsec");
	else
		ts.tv_nsec = json_object_lookup_int(
			jctx, 0, "clock_musec") * 1000;

	if (0 != errno)
		goto fail;

	up->pps_local = *rtime;
	/* get fudged receive time */
	up->pps_recvt = tspec_stamp_to_lfp(ts);
	L_SUB(&up->pps_recvt, &up->pps_fudge);

	/* map to next full second as reference time stamp */
	up->pps_stamp = up->pps_recvt;
	L_ADDUF(&up->pps_stamp, 0x80000000u);
	up->pps_stamp.l_uf = 0;
	
	pp->lastrec = up->pps_stamp;

	DPRINTF(2, ("GPSD_JSON(%d): process_pps, stamp='%s', recvt='%s'\n", 
		    up->unit,
		    gmprettydate(&up->pps_stamp),
		    gmprettydate(&up->pps_recvt)));
	
	/* When we have a time pulse, clear the TPV flag: the
	 * PPS is only valid for the >NEXT< TPV value!
	 */
	up->fl_pps = -1;
	up->fl_tpv =  0;
	return;

  fail:
	DPRINTF(2, ("GPSD_JSON(%d): process_pps FAILED, nsec=%d stamp='%s', recvt='%s'\n",
		    up->unit, up->fl_nsec,
		    gmprettydate(&up->pps_stamp),
		    gmprettydate(&up->pps_recvt)));
	up->tc_breply += 1;
}
Exemplo n.º 3
0
int
step_systime(
	double step
	)
{
	time_t pivot; /* for ntp era unfolding */
	struct timeval timetv, tvlast, tvdiff;
	struct timespec timets;
	struct calendar jd;
	l_fp fp_ofs, fp_sys; /* offset and target system time in FP */

	/*
	 * Get pivot time for NTP era unfolding. Since we don't step
	 * very often, we can afford to do the whole calculation from
	 * scratch. And we're not in the time-critical path yet.
	 */
#if SIZEOF_TIME_T > 4
	/*
	 * This code makes sure the resulting time stamp for the new
	 * system time is in the 2^32 seconds starting at 1970-01-01,
	 * 00:00:00 UTC.
	 */
	pivot = 0x80000000;
#if USE_COMPILETIME_PIVOT
	/*
	 * Add the compile time minus 10 years to get a possible target
	 * area of (compile time - 10 years) to (compile time + 126
	 * years).  This should be sufficient for a given binary of
	 * NTPD.
	 */
	if (ntpcal_get_build_date(&jd)) {
		jd.year -= 10;
		pivot += ntpcal_date_to_time(&jd);
	} else {
		msyslog(LOG_ERR,
			"step-systime: assume 1970-01-01 as build date");
	}
#else
	UNUSED_LOCAL(jd);
#endif /* USE_COMPILETIME_PIVOT */
#else
	UNUSED_LOCAL(jd);
	/* This makes sure the resulting time stamp is on or after
	 * 1969-12-31/23:59:59 UTC and gives us additional two years,
	 * from the change of NTP era in 2036 to the UNIX rollover in
	 * 2038. (Minus one second, but that won't hurt.) We *really*
	 * need a longer 'time_t' after that!  Or a different baseline,
	 * but that would cause other serious trouble, too.
	 */
	pivot = 0x7FFFFFFF;
#endif

	/* get the complete jump distance as l_fp */
	DTOLFP(sys_residual, &fp_sys);
	DTOLFP(step,         &fp_ofs);
	L_ADD(&fp_ofs, &fp_sys);

	/* ---> time-critical path starts ---> */

	/* get the current time as l_fp (without fuzz) and as struct timeval */
	get_ostime(&timets);
	fp_sys = tspec_stamp_to_lfp(timets);
	tvlast.tv_sec = timets.tv_sec;
	tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;

	/* get the target time as l_fp */
	L_ADD(&fp_sys, &fp_ofs);

	/* unfold the new system time */
	timetv = lfp_stamp_to_tval(fp_sys, &pivot);

	/* now set new system time */
	if (ntp_set_tod(&timetv, NULL) != 0) {
		msyslog(LOG_ERR, "step-systime: %m");
		return FALSE;
	}

	/* <--- time-critical path ended with 'ntp_set_tod()' <--- */

	sys_residual = 0;
	lamport_violated = (step < 0);
	if (step_callback)
		(*step_callback)();

#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...
	 */
	tvdiff = abs_tval(sub_tval(timetv, tvlast));
	if (tvdiff.tv_sec > 0) {
#ifdef HAVE_UTMP_H
		struct utmp ut;
#endif
#ifdef HAVE_UTMPX_H
		struct utmpx utx;
#endif

#ifdef HAVE_UTMP_H
		ZERO(ut);
#endif
#ifdef HAVE_UTMPX_H
		ZERO(utx);
#endif

		/* UTMP */

#ifdef UPDATE_UTMP
# ifdef HAVE_PUTUTLINE
#  ifndef _PATH_UTMP
#   define _PATH_UTMP UTMP_FILE
#  endif
		utmpname(_PATH_UTMP);
		ut.ut_type = OLD_TIME;
		strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
		ut.ut_time = tvlast.tv_sec;
		setutent();
		pututline(&ut);
		ut.ut_type = NEW_TIME;
		strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line));
		ut.ut_time = timetv.tv_sec;
		setutent();
		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;
		strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
		utx.ut_tv = tvlast;
		setutxent();
		pututxline(&utx);
		utx.ut_type = NEW_TIME;
		strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line));
		utx.ut_tv = timetv;
		setutxent();
		pututxline(&utx);
		endutxent();
# else /* not HAVE_PUTUTXLINE */
# endif /* not HAVE_PUTUTXLINE */
#endif /* UPDATE_UTMPX */

		/* WTMP */

#ifdef UPDATE_WTMP
# ifdef HAVE_PUTUTLINE
#  ifndef _PATH_WTMP
#   define _PATH_WTMP WTMP_FILE
#  endif
		utmpname(_PATH_WTMP);
		ut.ut_type = OLD_TIME;
		strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
		ut.ut_time = tvlast.tv_sec;
		setutent();
		pututline(&ut);
		ut.ut_type = NEW_TIME;
		strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line));
		ut.ut_time = timetv.tv_sec;
		setutent();
		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 = tvlast;
		strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
#  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;
		strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line));
#  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 TRUE;
}
Exemplo n.º 4
0
/*
 * get_systime - return system time in NTP timestamp format.
 */
void
get_systime(
	l_fp *now		/* system time */
	)
{
	static struct timespec	ts_prev;	/* prior os time */
	static l_fp		lfp_prev;	/* prior result */
	static double		dfuzz_prev;	/* prior fuzz */
	struct timespec ts;	/* seconds and nanoseconds */
	struct timespec ts_min;	/* earliest permissible */
	struct timespec ts_lam;	/* lamport fictional increment */
	struct timespec ts_prev_log;	/* for msyslog only */
	double	dfuzz;
	double	ddelta;
	l_fp	result;
	l_fp	lfpfuzz;
	l_fp	lfpdelta;

	get_ostime(&ts);
	DEBUG_REQUIRE(systime_init_done);
	ENTER_GET_SYSTIME_CRITSEC();

	/*
	 * After default_get_precision() has set a nonzero sys_fuzz,
	 * ensure every reading of the OS clock advances by at least
	 * sys_fuzz over the prior reading, thereby assuring each
	 * fuzzed result is strictly later than the prior.  Limit the
	 * necessary fiction to 1 second.
	 */
	if (!USING_SIGIO()) {
		ts_min = add_tspec_ns(ts_prev, sys_fuzz_nsec);
		if (cmp_tspec(ts, ts_min) < 0) {
			ts_lam = sub_tspec(ts_min, ts);
			if (ts_lam.tv_sec > 0 && !lamport_violated) {
				msyslog(LOG_ERR,
					"get_systime Lamport advance exceeds one second (%.9f)",
					ts_lam.tv_sec +
					    1e-9 * ts_lam.tv_nsec);
				exit(1);
			}
			if (!lamport_violated)
				ts = ts_min;
		}
		ts_prev_log = ts_prev;
		ts_prev = ts;
	} else {
		/*
		 * Quiet "ts_prev_log.tv_sec may be used uninitialized"
		 * warning from x86 gcc 4.5.2.
		 */
		ZERO(ts_prev_log);
	}

	/* convert from timespec to l_fp fixed-point */
	result = tspec_stamp_to_lfp(ts);

	/*
	 * Add in the fuzz.
	 */
	dfuzz = ntp_random() * 2. / FRAC * sys_fuzz;
	DTOLFP(dfuzz, &lfpfuzz);
	L_ADD(&result, &lfpfuzz);

	/*
	 * Ensure result is strictly greater than prior result (ignoring
	 * sys_residual's effect for now) once sys_fuzz has been
	 * determined.
	 */
	if (!USING_SIGIO()) {
		if (!L_ISZERO(&lfp_prev) && !lamport_violated) {
			if (!L_ISGTU(&result, &lfp_prev) &&
			    sys_fuzz > 0.) {
				msyslog(LOG_ERR, "ts_prev %s ts_min %s",
					tspectoa(ts_prev_log),
					tspectoa(ts_min));
				msyslog(LOG_ERR, "ts %s", tspectoa(ts));
				msyslog(LOG_ERR, "sys_fuzz %ld nsec, prior fuzz %.9f",
					sys_fuzz_nsec, dfuzz_prev);
				msyslog(LOG_ERR, "this fuzz %.9f",
					dfuzz);
				lfpdelta = lfp_prev;
				L_SUB(&lfpdelta, &result);
				LFPTOD(&lfpdelta, ddelta);
				msyslog(LOG_ERR,
					"prev get_systime 0x%x.%08x is %.9f later than 0x%x.%08x",
					lfp_prev.l_ui, lfp_prev.l_uf,
					ddelta, result.l_ui, result.l_uf);
			}
		}
		lfp_prev = result;
		dfuzz_prev = dfuzz;
		if (lamport_violated) 
			lamport_violated = FALSE;
	}
	LEAVE_GET_SYSTIME_CRITSEC();
	*now = result;
}
Exemplo n.º 5
0
/*
 * shm_timer - called once every second.
 *
 * This tries to grab a sample from the SHM segment, filtering bad ones
 */
static void
shm_timer(
	int unit,
	struct peer *peer
	)
{
	struct refclockproc * const pp = peer->procptr;
	struct shmunit *      const up = pp->unitptr;

	volatile struct shmTime *shm;

	l_fp tsrcv;
	l_fp tsref;
	int c;

	/* for formatting 'a_lastcode': */
	struct calendar cd;
	time_t tt;
	vint64 ts;

	enum segstat_t status;
	struct shm_stat_t shm_stat;

	up->ticks++;
	if ((shm = up->shm) == NULL) {
		/* try to map again - this may succeed if meanwhile some-
		body has ipcrm'ed the old (unaccessible) shared mem segment */
		shm = up->shm = getShmTime(unit, up->forall);
		if (shm == NULL) {
			DPRINTF(1, ("%s: no SHM segment\n",
				    refnumtoa(&peer->srcadr)));
			return;
		}
	}

	/* query the segment, atomically */
	status = shm_query(shm, &shm_stat);

	switch (status) {
	case OK:
	    DPRINTF(2, ("%s: SHM type %d sample\n",
			refnumtoa(&peer->srcadr), shm_stat.mode));
	    break;
	case NO_SEGMENT:
	    /* should never happen, but is harmless */
	    return;
	case NOT_READY:
	    DPRINTF(1, ("%s: SHM not ready\n",refnumtoa(&peer->srcadr)));
	    up->notready++;
	    return;
	case BAD_MODE:
	    DPRINTF(1, ("%s: SHM type blooper, mode=%d\n",
			refnumtoa(&peer->srcadr), shm->mode));
	    up->bad++;
	    msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",
		     shm->mode);
	    return;
	case CLASH:
	    DPRINTF(1, ("%s: type 1 access clash\n",
			refnumtoa(&peer->srcadr)));
	    msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
	    up->clash++;
	    return;
	default:
	    DPRINTF(1, ("%s: internal error, unknown SHM fetch status\n",
			refnumtoa(&peer->srcadr)));
	    msyslog (LOG_NOTICE, "internal error, unknown SHM fetch status");
	    up->bad++;
	    return;
	}


	/* format the last time code in human-readable form into
	 * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible
	 * tv_sec". I can't find a base for this claim, but we can work
	 * around that potential problem. BTW, simply casting a pointer
	 * is a receipe for disaster on some architectures.
	 */
	tt = (time_t)shm_stat.tvt.tv_sec;
	ts = time_to_vint64(&tt);
	ntpcal_time_to_date(&cd, &ts);
		
	/* add ntpq -c cv timecode in ISO 8601 format */
	c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
		     "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ",
		     cd.year, cd.month, cd.monthday,
		     cd.hour, cd.minute, cd.second,
		     (long)shm_stat.tvt.tv_nsec);
	pp->lencode = ((size_t)c < sizeof(pp->a_lastcode)) ? c : 0;

	/* check 1: age control of local time stamp */
	tt = shm_stat.tvc.tv_sec - shm_stat.tvr.tv_sec;
	if (tt < 0 || tt > up->max_delay) {
		DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n",
			    refnumtoa(&peer->srcadr), (long long)tt));
		up->bad++;
		msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds",
			 (long long)tt);
		return;
	}

	/* check 2: delta check */
	tt = shm_stat.tvr.tv_sec - shm_stat.tvt.tv_sec - (shm_stat.tvr.tv_nsec < shm_stat.tvt.tv_nsec);
	if (tt < 0)
		tt = -tt;
	if (up->max_delta > 0 && tt > up->max_delta) {
		DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n",
			    refnumtoa(&peer->srcadr), (long long)tt));
		up->bad++;
		msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n",
			 (long long)tt);
		return;
	}

	/* if we really made it to this point... we're winners! */
	DPRINTF(2, ("%s: SHM feeding data\n",
		    refnumtoa(&peer->srcadr)));
	tsrcv = tspec_stamp_to_lfp(shm_stat.tvr);
	tsref = tspec_stamp_to_lfp(shm_stat.tvt);
	pp->leap = shm_stat.leap;
	peer->precision = shm_stat.precision;
	refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1);
	up->good++;
}