]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/timesync/timesyncd.c
timesync: always initialize structs when declaring them as far as possible with conts...
[thirdparty/systemd.git] / src / timesync / timesyncd.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Kay Sievers
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <time.h>
28 #include <math.h>
29 #include <arpa/inet.h>
30 #include <netinet/in.h>
31 #include <netinet/ip.h>
32 #include <sys/timerfd.h>
33 #include <sys/timex.h>
34 #include <sys/socket.h>
35
36 #include "missing.h"
37 #include "util.h"
38 #include "sparse-endian.h"
39 #include "log.h"
40 #include "socket-util.h"
41 #include "sd-event.h"
42 #include "sd-daemon.h"
43
44 #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
45
46 #ifndef ADJ_SETOFFSET
47 #define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
48 #endif
49
50 /* expected accuracy of time synchronization; used to adjust the poll interval */
51 #define NTP_ACCURACY_SEC 0.2
52
53 /*
54 * "A client MUST NOT under any conditions use a poll interval less
55 * than 15 seconds."
56 */
57 #define NTP_POLL_INTERVAL_MIN_SEC 32
58 #define NTP_POLL_INTERVAL_MAX_SEC 2048
59
60 /*
61 * Maximum delta in seconds which the system clock is gradually adjusted
62 * (slew) to approach the network time. Deltas larger that this are set by
63 * letting the system time jump. The kernel's limit for adjtime is 0.5s.
64 */
65 #define NTP_MAX_ADJUST 0.4
66
67 /* NTP protocol, packet header */
68 #define NTP_LEAP_PLUSSEC 1
69 #define NTP_LEAP_MINUSSEC 2
70 #define NTP_LEAP_NOTINSYNC 3
71 #define NTP_MODE_CLIENT 3
72 #define NTP_MODE_SERVER 4
73 #define NTP_FIELD_LEAP(f) (((f) >> 6) & 3)
74 #define NTP_FIELD_VERSION(f) (((f) >> 3) & 7)
75 #define NTP_FIELD_MODE(f) ((f) & 7)
76 #define NTP_FIELD(l, v, m) (((l) << 6) | ((v) << 3) | (m))
77
78 /*
79 * "NTP timestamps are represented as a 64-bit unsigned fixed-point number,
80 * in seconds relative to 0h on 1 January 1900."
81 */
82 #define OFFSET_1900_1970 2208988800UL
83
84 struct ntp_ts {
85 be32_t sec;
86 be32_t frac;
87 } _packed_;
88
89 struct ntp_ts_short {
90 be16_t sec;
91 be16_t frac;
92 } _packed_;
93
94 struct ntp_msg {
95 uint8_t field;
96 uint8_t stratum;
97 int8_t poll;
98 int8_t precision;
99 struct ntp_ts_short root_delay;
100 struct ntp_ts_short root_dispersion;
101 char refid[4];
102 struct ntp_ts reference_time;
103 struct ntp_ts origin_time;
104 struct ntp_ts recv_time;
105 struct ntp_ts trans_time;
106 } _packed_;
107
108 typedef struct Manager Manager;
109 struct Manager {
110 sd_event *event;
111
112 /* peer */
113 sd_event_source *event_receive;
114 char *server;
115 union sockaddr_union server_addr;
116 int server_socket;
117 uint64_t packet_count;
118
119 /* last sent packet */
120 struct timespec trans_time_mon;
121 struct timespec trans_time;
122 usec_t retry_interval;
123 bool pending;
124
125 /* poll timer */
126 sd_event_source *event_timer;
127 usec_t poll_interval_usec;
128 bool poll_resync;
129
130 /* history data */
131 struct {
132 double offset;
133 double delay;
134 } samples[8];
135 unsigned int samples_idx;
136 double samples_jitter;
137
138 /* last change */
139 bool jumped;
140 int drift_ppm;
141
142 /* watch for time changes */
143 sd_event_source *event_clock_watch;
144 int clock_watch_fd;
145 };
146
147 static void manager_free(Manager *m);
148 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
149 #define _cleanup_manager_free_ _cleanup_(manager_freep)
150
151 static int sntp_arm_timer(Manager *m, usec_t next);
152 static int sntp_clock_watch_setup(Manager *m);
153 static void sntp_server_disconnect(Manager *m);
154
155 static double ntp_ts_to_d(const struct ntp_ts *ts) {
156 return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX);
157 }
158
159 static double ts_to_d(const struct timespec *ts) {
160 return ts->tv_sec + (1.0e-9 * ts->tv_nsec);
161 }
162
163 static double tv_to_d(const struct timeval *tv) {
164 return tv->tv_sec + (1.0e-6 * tv->tv_usec);
165 }
166
167 static double square(double d) {
168 return d * d;
169 }
170
171 static int sntp_send_request(Manager *m) {
172 struct ntp_msg ntpmsg = {
173 /*
174 * "The client initializes the NTP message header, sends the request
175 * to the server, and strips the time of day from the Transmit
176 * Timestamp field of the reply. For this purpose, all the NTP
177 * header fields are set to 0, except the Mode, VN, and optional
178 * Transmit Timestamp fields."
179 */
180 .field = NTP_FIELD(0, 4, NTP_MODE_CLIENT),
181 };
182
183 union sockaddr_union addr = {
184 .in.sin_family = AF_INET,
185 .in.sin_port = htobe16(123),
186 };
187 ssize_t len;
188 int r;
189
190
191 /*
192 * Set transmit timestamp, remember it; the server will send that back
193 * as the origin timestamp and we have an indication that this is the
194 * matching answer to our request.
195 *
196 * The actual value does not matter, We do not care about the correct
197 * NTP UINT_MAX fraction; we just pass the plain nanosecond value.
198 */
199 clock_gettime(CLOCK_MONOTONIC, &m->trans_time_mon);
200 clock_gettime(CLOCK_REALTIME, &m->trans_time);
201 ntpmsg.trans_time.sec = htobe32(m->trans_time.tv_sec + OFFSET_1900_1970);
202 ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec);
203
204 addr.in.sin_addr.s_addr = inet_addr(m->server);
205 len = sendto(m->server_socket, &ntpmsg, sizeof(ntpmsg), MSG_DONTWAIT, &addr.sa, sizeof(addr.in));
206 if (len == sizeof(ntpmsg)) {
207 m->pending = true;
208 log_debug("Sent NTP request to: %s", m->server);
209 } else
210 log_debug("Sending NTP request to %s failed: %m", m->server);
211
212 /* re-arm timer with incresing timeout, in case the packets never arrive back */
213 if (m->retry_interval > 0) {
214 if (m->retry_interval < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
215 m->retry_interval *= 2;
216 } else
217 m->retry_interval = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
218 r = sntp_arm_timer(m, m->retry_interval);
219 if (r < 0)
220 return r;
221
222 return 0;
223 }
224
225 static int sntp_timer(sd_event_source *source, usec_t usec, void *userdata) {
226 Manager *m = userdata;
227
228 assert(m);
229
230 sntp_send_request(m);
231 return 0;
232 }
233
234 static int sntp_arm_timer(Manager *m, usec_t next) {
235 int r;
236
237 assert(m);
238 assert(m->event_receive);
239
240 if (next == 0) {
241 m->event_timer = sd_event_source_unref(m->event_timer);
242 return 0;
243 }
244
245 if (m->event_timer) {
246 r = sd_event_source_set_time(m->event_timer, now(CLOCK_MONOTONIC) + next);
247 if (r < 0)
248 return r;
249
250 return sd_event_source_set_enabled(m->event_timer, SD_EVENT_ONESHOT);
251 }
252
253 r = sd_event_add_time(
254 m->event,
255 &m->event_timer,
256 CLOCK_MONOTONIC,
257 now(CLOCK_MONOTONIC) + next, 0,
258 sntp_timer, m);
259 if (r < 0)
260 return r;
261
262 return 0;
263 }
264
265 static int sntp_clock_watch(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
266 Manager *m = userdata;
267
268 assert(m);
269 assert(m->event_receive);
270
271 /* rearm timer */
272 sntp_clock_watch_setup(m);
273
274 /* skip our own jumps */
275 if (m->jumped) {
276 m->jumped = false;
277 return 0;
278 }
279
280 /* resync */
281 log_info("System time changed. Resyncing.");
282 m->poll_resync = true;
283 sntp_send_request(m);
284
285 return 0;
286 }
287
288 /* wake up when the system time changes underneath us */
289 static int sntp_clock_watch_setup(Manager *m) {
290
291 struct itimerspec its = {
292 .it_value.tv_sec = TIME_T_MAX
293 };
294
295 _cleanup_close_ int fd = -1;
296 sd_event_source *source;
297 int r;
298
299 assert(m);
300 assert(m->event_receive);
301
302 fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
303 if (fd < 0) {
304 log_error("Failed to create timerfd: %m");
305 return -errno;
306 }
307
308 if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
309 log_error("Failed to set up timerfd: %m");
310 return -errno;
311 }
312
313 r = sd_event_add_io(m->event, &source, fd, EPOLLIN, sntp_clock_watch, m);
314 if (r < 0) {
315 log_error("Failed to create clock watch event source: %s", strerror(-r));
316 return r;
317 }
318
319 sd_event_source_unref(m->event_clock_watch);
320 m->event_clock_watch = source;
321
322 if (m->clock_watch_fd >= 0)
323 close(m->clock_watch_fd);
324 m->clock_watch_fd = fd;
325 fd = -1;
326
327 return 0;
328 }
329
330 static int sntp_adjust_clock(Manager *m, double offset, int leap_sec) {
331 struct timex tmx = {};
332 int r;
333
334 /*
335 * For small deltas, tell the kernel to gradually adjust the system
336 * clock to the NTP time, larger deltas are just directly set.
337 *
338 * Clear STA_UNSYNC, it will enable the kernel's 11-minute mode, which
339 * syncs the system time periodically to the hardware clock.
340 */
341 if (fabs(offset) < NTP_MAX_ADJUST) {
342 tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR;
343 tmx.status = STA_PLL;
344 tmx.offset = offset * NSEC_PER_SEC;
345 tmx.constant = log2i(m->poll_interval_usec / USEC_PER_SEC) - 4;
346 tmx.maxerror = 0;
347 tmx.esterror = 0;
348 log_debug(" adjust (slew): %+.3f sec\n", offset);
349 } else {
350 tmx.modes = ADJ_SETOFFSET | ADJ_NANO;
351
352 /* ADJ_NANO uses nanoseconds in the microseconds field */
353 tmx.time.tv_sec = (long)offset;
354 tmx.time.tv_usec = (offset - tmx.time.tv_sec) * NSEC_PER_SEC;
355
356 /* the kernel expects -0.3s as {-1, 7000.000.000} */
357 if (tmx.time.tv_usec < 0) {
358 tmx.time.tv_sec -= 1;
359 tmx.time.tv_usec += NSEC_PER_SEC;
360 }
361
362 m->jumped = true;
363 log_debug(" adjust (jump): %+.3f sec\n", offset);
364 }
365
366 switch (leap_sec) {
367 case 1:
368 tmx.status |= STA_INS;
369 break;
370 case -1:
371 tmx.status |= STA_DEL;
372 break;
373 }
374
375 r = clock_adjtime(CLOCK_REALTIME, &tmx);
376 if (r < 0)
377 return r;
378
379 m->drift_ppm = tmx.freq / 65536;
380
381 log_debug(" status : %04i %s\n"
382 " time now : %li.%03lli\n"
383 " constant : %li\n"
384 " offset : %+.3f sec\n"
385 " freq offset : %+li (%i ppm)\n",
386 tmx.status, tmx.status & STA_UNSYNC ? "" : "sync",
387 tmx.time.tv_sec, tmx.time.tv_usec / NSEC_PER_MSEC,
388 tmx.constant,
389 (double)tmx.offset / NSEC_PER_SEC,
390 tmx.freq, m->drift_ppm);
391
392 return 0;
393 }
394
395 static bool sntp_sample_spike_detection(Manager *m, double offset, double delay) {
396 unsigned int i, idx_cur, idx_new, idx_min;
397 double jitter;
398 double j;
399
400 m->packet_count++;
401
402 /* ignore initial sample */
403 if (m->packet_count == 1)
404 return false;
405
406 /* store the current data in our samples array */
407 idx_cur = m->samples_idx;
408 idx_new = (idx_cur + 1) % ELEMENTSOF(m->samples);
409 m->samples_idx = idx_new;
410 m->samples[idx_new].offset = offset;
411 m->samples[idx_new].delay = delay;
412
413 /* calculate new jitter value from the RMS differences relative to the lowest delay sample */
414 jitter = m->samples_jitter;
415 for (idx_min = idx_cur, i = 0; i < ELEMENTSOF(m->samples); i++)
416 if (m->samples[i].delay > 0 && m->samples[i].delay < m->samples[idx_min].delay)
417 idx_min = i;
418
419 j = 0;
420 for (i = 0; i < ELEMENTSOF(m->samples); i++)
421 j += square(m->samples[i].offset - m->samples[idx_min].offset);
422 m->samples_jitter = sqrt(j / (ELEMENTSOF(m->samples) - 1));
423
424 /* ignore samples when resyncing */
425 if (m->poll_resync)
426 return false;
427
428 /* always accept offset if we are farther off than the round-trip delay */
429 if (fabs(offset) > delay)
430 return false;
431
432 /* we need a few samples before looking at them */
433 if (m->packet_count < 4)
434 return false;
435
436 /* do not accept anything worse than the maximum possible error of the best sample */
437 if (fabs(offset) > m->samples[idx_min].delay)
438 return true;
439
440 /* compare the difference between the current offset to the previous offset and jitter */
441 return fabs(offset - m->samples[idx_cur].offset) > 3 * jitter;
442 }
443
444 static void sntp_adjust_poll(Manager *m, double offset, bool spike) {
445 if (m->poll_resync) {
446 m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
447 m->poll_resync = false;
448 return;
449 }
450
451 /* set to minimal poll interval */
452 if (!spike && fabs(offset) > NTP_ACCURACY_SEC) {
453 m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
454 return;
455 }
456
457 /* increase polling interval */
458 if (fabs(offset) < NTP_ACCURACY_SEC * 0.25) {
459 if (m->poll_interval_usec < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
460 m->poll_interval_usec *= 2;
461 return;
462 }
463
464 /* decrease polling interval */
465 if (spike || fabs(offset) > NTP_ACCURACY_SEC * 0.75) {
466 if (m->poll_interval_usec > NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC)
467 m->poll_interval_usec /= 2;
468 return;
469 }
470 }
471
472 static int sntp_receive_response(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
473 Manager *m = userdata;
474 unsigned char buf[sizeof(struct ntp_msg)];
475 struct iovec iov = {
476 .iov_base = buf,
477 .iov_len = sizeof(buf),
478 };
479 union {
480 struct cmsghdr cmsghdr;
481 uint8_t buf[CMSG_SPACE(sizeof(struct timeval))];
482 } control;
483 union sockaddr_union server_addr;
484 struct msghdr msghdr = {
485 .msg_iov = &iov,
486 .msg_iovlen = 1,
487 .msg_control = &control,
488 .msg_controllen = sizeof(control),
489 .msg_name = &server_addr,
490 .msg_namelen = sizeof(server_addr),
491 };
492 struct cmsghdr *cmsg;
493 struct timespec now_ts;
494 struct timeval *recv_time;
495 ssize_t len;
496 struct ntp_msg *ntpmsg;
497 double origin, receive, trans, dest;
498 double delay, offset;
499 bool spike;
500 int leap_sec;
501 int r;
502
503 if (revents & (EPOLLHUP|EPOLLERR)) {
504 log_debug("Server connection returned error. Closing.");
505 sntp_server_disconnect(m);
506 return -ENOTCONN;
507 }
508
509 len = recvmsg(fd, &msghdr, MSG_DONTWAIT);
510 if (len < 0) {
511 log_debug("Error receiving message. Disconnecting.");
512 return -EINVAL;
513 }
514
515 if (iov.iov_len < sizeof(struct ntp_msg)) {
516 log_debug("Invalid response from server. Disconnecting.");
517 return -EINVAL;
518 }
519
520 if (m->server_addr.in.sin_addr.s_addr != server_addr.in.sin_addr.s_addr) {
521 log_debug("Response from unknown server. Disconnecting.");
522 return -EINVAL;
523 }
524
525 recv_time = NULL;
526 for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
527 if (cmsg->cmsg_level != SOL_SOCKET)
528 continue;
529
530 switch (cmsg->cmsg_type) {
531 case SCM_TIMESTAMP:
532 recv_time = (struct timeval *) CMSG_DATA(cmsg);
533 break;
534 }
535 }
536 if (!recv_time) {
537 log_debug("Invalid packet timestamp. Disconnecting.");
538 return -EINVAL;
539 }
540
541 ntpmsg = iov.iov_base;
542 if (!m->pending) {
543 log_debug("Unexpected reply. Ignoring.");
544 return 0;
545 }
546
547 /* check our "time cookie" (we just stored nanoseconds in the fraction field) */
548 if (be32toh(ntpmsg->origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 ||
549 be32toh(ntpmsg->origin_time.frac) != m->trans_time.tv_nsec) {
550 log_debug("Invalid reply; not our transmit time. Ignoring.");
551 return 0;
552 }
553
554 if (NTP_FIELD_LEAP(ntpmsg->field) == NTP_LEAP_NOTINSYNC) {
555 log_debug("Server is not synchronized. Disconnecting.");
556 return -EINVAL;
557 }
558
559 if (NTP_FIELD_VERSION(ntpmsg->field) != 4) {
560 log_debug("Response NTPv%d. Disconnecting.", NTP_FIELD_VERSION(ntpmsg->field));
561 return -EINVAL;
562 }
563
564 if (NTP_FIELD_MODE(ntpmsg->field) != NTP_MODE_SERVER) {
565 log_debug("Unsupported mode %d. Disconnecting.", NTP_FIELD_MODE(ntpmsg->field));
566 return -EINVAL;
567 }
568
569 /* valid packet */
570 m->pending = false;
571 m->retry_interval = 0;
572
573 /* announce leap seconds */
574 if (NTP_FIELD_LEAP(ntpmsg->field) & NTP_LEAP_PLUSSEC)
575 leap_sec = 1;
576 else if (NTP_FIELD_LEAP(ntpmsg->field) & NTP_LEAP_MINUSSEC)
577 leap_sec = -1;
578 else
579 leap_sec = 0;
580
581 /*
582 * "Timestamp Name ID When Generated
583 * ------------------------------------------------------------
584 * Originate Timestamp T1 time request sent by client
585 * Receive Timestamp T2 time request received by server
586 * Transmit Timestamp T3 time reply sent by server
587 * Destination Timestamp T4 time reply received by client
588 *
589 * The round-trip delay, d, and system clock offset, t, are defined as:
590 * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2"
591 */
592 clock_gettime(CLOCK_MONOTONIC, &now_ts);
593 origin = tv_to_d(recv_time) - (ts_to_d(&now_ts) - ts_to_d(&m->trans_time_mon)) + OFFSET_1900_1970;
594 receive = ntp_ts_to_d(&ntpmsg->recv_time);
595 trans = ntp_ts_to_d(&ntpmsg->trans_time);
596 dest = tv_to_d(recv_time) + OFFSET_1900_1970;
597
598 offset = ((receive - origin) + (trans - dest)) / 2;
599 delay = (dest - origin) - (trans - receive);
600
601 spike = sntp_sample_spike_detection(m, offset, delay);
602
603 sntp_adjust_poll(m, offset, spike);
604
605 log_debug("NTP response:\n"
606 " leap : %u\n"
607 " version : %u\n"
608 " mode : %u\n"
609 " stratum : %u\n"
610 " precision : %.6f sec (%d)\n"
611 " reference : %.4s\n"
612 " origin : %.3f\n"
613 " receive : %.3f\n"
614 " transmit : %.3f\n"
615 " dest : %.3f\n"
616 " offset : %+.3f sec\n"
617 " delay : %+.3f sec\n"
618 " packet count : %"PRIu64"\n"
619 " jitter : %.3f%s\n"
620 " poll interval: %llu\n",
621 NTP_FIELD_LEAP(ntpmsg->field),
622 NTP_FIELD_VERSION(ntpmsg->field),
623 NTP_FIELD_MODE(ntpmsg->field),
624 ntpmsg->stratum,
625 exp2(ntpmsg->precision), ntpmsg->precision,
626 ntpmsg->stratum == 1 ? ntpmsg->refid : "n/a",
627 origin - OFFSET_1900_1970,
628 receive - OFFSET_1900_1970,
629 trans - OFFSET_1900_1970,
630 dest - OFFSET_1900_1970,
631 offset, delay,
632 m->packet_count,
633 m->samples_jitter, spike ? " spike" : "",
634 m->poll_interval_usec / USEC_PER_SEC);
635
636 if (!spike) {
637 r = sntp_adjust_clock(m, offset, leap_sec);
638 if (r < 0)
639 log_error("Failed to call clock_adjtime(): %m");
640 }
641
642 log_info("%s: interval/delta/delay/jitter/drift %llus/%+.3fs/%.3fs/%.3fs/%+ippm%s",
643 m->server, m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, m->drift_ppm,
644 spike ? " (ignored)" : "");
645 r = sntp_arm_timer(m, m->poll_interval_usec);
646 if (r < 0)
647 return r;
648
649 return 0;
650 }
651
652 static int sntp_server_connect(Manager *m, const char *server) {
653 _cleanup_free_ char *s = NULL;
654
655 assert(m);
656 assert(server);
657 assert(m->server_socket >= 0);
658
659 s = strdup(server);
660 if (!s)
661 return -ENOMEM;
662
663 free(m->server);
664 m->server = s;
665 s = NULL;
666
667 zero(m->server_addr);
668 m->server_addr.in.sin_family = AF_INET;
669 m->server_addr.in.sin_addr.s_addr = inet_addr(server);
670
671 m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
672
673 return sntp_send_request(m);
674 }
675
676 static void sntp_server_disconnect(Manager *m) {
677 if (!m->server)
678 return;
679
680 m->event_timer = sd_event_source_unref(m->event_timer);
681
682 m->event_clock_watch = sd_event_source_unref(m->event_clock_watch);
683 if (m->clock_watch_fd > 0)
684 close(m->clock_watch_fd);
685 m->clock_watch_fd = -1;
686
687 m->event_receive = sd_event_source_unref(m->event_receive);
688 if (m->server_socket > 0)
689 close(m->server_socket);
690 m->server_socket = -1;
691
692 zero(m->server_addr);
693 free(m->server);
694 m->server = NULL;
695 }
696
697 static int sntp_listen_setup(Manager *m) {
698
699 union sockaddr_union addr = {
700 .in.sin_family = AF_INET,
701 };
702
703 _cleanup_close_ int fd = -1;
704 const int on = 1;
705 const int tos = IPTOS_LOWDELAY;
706 int r;
707
708 fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
709 if (fd < 0)
710 return -errno;
711
712 r = bind(fd, &addr.sa, sizeof(addr.in));
713 if (r < 0)
714 return -errno;
715
716 r = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on));
717 if (r < 0)
718 return -errno;
719
720 r = setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
721 if (r < 0)
722 return -errno;
723
724 r = sd_event_add_io(m->event, &m->event_receive, fd, EPOLLIN, sntp_receive_response, m);
725 if (r < 0)
726 return r;
727
728 m->server_socket = fd;
729 fd = -1;
730
731 return 0;
732 }
733
734 static int manager_new(Manager **ret) {
735 _cleanup_manager_free_ Manager *m = NULL;
736 int r;
737
738 m = new0(Manager, 1);
739 if (!m)
740 return -ENOMEM;
741
742 r = sd_event_default(&m->event);
743 if (r < 0)
744 return r;
745
746 r = sntp_listen_setup(m);
747 if (r < 0)
748 return r;
749
750 r = sntp_clock_watch_setup(m);
751 if (r < 0)
752 return r;
753
754 *ret = m;
755 m = NULL;
756
757 return 0;
758 }
759
760 static void manager_free(Manager *m) {
761
762 if (!m)
763 return;
764
765 sd_event_unref(m->event);
766 free(m);
767 }
768
769 int main(int argc, char *argv[]) {
770 _cleanup_manager_free_ Manager *m = NULL;
771 const char *server;
772 int r;
773
774 log_set_target(LOG_TARGET_AUTO);
775 log_parse_environment();
776 log_open();
777
778 r = manager_new(&m);
779 if (r < 0)
780 goto out;
781
782 server = "216.239.32.15"; /* time1.google.com */
783
784 sd_notify(false, "READY=1");
785
786 r = sntp_server_connect(m, server);
787 if (r < 0)
788 goto out;
789
790 sd_notifyf(false, "STATUS=Using Time Server: %s", server);
791
792 r = sd_event_loop(m->event);
793 if (r < 0)
794 goto out;
795
796 out:
797 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
798 }