Example #1
0
void
ntpd_settime(double d)
{
	struct timeval	tv, curtime;
	char		buf[80];
	time_t		tval;

	if (gettimeofday(&curtime, NULL) == -1) {
		log_warn("gettimeofday");
		return;
	}
	d_to_tv(d, &tv);
	curtime.tv_usec += tv.tv_usec + 1000000;
	curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000);
	curtime.tv_usec %= 1000000;

	if (settimeofday(&curtime, NULL) == -1) {
		log_warn("settimeofday");
		return;
	}
	tval = curtime.tv_sec;
	strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y",
	    localtime(&tval));
	log_info("set local clock to %s (offset %fs)", buf, d);
}
Example #2
0
void
show_status_msg(struct imsg *imsg)
{
	struct ctl_show_status	*cstatus;
	double			 clock_offset;
	struct timeval		 tv;

	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_status))
		fatalx("invalid IMSG_CTL_SHOW_STATUS received");

	cstatus = (struct ctl_show_status *)imsg->data;

	if (cstatus->peercnt > 0)
		printf("%d/%d peers valid, ",
		    cstatus->valid_peers, cstatus->peercnt);

	if (cstatus->sensorcnt > 0)
		printf("%d/%d sensors valid, ",
		    cstatus->valid_sensors, cstatus->sensorcnt);

	if (cstatus->constraint_median) {
		tv.tv_sec = cstatus->constraint_median +
		    (getmonotime() - cstatus->constraint_last);
		tv.tv_usec = 0;
		d_to_tv(gettime_from_timeval(&tv) - gettime(), &tv);
		printf("constraint offset %llds", (long long)tv.tv_sec);
		if (cstatus->constraint_errors)
			printf(" (%d errors)",
			    cstatus->constraint_errors);
		printf(", ");
	}

	if (cstatus->peercnt + cstatus->sensorcnt == 0)
		printf("no peers and no sensors configured\n");

	if (cstatus->synced == 1)
		printf("clock synced, stratum %u\n", cstatus->stratum);
	else {
		printf("clock unsynced");
		clock_offset = cstatus->clock_offset < 0 ?
		    -1.0 * cstatus->clock_offset : cstatus->clock_offset;
		if (clock_offset > 5e-7)
			printf(", clock offset is %.3fms\n",
			    cstatus->clock_offset);
		else
			printf("\n");
	}
}
Example #3
0
int
ntpd_adjtime(double d)
{
	struct timeval	tv, olddelta;
	int		synced = 0;
	static int	firstadj = 1;

	if (d >= (double)LOG_NEGLIGEE / 1000 ||
	    d <= -1 * (double)LOG_NEGLIGEE / 1000)
		log_info("adjusting local clock by %fs", d);
	else
		log_debug("adjusting local clock by %fs", d);
	d_to_tv(d, &tv);
	if (adjtime(&tv, &olddelta) == -1)
		log_warn("adjtime failed");
	else if (!firstadj && olddelta.tv_sec == 0 && olddelta.tv_usec == 0)
		synced = 1;
	firstadj = 0;
	return (synced);
}
Example #4
0
/* wake up when the system time changes underneath us */
static int sntp_clock_watch_setup(SNTPContext *sntp) {
        struct itimerspec its = { .it_value.tv_sec = TIME_T_MAX };
        _cleanup_close_ int fd = -1;
        sd_event *e;
        sd_event_source *source;
        int r;

        assert(sntp);
        assert(sntp->event_receive);

        fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
        if (fd < 0) {
                log_error("Failed to create timerfd: %m");
                return -errno;
        }

        if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
                log_error("Failed to set up timerfd: %m");
                return -errno;
        }

        e = sd_event_source_get_event(sntp->event_receive);
        r = sd_event_add_io(e, &source, fd, EPOLLIN, sntp_clock_watch, sntp);
        if (r < 0) {
                log_error("Failed to create clock watch event source: %s", strerror(-r));
                return r;
        }

        sd_event_source_unref(sntp->event_clock_watch);
        sntp->event_clock_watch = source;

        if (sntp->clock_watch_fd >= 0)
                close(sntp->clock_watch_fd);
        sntp->clock_watch_fd = fd;
        fd = -1;

        return 0;
}

