]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/timesync/timesyncd-manager.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / timesync / timesyncd-manager.c
index a455652a27ffc15bfdf4c6961343c4e3bb096686..d5eaf64e74e0654b81ca95b0899cf7bfe4f9c445 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
 /* expected accuracy of time synchronization; used to adjust the poll interval */
 #define NTP_ACCURACY_SEC                0.2
 
-/*
- * "A client MUST NOT under any conditions use a poll interval less
- * than 15 seconds."
- */
-#define NTP_POLL_INTERVAL_MIN_SEC       32
-#define NTP_POLL_INTERVAL_MAX_SEC       2048
-
 /*
  * Maximum delta in seconds which the system clock is gradually adjusted
- * (slew) to approach the network time. Deltas larger that this are set by
+ * (slewed) to approach the network time. Deltas larger that this are set by
  * letting the system time jump. The kernel's limit for adjtime is 0.5s.
  */
 #define NTP_MAX_ADJUST                  0.4
@@ -80,8 +74,8 @@
 #define NTP_FIELD_MODE(f)               ((f) & 7)
 #define NTP_FIELD(l, v, m)              (((l) << 6) | ((v) << 3) | (m))
 
-/* Maximum acceptable root distance in seconds. */
-#define NTP_MAX_ROOT_DISTANCE           5.0
+/* Default of maximum acceptable root distance in microseconds. */
+#define NTP_MAX_ROOT_DISTANCE           (5 * USEC_PER_SEC)
 
 /* Maximum number of missed replies before selecting another source. */
 #define NTP_MAX_MISSED_REPLIES          2
