#include "util.h"
#include "sparse-endian.h"
#include "log.h"
+#include "socket-util.h"
#include "sd-event.h"
#include "sd-daemon.h"
/* 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;
/* last change */
bool jumped;
+ int drift_ppm;
/* watch for time changes */
sd_event_source *event_clock_watch;
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) {
}
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
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);
/* 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;
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;
* 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) {
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;
}
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,
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;
}
" 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),
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;
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;
}
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;
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;
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)