static int sntp_adjust_clock(SNTPContext *sntp, double offset, int leap_sec) {
        struct timex tmx = {};
        int r;

        /*
         * For small deltas, tell the kernel to gradually adjust the system
         * clock to the NTP time, larger deltas are just directly set.
         *
         * Clear STA_UNSYNC, it will enable the kernel's 11-minute mode, which
         * syncs the system time periodically to the hardware clock.
         */
        if (offset < NTP_MAX_ADJUST && offset > -NTP_MAX_ADJUST) {
                tmx.modes |= ADJ_STATUS | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR;
                tmx.status = STA_PLL;
                tmx.offset = offset * 1000 * 1000;
                tmx.constant = log2i(sntp->poll_interval_usec / USEC_PER_SEC) - 6;
                tmx.maxerror = 0;
                tmx.esterror = 0;
                log_debug("  adjust (slew): %+f sec\n", (double)tmx.offset / USEC_PER_SEC);
        } else {
                tmx.modes = ADJ_SETOFFSET;
                d_to_tv(offset, &tmx.time);

                sntp->jumped = true;
                log_debug("  adjust (jump): %+f sec\n", tv_to_d(&tmx.time));
        }

        switch (leap_sec) {
        case 1:
                tmx.status |= STA_INS;
                break;
        case -1:
                tmx.status |= STA_DEL;
                break;
        }

        r = clock_adjtime(CLOCK_REALTIME, &tmx);
        if (r < 0)
                return r;

        log_debug("  status       : %04i %s\n"
                  "  time now     : %li.%06li\n"
                  "  constant     : %li\n"
                  "  offset       : %+f sec\n"
                  "  freq offset  : %+li (%+.3f ppm)\n",
                  tmx.status, tmx.status & STA_UNSYNC ? "" : "sync",
                  tmx.time.tv_sec, tmx.time.tv_usec,
                  tmx.constant,
                  (double)tmx.offset / USEC_PER_SEC,
                  tmx.freq, (double)tmx.freq / 65536);

        return 0;
}

static bool sntp_sample_spike_detection(SNTPContext *sntp, double offset, double delay) {
        unsigned int i, idx_cur, idx_new, idx_min;
        double jitter;
        double j;

        /* store the current data in our samples array */
        idx_cur = sntp->samples_idx;
        idx_new = (idx_cur + 1) % ELEMENTSOF(sntp->samples);
        sntp->samples_idx = idx_new;
        sntp->samples[idx_new].offset = offset;
        sntp->samples[idx_new].delay = delay;

        sntp->packet_count++;
        jitter = sntp->samples_jitter;

        /* calculate new jitter value from the RMS differences relative to the lowest delay sample */
        for (idx_min = idx_cur, i = 0; i < ELEMENTSOF(sntp->samples); i++)
                if (sntp->samples[i].delay > 0 && sntp->samples[i].delay < sntp->samples[idx_min].delay)
                        idx_min = i;

        j = 0;
        for (i = 0; i < ELEMENTSOF(sntp->samples); i++)
                j += square(sntp->samples[i].offset - sntp->samples[idx_min].offset);
        sntp->samples_jitter = sqrt(j / (ELEMENTSOF(sntp->samples) - 1));

        /* ignore samples when resyncing */
        if (sntp->poll_resync)
                return false;

        /* always accept offset if we are farther off than the round-trip delay */
        if (fabs(offset) > delay)
                return false;

        /* we need a few samples before looking at them */
        if (sntp->packet_count < 4)
                return false;

        /* do not accept anything worse than the maximum possible error of the best sample */
        if (fabs(offset) > sntp->samples[idx_min].delay)
                return true;

        /* compare the difference between the current offset to the previous offset and jitter */
        return fabs(offset - sntp->samples[idx_cur].offset) > 3 * jitter;
}