5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <netinet/ip.h>
36 #include <arpa/inet.h>
40 #include <gweb/gresolv.h>
47 } __attribute__ ((packed));
52 } __attribute__ ((packed));
55 uint8_t flags; /* Mode, version and leap indicator */
56 uint8_t stratum; /* Stratum details */
57 int8_t poll; /* Maximum interval in log2 seconds */
58 int8_t precision; /* Clock precision in log2 seconds */
59 struct ntp_short rootdelay; /* Root delay */
60 struct ntp_short rootdisp; /* Root dispersion */
61 uint32_t refid; /* Reference ID */
62 struct ntp_time reftime; /* Reference timestamp */
63 struct ntp_time orgtime; /* Origin timestamp */
64 struct ntp_time rectime; /* Receive timestamp */
65 struct ntp_time xmttime; /* Transmit timestamp */
66 } __attribute__ ((packed));
68 #define OFFSET_1900_1970 2208988800UL /* 1970 - 1900 in seconds */
70 #define STEPTIME_MIN_OFFSET 0.128
72 #define LOGTOD(a) ((a) < 0 ? 1. / (1L << -(a)) : 1L << (int)(a))
74 static struct timeval transmit_timeval;
75 static char *transmit_server;
76 static int transmit_fd;
77 static guint transmit_delay = 16;
79 static void send_packet(int fd, const char *server)
82 struct sockaddr_in addr;
85 memset(&msg, 0, sizeof(msg));
89 msg.xmttime.seconds = random();
90 msg.xmttime.fraction = random();
92 memset(&addr, 0, sizeof(addr));
93 addr.sin_family = AF_INET;
94 addr.sin_port = htons(123);
95 addr.sin_addr.s_addr = inet_addr(server);
97 gettimeofday(&transmit_timeval, NULL);
99 len = sendto(fd, &msg, sizeof(msg), MSG_DONTWAIT,
100 &addr, sizeof(addr));
102 connman_error("Time request for server %s failed", server);
106 if (len != sizeof(msg)) {
107 connman_error("Broken time request for server %s", server);
112 static gboolean next_request(gpointer user_data)
114 DBG("server %s", transmit_server);
116 send_packet(transmit_fd, transmit_server);
121 static void decode_msg(void *base, size_t len, struct timeval *tv)
123 struct ntp_msg *msg = base;
124 double org, rec, xmt, dst;
125 double delay, offset;
127 if (len < sizeof(*msg)) {
128 connman_error("Invalid response from time server");
133 connman_error("Invalid packet timestamp from time server");
137 DBG("flags : 0x%02x", msg->flags);
138 DBG("stratum : %u", msg->stratum);
139 DBG("poll : %f seconds (%d)",
140 LOGTOD(msg->poll), msg->poll);
141 DBG("precision : %f seconds (%d)",
142 LOGTOD(msg->precision), msg->precision);
143 DBG("root delay : %u seconds (fraction %u)",
144 msg->rootdelay.seconds, msg->rootdelay.fraction);
145 DBG("root disp. : %u seconds (fraction %u)",
146 msg->rootdisp.seconds, msg->rootdisp.fraction);
147 DBG("reference : 0x%04x", msg->refid);
149 transmit_delay = LOGTOD(msg->poll);
151 if (msg->flags != 0x24)
154 org = transmit_timeval.tv_sec +
155 (1.0e-6 * transmit_timeval.tv_usec) + OFFSET_1900_1970;
156 rec = ntohl(msg->rectime.seconds) +
157 ((double) ntohl(msg->rectime.fraction) / UINT_MAX);
158 xmt = ntohl(msg->xmttime.seconds) +
159 ((double) ntohl(msg->xmttime.fraction) / UINT_MAX);
160 dst = tv->tv_sec + (1.0e-6 * tv->tv_usec) + OFFSET_1900_1970;
162 DBG("org=%f rec=%f xmt=%f dst=%f", org, rec, xmt, dst);
164 offset = ((rec - org) + (xmt - dst)) / 2;
165 delay = (dst - org) - (xmt - rec);
167 DBG("offset=%f delay=%f", offset, delay);
169 if (offset < STEPTIME_MIN_OFFSET && offset > -STEPTIME_MIN_OFFSET) {
172 adj.tv_sec = (long) offset;
173 adj.tv_usec = (offset - adj.tv_sec) * 1000000;
175 DBG("adjusting time");
177 if (adjtime(&adj, &adj) < 0) {
178 connman_error("Failed to adjust time");
182 DBG("%lu seconds, %lu msecs", adj.tv_sec, adj.tv_usec);
187 gettimeofday(&cur, NULL);
188 dtime = offset + cur.tv_sec + 1.0e-6 * cur.tv_usec;
189 cur.tv_sec = (long) dtime;
190 cur.tv_usec = (dtime - cur.tv_sec) * 1000000;
194 if (settimeofday(&cur, NULL) < 0) {
195 connman_error("Failed to set time");
199 DBG("%lu seconds, %lu msecs", cur.tv_sec, cur.tv_usec);
203 static guint channel_watch = 0;
205 static gboolean received_data(GIOChannel *channel, GIOCondition condition,
208 unsigned char buf[128];
211 struct cmsghdr *cmsg;
217 if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
218 connman_error("Problem with timer server channel");
223 fd = g_io_channel_unix_get_fd(channel);
226 iov.iov_len = sizeof(buf);
228 memset(&msg, 0, sizeof(msg));
231 msg.msg_control = aux;
232 msg.msg_controllen = sizeof(aux);
234 len = recvmsg(fd, &msg, MSG_DONTWAIT);
240 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
241 if (cmsg->cmsg_level != SOL_SOCKET)
244 switch (cmsg->cmsg_type) {
246 tv = (struct timeval *) CMSG_DATA(cmsg);
251 decode_msg(iov.iov_base, iov.iov_len, tv);
253 g_timeout_add_seconds(transmit_delay, next_request, NULL);
258 static void start_ntp(const char *server)
261 struct sockaddr_in addr;
262 int fd, tos = IPTOS_LOWDELAY, timestamp = 1;
264 DBG("server %s", server);
266 if (channel_watch > 0)
269 fd = socket(PF_INET, SOCK_DGRAM, 0);
271 connman_error("Failed to open time server socket");
275 memset(&addr, 0, sizeof(addr));
276 addr.sin_family = AF_INET;
278 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
279 connman_error("Failed to bind time server socket");
284 if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
285 connman_error("Failed to set type of service option");
290 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, ×tamp,
291 sizeof(timestamp)) < 0) {
292 connman_error("Failed to enable timestamp support");
297 channel = g_io_channel_unix_new(fd);
298 if (channel == NULL) {
303 g_io_channel_set_encoding(channel, NULL, NULL);
304 g_io_channel_set_buffered(channel, FALSE);
306 g_io_channel_set_close_on_unref(channel, TRUE);
308 channel_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
309 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
310 received_data, NULL, NULL);
312 g_io_channel_unref(channel);
315 transmit_server = g_strdup(server);
317 send_packet(fd, server);
320 static void resolv_debug(const char *str, void *data)
322 connman_info("%s: %s\n", (const char *) data, str);
325 static GResolv *resolv = NULL;
326 static guint resolv_lookup = 0;
328 static void resolv_result(GResolvResultStatus status,
329 char **results, gpointer user_data)
335 if (results != NULL) {
336 for (i = 0; results[i]; i++)
337 DBG("result: %s", results[i]);
339 if (results[0] != NULL)
340 start_ntp(results[0]);
344 int __connman_ntp_start(const char *interface, const char *resolver,
347 DBG("interface %s server %s", interface, server);
349 resolv = g_resolv_new(0);
353 if (getenv("CONNMAN_RESOLV_DEBUG"))
354 g_resolv_set_debug(resolv, resolv_debug, "RESOLV");
356 if (resolver != NULL)
357 g_resolv_add_nameserver(resolv, resolver, 53, 0);
359 g_resolv_lookup_hostname(resolv, server, resolv_result, NULL);
364 void __connman_ntp_stop(const char *interface)
366 DBG("interface %s", interface);
371 if (resolv_lookup > 0) {
372 g_resolv_cancel_lookup(resolv, resolv_lookup);
376 if (channel_watch > 0) {
377 g_source_remove(channel_watch);
381 g_resolv_unref(resolv);