chiark / gitweb /
timesync: always initialize structs when declaring them as far as possible with conts...
[elogind.git] / src / timesync / timesyncd.c
index b6e78228bbab1236d170f2646f695e646713da93..72dcf0b058223155806d614e9c2bbb25d76d7ada 100644 (file)
@@ -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("%s: interval/offset/delay/jitter %llu/%+f/%f/%f",
-                 m->server, m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter);
-
         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;
 
@@ -773,16 +781,13 @@ int main(int argc, char *argv[]) {
 
         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=Connected to %s", server);
+        sd_notifyf(false, "STATUS=Using Time Server: %s", server);
 
         r = sd_event_loop(m->event);
         if (r < 0)