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); }
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"); } }
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); }
/* 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; }