@@ -204,10 +198,10 @@ static int manager_send_request(Manager *m) {
 
         /* re-arm timer with increasing timeout, in case the packets never arrive back */
         if (m->retry_interval > 0) {
-                if (m->retry_interval < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
+                if (m->retry_interval < m->poll_interval_max_usec)
                         m->retry_interval *= 2;
         } else
-                m->retry_interval = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
+                m->retry_interval = m->poll_interval_min_usec;
 
         r = manager_arm_timer(m, m->retry_interval);
         if (r < 0)
@@ -330,11 +324,13 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
                 tmx.esterror = 0;
                 log_debug("  adjust (slew): %+.3f sec", offset);
         } else {
-                tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET;
+                tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET | ADJ_MAXERROR | ADJ_ESTERROR;
 
                 /* 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;
+                tmx.maxerror = 0;
+                tmx.esterror = 0;
 
                 /* the kernel expects -0.3s as {-1, 7000.000.000} */
                 if (tmx.time.tv_usec < 0) {
@@ -371,15 +367,15 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
                 return -errno;
 
         /* If touch fails, there isn't much we can do. Maybe it'll work next time. */
-        (void) touch("/var/lib/systemd/clock");
+        (void) touch("/var/lib/systemd/timesync/clock");
 
         m->drift_ppm = tmx.freq / 65536;
 
         log_debug("  status       : %04i %s\n"
-                  "  time now     : %li.%03"PRI_USEC"\n"
-                  "  constant     : %li\n"
+                  "  time now     : %"PRI_TIME".%03"PRI_USEC"\n"
+                  "  constant     : %"PRI_TIMEX"\n"
                   "  offset       : %+.3f sec\n"
-                  "  freq offset  : %+li (%i ppm)\n",
+                  "  freq offset  : %+"PRI_TIMEX" (%i ppm)\n",
                   tmx.status, tmx.status & STA_UNSYNC ? "unsync" : "sync",
                   tmx.time.tv_sec, tmx.time.tv_usec / NSEC_PER_MSEC,
                   tmx.constant,
@@ -444,27 +440,27 @@ static void manager_adjust_poll(Manager *m, double offset, bool spike) {
         assert(m);
 
         if (m->poll_resync) {
-                m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
+                m->poll_interval_usec = m->poll_interval_min_usec;
                 m->poll_resync = false;
                 return;
         }
 
         /* set to minimal poll interval */
         if (!spike && fabs(offset) > NTP_ACCURACY_SEC) {
-                m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
+                m->poll_interval_usec = m->poll_interval_min_usec;
                 return;
         }
 
         /* increase polling interval */
         if (fabs(offset) < NTP_ACCURACY_SEC * 0.25) {
-                if (m->poll_interval_usec < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
+                if (m->poll_interval_usec < m->poll_interval_max_usec)
                         m->poll_interval_usec *= 2;
                 return;
         }
 
         /* decrease polling interval */
         if (spike || fabs(offset) > NTP_ACCURACY_SEC * 0.75) {
-                if (m->poll_interval_usec > NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC)
+                if (m->poll_interval_usec > m->poll_interval_min_usec)
                         m->poll_interval_usec /= 2;
                 return;
         }
@@ -492,7 +488,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 .msg_namelen = sizeof(server_addr),
         };
         struct cmsghdr *cmsg;
-        struct timespec *recv_time;
+        struct timespec *recv_time = NULL;
         ssize_t len;
         double origin, receive, trans, dest;
         double delay, offset;
@@ -531,7 +527,6 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 return 0;
         }
 
-        recv_time = NULL;
         CMSG_FOREACH(cmsg, &msghdr) {
                 if (cmsg->cmsg_level != SOL_SOCKET)
                         continue;
@@ -556,7 +551,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
 
         /* check our "time cookie" (we just stored nanoseconds in the fraction field) */
         if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 ||
-            be32toh(ntpmsg.origin_time.frac) != m->trans_time.tv_nsec) {
+            be32toh(ntpmsg.origin_time.frac) != (unsigned long) m->trans_time.tv_nsec) {
                 log_debug("Invalid reply; not our transmit time. Ignoring.");
                 return 0;
         }
@@ -586,7 +581,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
         }
 
         root_distance = ntp_ts_short_to_d(&ntpmsg.root_delay) / 2 + ntp_ts_short_to_d(&ntpmsg.root_dispersion);
-        if (root_distance > NTP_MAX_ROOT_DISTANCE) {
+        if (root_distance > (double) m->max_root_distance_usec / (double) USEC_PER_SEC) {
                 log_debug("Server has too large root distance. Disconnecting.");
                 return manager_connect(m);
         }
@@ -741,7 +736,7 @@ static int manager_begin(Manager *m) {
         m->good = false;
         m->missed_replies = NTP_MAX_MISSED_REPLIES;
         if (m->poll_interval_usec == 0)
-                m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
+                m->poll_interval_usec = m->poll_interval_min_usec;
 
         server_address_pretty(m->current_server_address, &pretty);
         log_debug("Connecting to time server %s (%s).", strna(pretty), m->current_server_name->string);
@@ -919,7 +914,7 @@ int manager_connect(Manager *m) {
                                 m->exhausted_servers = true;
 
                                 /* Increase the polling interval */
-                                if (m->poll_interval_usec < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
+                                if (m->poll_interval_usec < m->poll_interval_max_usec)
                                         m->poll_interval_usec *= 2;
 
                                 return 0;
@@ -1010,6 +1005,7 @@ static int manager_network_read_link_servers(Manager *m) {
         _cleanup_strv_free_ char **ntp = NULL;
         ServerName *n, *nx;
         char **i;
+        bool changed = false;
         int r;
 
         assert(m);
@@ -1035,14 +1031,18 @@ static int manager_network_read_link_servers(Manager *m) {
                         r = server_name_new(m, NULL, SERVER_LINK, *i);
                         if (r < 0)
                                 goto clear;
+
+                        changed = true;
                 }
         }
 
         LIST_FOREACH_SAFE(names, n, nx, m->link_servers)
-                if (n->marked)
+                if (n->marked) {
                         server_name_free(n);
+                        changed = true;
+                }
 
-        return 0;
+        return changed;
 
 clear:
         manager_flush_server_names(m, SERVER_LINK);
@@ -1051,14 +1051,14 @@ clear:
 
 static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
         Manager *m = userdata;
-        bool connected, online;
+        bool changed, connected, online;
         int r;
 
         assert(m);
 
         sd_network_monitor_flush(m->network_monitor);
 
-        manager_network_read_link_servers(m);
+        changed = !!manager_network_read_link_servers(m);
 
         /* check if the machine is online */
         online = network_is_online();
@@ -1070,7 +1070,7 @@ static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t re
                 log_info("No network connectivity, watching for changes.");
                 manager_disconnect(m);
 
-        } else if (!connected && online) {
+        } else if (!connected && online && changed) {
                 log_info("Network configuration changed, trying to establish connection.");
 
                 if (m->current_server_address)
@@ -1090,6 +1090,10 @@ static int manager_network_monitor_listen(Manager *m) {
         assert(m);
 
         r = sd_network_monitor_new(&m->network_monitor, NULL);
+        if (r == -ENOENT) {
+                log_info("systemd does not appear to be running, not listening for systemd-networkd events.");
+                return 0;
+        }
         if (r < 0)
                 return r;
 
@@ -1118,14 +1122,14 @@ int manager_new(Manager **ret) {
         if (!m)
                 return -ENOMEM;
 
+        m->max_root_distance_usec = NTP_MAX_ROOT_DISTANCE;
+        m->poll_interval_min_usec = NTP_POLL_INTERVAL_MIN_USEC;
+        m->poll_interval_max_usec = NTP_POLL_INTERVAL_MAX_USEC;
+
         m->server_socket = m->clock_watch_fd = -1;
 
         RATELIMIT_INIT(m->ratelimit, RATELIMIT_INTERVAL_USEC, RATELIMIT_BURST);
 
-        r = manager_parse_server_string(m, SERVER_FALLBACK, NTP_SERVERS);
-        if (r < 0)
-                return r;
-
         r = sd_event_default(&m->event);
         if (r < 0)
                 return r;
@@ -1149,8 +1153,7 @@ int manager_new(Manager **ret) {
 
         manager_network_read_link_servers(m);
 
-        *ret = m;
-        m = NULL;
+        *ret = TAKE_PTR(m);
 
         return 0;
 }