timesyncd-manager.c revision 6ff6f4d851ba5b8e6f07a8e029986f13c2e63b9d
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers This file is part of systemd.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers Copyright 2014 Kay Sievers, Lennart Poettering
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers systemd is free software; you can redistribute it and/or modify it
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers under the terms of the GNU Lesser General Public License as published by
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers the Free Software Foundation; either version 2.1 of the License, or
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers (at your option) any later version.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers systemd is distributed in the hope that it will be useful, but
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers Lesser General Public License for more details.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers You should have received a copy of the GNU Lesser General Public License
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/* expected accuracy of time synchronization; used to adjust the poll interval */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * "A client MUST NOT under any conditions use a poll interval less
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * than 15 seconds."
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * Maximum delta in seconds which the system clock is gradually adjusted
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * (slew) to approach the network time. Deltas larger that this are set by
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * letting the system time jump. The kernel's limit for adjtime is 0.5s.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/* NTP protocol, packet header */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers#define NTP_FIELD(l, v, m) (((l) << 6) | ((v) << 3) | (m))
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/* Maximum acceptable root distance in seconds. */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/* Maximum number of missed replies before selecting another source. */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * "NTP timestamps are represented as a 64-bit unsigned fixed-point number,
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * in seconds relative to 0h on 1 January 1900."
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers#define RATELIMIT_INTERVAL_USEC (10*USEC_PER_SEC)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic int manager_arm_timer(Manager *m, usec_t next);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic int manager_clock_watch_setup(Manager *m);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic double ntp_ts_short_to_d(const struct ntp_ts_short *ts) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic double ntp_ts_to_d(const struct ntp_ts *ts) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic double ts_to_d(const struct timespec *ts) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic int manager_timeout(sd_event_source *source, usec_t usec, void *userdata) {
6c7980093c4e39d07bf06484f96f489e236c7c29Kay Sievers server_address_pretty(m->current_server_address, &pretty);
6c7980093c4e39d07bf06484f96f489e236c7c29Kay Sievers log_info("Timed out waiting for reply from %s (%s).", strna(pretty), m->current_server_name->string);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers * "The client initializes the NTP message header, sends the request
assert(m);
r = manager_listen_setup(m);
len = sendto(m->server_socket, &ntpmsg, sizeof(ntpmsg), MSG_DONTWAIT, &m->current_server_address->sockaddr.sa, m->current_server_address->socklen);
m->pending = true;
log_debug_errno(errno, "Sending NTP request to %s (%s) failed: %m", strna(pretty), m->current_server_name->string);
return manager_connect(m);
if (m->retry_interval > 0) {
m->missed_replies++;
r = sd_event_add_time(
m->event,
&m->event_timeout,
manager_timeout, m);
assert(m);
return manager_send_request(m);
assert(m);
if (next == 0) {
if (m->event_timer) {
return sd_event_add_time(
m->event,
&m->event_timer,
manager_timer, m);
assert(m);
if (m->jumped) {
m->jumped = false;
m->poll_resync = true;
return manager_send_request(m);
assert(m);
if (m->clock_watch_fd < 0)
r = sd_event_add_io(m->event, &m->event_clock_watch, m->clock_watch_fd, EPOLLIN, manager_clock_watch, m);
assert(m);
m->jumped = true;
if (m->rtc_local_time)
switch (leap_sec) {
return -errno;
double jitter;
assert(m);
m->packet_count++;
idx_min = i;
if (m->poll_resync)
assert(m);
if (m->poll_resync) {
m->poll_resync = false;
static int manager_receive_response(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
} control;
double root_distance;
bool spike;
int leap_sec;
assert(m);
return manager_connect(m);
if (len < 0) {
return manager_connect(m);
return manager_connect(m);
if (!m->current_server_name ||
!m->current_server_address ||
case SCM_TIMESTAMPNS:
if (!recv_time) {
return -EINVAL;
if (!m->pending) {
m->missed_replies = 0;
return manager_connect(m);
return manager_connect(m);
return manager_connect(m);
return manager_connect(m);
root_distance = ntp_ts_short_to_d(&ntpmsg.root_delay) / 2 + ntp_ts_short_to_d(&ntpmsg.root_dispersion);
return manager_connect(m);
m->pending = false;
m->retry_interval = 0;
leap_sec = 0;
m->packet_count,
if (!spike) {
m->sync = true;
if (!m->good) {
m->good = true;
sd_notifyf(false, "STATUS=Synchronized to time server %s (%s).", strna(pretty), m->current_server_name->string);
assert(m);
if (m->server_socket >= 0)
if (m->server_socket < 0)
return -errno;
return -errno;
return -errno;
return sd_event_add_io(m->event, &m->event_receive, m->server_socket, EPOLLIN, manager_receive_response, m);
assert(m);
assert(m);
m->good = false;
if (m->poll_interval_usec == 0)
sd_notifyf(false, "STATUS=Connecting to time server %s (%s).", strna(pretty), m->current_server_name->string);
r = manager_clock_watch_setup(m);
return manager_send_request(m);
assert(m);
if (m->current_server_name == n)
m->current_server_name = n;
assert(m);
if (m->current_server_address == a)
m->current_server_address = a;
static int manager_resolve_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) {
assert(q);
assert(m);
if (ret != 0) {
return manager_connect(m);
ServerAddress *a;
r = server_address_new(m->current_server_name, &a, (const union sockaddr_union*) ai->ai_addr, ai->ai_addrlen);
return manager_connect(m);
return manager_begin(m);
assert(m);
return manager_connect(m);
assert(m);
r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + RETRY_USEC, 0, manager_retry_connect, m);
ServerName *f;
bool restart = true;
f = m->system_servers;
f = m->link_servers;
f = m->link_servers;
f = m->system_servers;
restart = false;
f = m->fallback_servers;
r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + m->poll_interval_usec, 0, manager_retry_connect, m);
m->exhausted_servers = true;
m->exhausted_servers = false;
manager_set_server_name(m, f);
/* Tell the resolver to reread /etc/resolv.conf, in
res_init();
r = sd_resolve_getaddrinfo(m->resolve, &m->resolve_query, m->current_server_name->string, "123", &hints, manager_resolve_handler, m);
r = manager_begin(m);
assert(m);
assert(m);
if (t == SERVER_SYSTEM)
while (m->system_servers)
if (t == SERVER_LINK)
while (m->link_servers)
if (t == SERVER_FALLBACK)
while (m->fallback_servers)
free(m);
assert(m);
goto clear;
n->marked = true;
bool found = false;
n->marked = false;
found = true;
if (!found) {
goto clear;
if (n->marked)
server_name_free(n);
static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
assert(m);
if (m->current_server_address)
r = manager_begin(m);
r = manager_connect(m);
assert(m);
if (fd < 0)
return fd;
if (events < 0)
return events;
r = sd_event_add_io(m->event, &m->network_event_source, fd, events, manager_network_event_handler, m);
return -ENOMEM;
r = manager_network_monitor_listen(m);
*ret = m;
m = NULL;