X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Ftimesync%2Ftimesyncd.c;h=72dcf0b058223155806d614e9c2bbb25d76d7ada;hb=5f8cfaee52745c885ea4148cd720c71ee5efc742;hp=5bd61dd07c6061b1d6f9a295b2ecedd379a104ab;hpb=687ed1237b20a6db174fd0b372df20fa9a3a23c2;p=elogind.git diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 5bd61dd07..72dcf0b05 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -37,6 +37,7 @@ #include "util.h" #include "sparse-endian.h" #include "log.h" +#include "socket-util.h" #include "sd-event.h" #include "sd-daemon.h" @@ -111,7 +112,7 @@ struct Manager { /* peer */ sd_event_source *event_receive; char *server; - struct sockaddr_in server_addr; + union sockaddr_union server_addr; int server_socket; uint64_t packet_count; @@ -136,6 +137,7 @@ struct Manager { /* last change */ bool jumped; + int drift_ppm; /* watch for time changes */ sd_event_source *event_clock_watch; @@ -154,23 +156,12 @@ static double ntp_ts_to_d(const struct ntp_ts *ts) { return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX); } -static double tv_to_d(const struct timeval *tv) { - return tv->tv_sec + (1.0e-6 * tv->tv_usec); -} - static double ts_to_d(const struct timespec *ts) { return ts->tv_sec + (1.0e-9 * ts->tv_nsec); } -static void d_to_tv(double d, struct timeval *tv) { - tv->tv_sec = (long)d; - tv->tv_usec = (d - tv->tv_sec) * 1000 * 1000; - - /* the kernel expects -0.3s as {-1, 7000.000} */ - if (tv->tv_usec < 0) { - tv->tv_sec -= 1; - tv->tv_usec += 1000 * 1000; - } +static double tv_to_d(const struct timeval *tv) { + return tv->tv_sec + (1.0e-6 * tv->tv_usec); } static double square(double d) { @@ -178,19 +169,24 @@ static double square(double d) { } static int sntp_send_request(Manager *m) { - struct ntp_msg ntpmsg = {}; - struct sockaddr_in addr = {}; + struct ntp_msg ntpmsg = { + /* + * "The client initializes the NTP message header, sends the request + * to the server, and strips the time of day from the Transmit + * Timestamp field of the reply. For this purpose, all the NTP + * header fields are set to 0, except the Mode, VN, and optional + * Transmit Timestamp fields." + */ + .field = NTP_FIELD(0, 4, NTP_MODE_CLIENT), + }; + + union sockaddr_union addr = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(123), + }; ssize_t len; int r; - /* - * "The client initializes the NTP message header, sends the request - * to the server, and strips the time of day from the Transmit - * Timestamp field of the reply. For this purpose, all the NTP - * header fields are set to 0, except the Mode, VN, and optional - * Transmit Timestamp fields." - */ - ntpmsg.field = NTP_FIELD(0, 4, NTP_MODE_CLIENT); /* * Set transmit timestamp, remember it; the server will send that back @@ -205,10 +201,8 @@ static int sntp_send_request(Manager *m) { ntpmsg.trans_time.sec = htobe32(m->trans_time.tv_sec + OFFSET_1900_1970); ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec); - addr.sin_family = AF_INET; - addr.sin_port = htobe16(123); - addr.sin_addr.s_addr = inet_addr(m->server); - len = sendto(m->server_socket, &ntpmsg, sizeof(ntpmsg), MSG_DONTWAIT, &addr, sizeof(addr)); + addr.in.sin_addr.s_addr = inet_addr(m->server); + len = sendto(m->server_socket, &ntpmsg, sizeof(ntpmsg), MSG_DONTWAIT, &addr.sa, sizeof(addr.in)); if (len == sizeof(ntpmsg)) { m->pending = true; log_debug("Sent NTP request to: %s", m->server); @@ -293,9 +287,12 @@ static int sntp_clock_watch(sd_event_source *source, int fd, uint32_t revents, v /* wake up when the system time changes underneath us */ static int sntp_clock_watch_setup(Manager *m) { - struct itimerspec its = { .it_value.tv_sec = TIME_T_MAX }; + + struct itimerspec its = { + .it_value.tv_sec = TIME_T_MAX + }; + _cleanup_close_ int fd = -1; - sd_event *e; sd_event_source *source; int r; @@ -313,8 +310,7 @@ static int sntp_clock_watch_setup(Manager *m) { return -errno; } - e = sd_event_source_get_event(m->event_receive); - r = sd_event_add_io(e, &source, fd, EPOLLIN, sntp_clock_watch, m); + r = sd_event_add_io(m->event, &source, fd, EPOLLIN, sntp_clock_watch, m); if (r < 0) { log_error("Failed to create clock watch event source: %s", strerror(-r)); return r; @@ -343,19 +339,28 @@ static int sntp_adjust_clock(Manager *m, double offset, int leap_sec) { * syncs the system time periodically to the hardware clock. */ if (fabs(offset) < NTP_MAX_ADJUST) { - tmx.modes = ADJ_STATUS | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR; + tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR; tmx.status = STA_PLL; - tmx.offset = offset * USEC_PER_SEC; - tmx.constant = log2i(m->poll_interval_usec / USEC_PER_SEC) - 6; + tmx.offset = offset * NSEC_PER_SEC; + tmx.constant = log2i(m->poll_interval_usec / USEC_PER_SEC) - 4; tmx.maxerror = 0; tmx.esterror = 0; - log_debug(" adjust (slew): %+f sec\n", (double)tmx.offset / USEC_PER_SEC); + log_debug(" adjust (slew): %+.3f sec\n", offset); } else { - tmx.modes = ADJ_SETOFFSET; - d_to_tv(offset, &tmx.time); + tmx.modes = ADJ_SETOFFSET | ADJ_NANO; + + /* ADJ_NANO uses nanoseconds in the microseconds field */ + tmx.time.tv_sec = (long)offset; + tmx.time.tv_usec = (offset - tmx.time.tv_sec) * NSEC_PER_SEC; + + /* the kernel expects -0.3s as {-1, 7000.000.000} */ + if (tmx.time.tv_usec < 0) { + tmx.time.tv_sec -= 1; + tmx.time.tv_usec += NSEC_PER_SEC; + } m->jumped = true; - log_debug(" adjust (jump): %+f sec\n", tv_to_d(&tmx.time)); + log_debug(" adjust (jump): %+.3f sec\n", offset); } switch (leap_sec) { @@ -367,21 +372,22 @@ static int sntp_adjust_clock(Manager *m, double offset, int leap_sec) { break; } - //r = clock_adjtime(CLOCK_REALTIME, &tmx); - r = adjtimex(&tmx); + r = clock_adjtime(CLOCK_REALTIME, &tmx); if (r < 0) return r; + m->drift_ppm = tmx.freq / 65536; + log_debug(" status : %04i %s\n" - " time now : %li.%06li\n" + " time now : %li.%03lli\n" " constant : %li\n" - " offset : %+f sec\n" - " freq offset : %+li (%+.3f ppm)\n", + " offset : %+.3f sec\n" + " freq offset : %+li (%i ppm)\n", tmx.status, tmx.status & STA_UNSYNC ? "" : "sync", - tmx.time.tv_sec, tmx.time.tv_usec, + tmx.time.tv_sec, tmx.time.tv_usec / NSEC_PER_MSEC, tmx.constant, - (double)tmx.offset / USEC_PER_SEC, - tmx.freq, (double)tmx.freq / 65536); + (double)tmx.offset / NSEC_PER_SEC, + tmx.freq, m->drift_ppm); return 0; } @@ -474,7 +480,7 @@ static int sntp_receive_response(sd_event_source *source, int fd, uint32_t reven struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(struct timeval))]; } control; - struct sockaddr_in server_addr; + union sockaddr_union server_addr; struct msghdr msghdr = { .msg_iov = &iov, .msg_iovlen = 1, @@ -511,7 +517,7 @@ static int sntp_receive_response(sd_event_source *source, int fd, uint32_t reven return -EINVAL; } - if (m->server_addr.sin_addr.s_addr != server_addr.sin_addr.s_addr) { + if (m->server_addr.in.sin_addr.s_addr != server_addr.in.sin_addr.s_addr) { log_debug("Response from unknown server. Disconnecting."); return -EINVAL; } @@ -601,16 +607,16 @@ static int sntp_receive_response(sd_event_source *source, int fd, uint32_t reven " version : %u\n" " mode : %u\n" " stratum : %u\n" - " precision : %f sec (%d)\n" + " precision : %.6f sec (%d)\n" " reference : %.4s\n" - " origin : %f\n" - " receive : %f\n" - " transmit : %f\n" - " dest : %f\n" - " offset : %+f sec\n" - " delay : %+f sec\n" + " origin : %.3f\n" + " receive : %.3f\n" + " transmit : %.3f\n" + " dest : %.3f\n" + " offset : %+.3f sec\n" + " delay : %+.3f sec\n" " packet count : %"PRIu64"\n" - " jitter : %f%s\n" + " jitter : %.3f%s\n" " poll interval: %llu\n", NTP_FIELD_LEAP(ntpmsg->field), NTP_FIELD_VERSION(ntpmsg->field), @@ -627,15 +633,15 @@ static int sntp_receive_response(sd_event_source *source, int fd, uint32_t reven m->samples_jitter, spike ? " spike" : "", m->poll_interval_usec / USEC_PER_SEC); - log_info("%4llu %+10f %10f %10f%s", - m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, spike ? " spike" : ""); - if (!spike) { r = sntp_adjust_clock(m, offset, leap_sec); if (r < 0) log_error("Failed to call clock_adjtime(): %m"); } + log_info("%s: interval/delta/delay/jitter/drift %llus/%+.3fs/%.3fs/%.3fs/%+ippm%s", + m->server, m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, m->drift_ppm, + spike ? " (ignored)" : ""); r = sntp_arm_timer(m, m->poll_interval_usec); if (r < 0) return r; @@ -659,8 +665,8 @@ static int sntp_server_connect(Manager *m, const char *server) { s = NULL; zero(m->server_addr); - m->server_addr.sin_family = AF_INET; - m->server_addr.sin_addr.s_addr = inet_addr(server); + m->server_addr.in.sin_family = AF_INET; + m->server_addr.in.sin_addr.s_addr = inet_addr(server); m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; @@ -689,8 +695,12 @@ static void sntp_server_disconnect(Manager *m) { } static int sntp_listen_setup(Manager *m) { + + union sockaddr_union addr = { + .in.sin_family = AF_INET, + }; + _cleanup_close_ int fd = -1; - struct sockaddr_in addr; const int on = 1; const int tos = IPTOS_LOWDELAY; int r; @@ -699,9 +709,7 @@ static int sntp_listen_setup(Manager *m) { if (fd < 0) return -errno; - zero(addr); - addr.sin_family = AF_INET; - r = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + r = bind(fd, &addr.sa, sizeof(addr.in)); if (r < 0) return -errno; @@ -771,18 +779,16 @@ int main(int argc, char *argv[]) { if (r < 0) goto out; - //server = "216.239.32.15"; /* time1.google.com */ - //server = "192.53.103.108"; /* ntp1.ptb.de */ - server = "27.54.95.11"; /* au.pool.ntp.org */ + server = "216.239.32.15"; /* time1.google.com */ - sd_notifyf(false, - "READY=1\n" - "STATUS=Connecting to %s", server); + sd_notify(false, "READY=1"); r = sntp_server_connect(m, server); if (r < 0) goto out; + sd_notifyf(false, "STATUS=Using Time Server: %s", server); + r = sd_event_loop(m->event); if (r < 0) goto out;