- return r;
-
- return manager_send_request(m);
-}
-
-static void server_name_flush_addresses(ServerName *n) {
- ServerAddress *a;
-
- assert(n);
-
- while ((a = n->addresses)) {
- LIST_REMOVE(addresses, n->addresses, a);
- free(a);
- }
-}
-
-static void manager_flush_names(Manager *m) {
- ServerName *n;
-
- assert(m);
-
- while ((n = m->servers)) {
- LIST_REMOVE(names, m->servers, n);
- free(n->string);
- server_name_flush_addresses(n);
- free(n);
- }
-}
-
-static int manager_resolve_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) {
- Manager *m = userdata;
- ServerAddress *a, *last = NULL;
-
- assert(q);
- assert(m);
- assert(m->current_server_name);
-
- m->resolve_query = sd_resolve_query_unref(m->resolve_query);
-
- if (ret != 0) {
- log_info("Failed to resolve %s: %s", m->current_server_name->string, gai_strerror(ret));
-
- /* Try next host */
- return manager_connect(m);
- }
-
- server_name_flush_addresses(m->current_server_name);
-
- for (; ai; ai = ai->ai_next) {
- _cleanup_free_ char *pretty = NULL;
-
- assert(ai->ai_addr);
- assert(ai->ai_addrlen >= offsetof(struct sockaddr, sa_data));
- assert(ai->ai_addrlen <= sizeof(union sockaddr_union));
-
- if (!IN_SET(ai->ai_addr->sa_family, AF_INET, AF_INET6)) {
- log_warning("Unsuitable address protocol for %s", m->current_server_name->string);
- continue;
- }
-
- a = new0(ServerAddress, 1);
- if (!a)
- return log_oom();
-
- memcpy(&a->sockaddr, ai->ai_addr, ai->ai_addrlen);
- a->socklen = ai->ai_addrlen;
-
- LIST_INSERT_AFTER(addresses, m->current_server_name->addresses, last, a);
- last = a;
-
- sockaddr_pretty(&a->sockaddr.sa, a->socklen, true, &pretty);
- log_debug("Resolved address %s for %s.", pretty, m->current_server_name->string);
- }
-
- if (!m->current_server_name->addresses) {
- log_error("Failed to find suitable address for host %s.", m->current_server_name->string);
-
- /* Try next host */
- return manager_connect(m);
- }
-
- m->current_server_address = m->current_server_name->addresses;
-
- return manager_begin(m);
-}
-
-static int manager_retry(sd_event_source *source, usec_t usec, void *userdata) {
- Manager *m = userdata;
-
- assert(m);
-
- return manager_connect(m);
-}
-
-static int manager_connect(Manager *m) {
-
- struct addrinfo hints = {
- .ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
- .ai_socktype = SOCK_DGRAM,
- };
- int r;
-
- assert(m);
-
- manager_disconnect(m);
-
- m->event_retry = sd_event_source_unref(m->event_retry);
- if (!ratelimit_test(&m->ratelimit)) {
- log_debug("Slowing down attempts to contact servers.");
-
- r = sd_event_add_time(m->event, &m->event_retry, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + RETRY_USEC, 0, manager_retry, m);
- if (r < 0) {
- log_error("Failed to create retry timer: %s", strerror(-r));
- return r;
- }
-
- return 0;
- }
-
- /* If we already are operating on some address, switch to the
- * next one. */
- if (m->current_server_address && m->current_server_address->addresses_next)
- m->current_server_address = m->current_server_address->addresses_next;
- else {
- /* Hmm, we are through all addresses, let's look for the next host instead */
- m->current_server_address = NULL;
-
- if (m->current_server_name && m->current_server_name->names_next)
- m->current_server_name = m->current_server_name->names_next;
- else {
- if (!m->servers) {
- m->current_server_name = NULL;
- log_debug("No server found.");
- return 0;
- }
-
- m->current_server_name = m->servers;
- }
-
- /* Tell the resolver to reread /etc/resolv.conf, in
- * case it changed. */
- res_init();
-
- r = sd_resolve_getaddrinfo(m->resolve, &m->resolve_query, m->current_server_name->string, "123", &hints, manager_resolve_handler, m);
- if (r < 0) {
- log_error("Failed to create resolver: %s", strerror(-r));
- return r;
- }
-
- return 1;
- }
-
- r = manager_begin(m);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int manager_add_server(Manager *m, const char *server) {
- ServerName *n, *tail;
-
- assert(m);
- assert(server);
-
- n = new0(ServerName, 1);
- if (!n)
- return -ENOMEM;
-
- n->string = strdup(server);
- if (!n->string) {
- free(n);
- return -ENOMEM;
- }
-
- LIST_FIND_TAIL(names, m->servers, tail);
- LIST_INSERT_AFTER(names, m->servers, tail, n);
-
- return 0;
-}
-
-static int manager_add_server_string(Manager *m, const char *string) {
- char *w, *state;
- size_t l;
- int r;
-
- assert(m);
- assert(string);
-
- FOREACH_WORD_QUOTED(w, l, string, state) {
- char t[l+1];
-
- memcpy(t, w, l);
- t[l] = 0;
-
- r = manager_add_server(m, t);
- if (r < 0)
- log_error("Failed to add server %s to configuration, ignoring: %s", t, strerror(-r));
- }
-
- return 0;
-}
-
-static void manager_disconnect(Manager *m) {
- assert(m);
-
- m->resolve_query = sd_resolve_query_unref(m->resolve_query);
-
- m->event_timer = sd_event_source_unref(m->event_timer);
-
- m->event_receive = sd_event_source_unref(m->event_receive);
- m->server_socket = safe_close(m->server_socket);
-
- m->event_clock_watch = sd_event_source_unref(m->event_clock_watch);
- m->clock_watch_fd = safe_close(m->clock_watch_fd);
-
- m->event_timeout = sd_event_source_unref(m->event_timeout);
-
- sd_notifyf(false, "STATUS=Idle.");
-}
-
-static int manager_new(Manager **ret) {
- _cleanup_manager_free_ Manager *m = NULL;
- int r;
-
- m = new0(Manager, 1);
- if (!m)
- return -ENOMEM;
-
- m->server_socket = m->clock_watch_fd = -1;
-
- RATELIMIT_INIT(m->ratelimit, RATELIMIT_INTERVAL_USEC, RATELIMIT_BURST);
-
- r = sd_event_default(&m->event);
- if (r < 0)
- return r;
-
- sd_event_add_signal(m->event, &m->sigterm, SIGTERM, NULL, NULL);
- sd_event_add_signal(m->event, &m->sigint, SIGINT, NULL, NULL);
-
- r = sd_resolve_default(&m->resolve);
- if (r < 0)
- return r;
-
- r = sd_resolve_attach_event(m->resolve, m->event, 0);
- if (r < 0)
- return 0;
-
- r = manager_clock_watch_setup(m);
- if (r < 0)
- return r;
-
- *ret = m;
- m = NULL;
-
- return 0;
-}
-
-static void manager_free(Manager *m) {
- if (!m)
- return;
-
- manager_disconnect(m);
- manager_flush_names(m);
-
- sd_event_source_unref(m->sigint);
- sd_event_source_unref(m->sigterm);
-
- 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);
-
- free(m);
-}
-
-int config_parse_servers(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Manager *m = userdata;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- manager_flush_names(m);
- manager_add_server_string(m, rvalue);
-
- return 0;
-}
-
-static int manager_parse_config_file(Manager *m) {
- static const char fn[] = "/etc/systemd/timesyncd.conf";
- _cleanup_fclose_ FILE *f = NULL;
- int r;
-
- assert(m);
-
- f = fopen(fn, "re");
- if (!f) {
- if (errno == ENOENT)
- return 0;
-
- log_warning("Failed to open configuration file %s: %m", fn);
- return -errno;
- }
-
- r = config_parse(NULL, fn, f, "Time\0", config_item_perf_lookup,
- (void*) timesyncd_gperf_lookup, false, false, m);
- if (r < 0)
- log_warning("Failed to parse configuration file: %s", strerror(-r));
-
- return r;
-}
-
-static bool network_is_online(void) {
- _cleanup_free_ unsigned *indices = NULL;
- int r, n, i;
-
- n = sd_network_get_ifindices(&indices);
- if (n <= 0)
- return false;
-
- for (i = 0; i < n; i++) {
- _cleanup_free_ char *oper_state = NULL;
-
- if (sd_network_link_is_loopback(indices[i]))
- /* ignore loopback devices */
- continue;
-
- r = sd_network_get_link_operational_state(indices[i], &oper_state);
- if (r >= 0 && streq(oper_state, "carrier"))
- return true;
- }
-
- 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;
-
- if (argc > 1) {
- log_error("This program does not take arguments.");
- return EXIT_FAILURE;
- }
-
- log_set_target(LOG_TARGET_AUTO);
- log_set_facility(LOG_CRON);
- log_parse_environment();
- log_open();
-
- umask(0022);