#include "sd-event.h"
#include "sd-resolve.h"
#include "sd-daemon.h"
+#include "sd-network.h"
+#include "event-util.h"
+#include "network-util.h"
#include "timesyncd.h"
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
}
static int manager_receive_response(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- _cleanup_free_ char *pretty = NULL;
Manager *m = userdata;
struct ntp_msg ntpmsg;
m->event_timeout = sd_event_source_unref(m->event_timeout);
+ if (be32toh(ntpmsg.recv_time.sec) < TIME_EPOCH + OFFSET_1900_1970 ||
+ be32toh(ntpmsg.trans_time.sec) < TIME_EPOCH + OFFSET_1900_1970) {
+ log_debug("Invalid reply, returned times before epoch. Ignoring.");
+ return manager_connect(m);
+ }
+
if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC) {
log_debug("Server is not synchronized. Disconnecting.");
return manager_connect(m);
}
- if (NTP_FIELD_VERSION(ntpmsg.field) != 4 && NTP_FIELD_VERSION(ntpmsg.field) != 3) {
+ if (!IN_SET(NTP_FIELD_VERSION(ntpmsg.field), 3, 4)) {
log_debug("Response NTPv%d. Disconnecting.", NTP_FIELD_VERSION(ntpmsg.field));
return manager_connect(m);
}
log_error("Failed to call clock_adjtime(): %m");
}
- sockaddr_pretty(&m->current_server_address->sockaddr.sa, m->current_server_address->socklen, true, &pretty);
- log_info("%s (%s): interval/delta/delay/jitter/drift %llus/%+.3fs/%.3fs/%.3fs/%+ippm%s",
- strna(pretty), m->current_server_name->string, m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, m->drift_ppm,
+ log_info("interval/delta/delay/jitter/drift %llus/%+.3fs/%.3fs/%.3fs/%+ippm%s",
+ m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, m->drift_ppm,
spike ? " (ignored)" : "");
r = manager_arm_timer(m, m->poll_interval_usec);
m->resolve_query = sd_resolve_query_unref(m->resolve_query);
if (ret != 0) {
- log_error("Failed to resolve %s: %s", m->current_server_name->string, gai_strerror(ret));
+ log_info("Failed to resolve %s: %s", m->current_server_name->string, gai_strerror(ret));
/* Try next host */
return manager_connect(m);
sd_event_source_unref(m->event_retry);
+ sd_event_source_unref(m->network_event_source);
+ sd_network_monitor_unref(m->network_monitor);
+
sd_resolve_unref(m->resolve);
sd_event_unref(m->event);
return r;
}
+static bool network_is_online(void) {
+ _cleanup_free_ char *state = NULL;
+ int r;
+
+ r = sd_network_get_operational_state(&state);
+ if (r >= 0 && streq("carrier", state))
+ return true;
+ else
+ return false;
+}
+
+static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents,
+ void *userdata) {
+ Manager *m = userdata;
+ bool connected, online;
+ int r;
+
+ assert(m);
+
+ /* check if the machine is online */
+ online = network_is_online();
+
+ /* check if the client is currently connected */
+ connected = (m->server_socket != -1);
+
+ if (connected && !online) {
+ log_info("No network connectivity. Suspending.");
+ manager_disconnect(m);
+ } else if (!connected && online) {
+ log_info("Network connectivity detected. Resuming.");
+ if (m->current_server_address) {
+ r = manager_begin(m);
+ if (r < 0)
+ return r;
+ } else {
+ r = manager_connect(m);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ sd_network_monitor_flush(m->network_monitor);
+
+ return 0;
+}
+
+static int manager_network_monitor_listen(Manager *m) {
+ _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
+ _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
+ int r, fd, events;
+
+ r = sd_network_monitor_new(NULL, &monitor);
+ if (r < 0)
+ return r;
+
+ fd = sd_network_monitor_get_fd(monitor);
+ if (fd < 0)
+ return fd;
+
+ events = sd_network_monitor_get_events(monitor);
+ if (events < 0)
+ return events;
+
+ r = sd_event_add_io(m->event, &event_source, fd, events,
+ &manager_network_event_handler, m);
+ if (r < 0)
+ return r;
+
+ m->network_monitor = monitor;
+ m->network_event_source = event_source;
+ monitor = NULL;
+ event_source = NULL;
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
_cleanup_manager_free_ Manager *m = NULL;
int r;
manager_add_server_string(m, NTP_SERVERS);
manager_parse_config_file(m);
+ r = manager_network_monitor_listen(m);
+ if (r < 0) {
+ log_error("Failed to listen to networkd events: %s", strerror(-r));
+ goto out;
+ }
+
log_debug("systemd-timesyncd running as pid %lu", (unsigned long) getpid());
sd_notify(false, "READY=1");
- r = manager_connect(m);
- if (r < 0)
- goto out;
+ if (network_is_online()) {
+ r = manager_connect(m);
+ if (r < 0)
+ goto out;
+ }
r = sd_event_loop(m->event);
if (r < 0) {