diff options
Diffstat (limited to 'src/ntp.c')
-rwxr-xr-x | src/ntp.c | 258 |
1 files changed, 130 insertions, 128 deletions
@@ -23,7 +23,6 @@ #include <config.h> #endif -#define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <unistd.h> @@ -118,43 +117,55 @@ struct ntp_msg { #define NTP_PRECISION_US -19 #define NTP_PRECISION_NS -29 -static guint channel_watch = 0; -static struct timespec mtx_time; -static int transmit_fd = 0; - -static char *timeserver = NULL; -static struct sockaddr_in6 timeserver_addr; -static gint poll_id = 0; -static gint timeout_id = 0; -static guint retries = 0; - -static void send_packet(int fd, struct sockaddr *server, uint32_t timeout); - -static void next_server(void) +struct ntp_data { + char *timeserver; + struct sockaddr_in6 timeserver_addr; + struct timespec mtx_time; + int transmit_fd; + gint timeout_id; + guint retries; + guint channel_watch; + gint poll_id; + uint32_t timeout; + __connman_ntp_cb_t cb; + void *user_data; +}; + +static struct ntp_data *ntp_data; + +static void free_ntp_data(struct ntp_data *nd) { - if (timeserver) { - g_free(timeserver); - timeserver = NULL; - } - - __connman_timeserver_sync_next(); + if (nd->poll_id) + g_source_remove(nd->poll_id); + if (nd->timeout_id) + g_source_remove(nd->timeout_id); + if (nd->channel_watch) + g_source_remove(nd->channel_watch); + if (nd->timeserver) + g_free(nd->timeserver); + g_free(nd); } +static void send_packet(struct ntp_data *nd, struct sockaddr *server, + uint32_t timeout); + static gboolean send_timeout(gpointer user_data) { - uint32_t timeout = GPOINTER_TO_UINT(user_data); + struct ntp_data *nd = user_data; - DBG("send timeout %u (retries %d)", timeout, retries); + DBG("send timeout %u (retries %d)", nd->timeout, nd->retries); - if (retries++ == NTP_SEND_RETRIES) - next_server(); + if (nd->retries++ == NTP_SEND_RETRIES) + nd->cb(false, nd->user_data); else - send_packet(transmit_fd, (struct sockaddr *)×erver_addr, timeout << 1); + send_packet(nd, (struct sockaddr *)&nd->timeserver_addr, + nd->timeout << 1); return FALSE; } -static void send_packet(int fd, struct sockaddr *server, uint32_t timeout) +static void send_packet(struct ntp_data *nd, struct sockaddr *server, + uint32_t timeout) { struct ntp_msg msg; struct timeval transmit_timeval; @@ -177,38 +188,28 @@ static void send_packet(int fd, struct sockaddr *server, uint32_t timeout) if (server->sa_family == AF_INET) { size = sizeof(struct sockaddr_in); - addr = (void *)&(((struct sockaddr_in *)×erver_addr)->sin_addr); + addr = (void *)&(((struct sockaddr_in *)&nd->timeserver_addr)->sin_addr); } else if (server->sa_family == AF_INET6) { size = sizeof(struct sockaddr_in6); - addr = (void *)×erver_addr.sin6_addr; + addr = (void *)&nd->timeserver_addr.sin6_addr; } else { - connman_error("Family is neither ipv4 nor ipv6"); + DBG("Family is neither ipv4 nor ipv6"); + nd->cb(false, nd->user_data); return; } gettimeofday(&transmit_timeval, NULL); - clock_gettime(CLOCK_MONOTONIC, &mtx_time); + clock_gettime(CLOCK_MONOTONIC, &nd->mtx_time); msg.xmttime.seconds = htonl(transmit_timeval.tv_sec + OFFSET_1900_1970); msg.xmttime.fraction = htonl(transmit_timeval.tv_usec * 1000); - len = sendto(fd, &msg, sizeof(msg), MSG_DONTWAIT, + len = sendto(nd->transmit_fd, &msg, sizeof(msg), MSG_DONTWAIT, server, size); - - if (len < 0) { - connman_error("Time request for server %s failed (%d/%s)", - inet_ntop(server->sa_family, addr, ipaddrstring, sizeof(ipaddrstring)), - errno, strerror(errno)); - - if (errno == ENETUNREACH) - __connman_timeserver_sync_next(); - - return; - } - - if (len != sizeof(msg)) { - connman_error("Broken time request for server %s", + if (len < 0 || len != sizeof(msg)) { + DBG("Time request for server %s failed", inet_ntop(server->sa_family, addr, ipaddrstring, sizeof(ipaddrstring))); + nd->cb(false, nd->user_data); return; } @@ -218,34 +219,35 @@ static void send_packet(int fd, struct sockaddr *server, uint32_t timeout) * trying another server. */ - timeout_id = g_timeout_add_seconds(timeout, send_timeout, - GUINT_TO_POINTER(timeout)); + nd->timeout = timeout; + nd->timeout_id = g_timeout_add_seconds(timeout, send_timeout, nd); } static gboolean next_poll(gpointer user_data) { - poll_id = 0; + struct ntp_data *nd = user_data; + nd->poll_id = 0; - if (!timeserver || transmit_fd == 0) + if (!nd->timeserver || nd->transmit_fd == 0) return FALSE; - send_packet(transmit_fd, (struct sockaddr *)×erver_addr, NTP_SEND_TIMEOUT); + send_packet(nd, (struct sockaddr *)&nd->timeserver_addr, NTP_SEND_TIMEOUT); return FALSE; } -static void reset_timeout(void) +static void reset_timeout(struct ntp_data *nd) { - if (timeout_id > 0) { - g_source_remove(timeout_id); - timeout_id = 0; + if (nd->timeout_id > 0) { + g_source_remove(nd->timeout_id); + nd->timeout_id = 0; } - retries = 0; + nd->retries = 0; } -static void decode_msg(void *base, size_t len, struct timeval *tv, - struct timespec *mrx_time) +static void decode_msg(struct ntp_data *nd, void *base, size_t len, + struct timeval *tv, struct timespec *mrx_time) { struct ntp_msg *msg = base; double m_delta, org, rec, xmt, dst; @@ -254,6 +256,7 @@ static void decode_msg(void *base, size_t len, struct timeval *tv, #if !defined TIZEN_EXT struct timex tmx = {}; #endif + if (len < sizeof(*msg)) { connman_error("Invalid response from time server"); return; @@ -281,9 +284,9 @@ static void decode_msg(void *base, size_t len, struct timeval *tv, uint32_t code = ntohl(msg->refid); connman_info("Skipping server %s KoD code %c%c%c%c", - timeserver, code >> 24, code >> 16 & 0xff, + nd->timeserver, code >> 24, code >> 16 & 0xff, code >> 8 & 0xff, code & 0xff); - next_server(); + nd->cb(false, nd->user_data); return; } @@ -291,6 +294,7 @@ static void decode_msg(void *base, size_t len, struct timeval *tv, if (NTP_FLAGS_LI_DECODE(msg->flags) == NTP_FLAG_LI_NOTINSYNC) { DBG("ignoring unsynchronized peer"); + nd->cb(false, nd->user_data); return; } @@ -301,17 +305,19 @@ static void decode_msg(void *base, size_t len, struct timeval *tv, NTP_FLAG_VN_VER4, NTP_FLAGS_VN_DECODE(msg->flags)); } else { DBG("unsupported version %d", NTP_FLAGS_VN_DECODE(msg->flags)); + nd->cb(false, nd->user_data); return; } } if (NTP_FLAGS_MD_DECODE(msg->flags) != NTP_FLAG_MD_SERVER) { DBG("unsupported mode %d", NTP_FLAGS_MD_DECODE(msg->flags)); + nd->cb(false, nd->user_data); return; } - m_delta = mrx_time->tv_sec - mtx_time.tv_sec + - 1.0e-9 * (mrx_time->tv_nsec - mtx_time.tv_nsec); + m_delta = mrx_time->tv_sec - nd->mtx_time.tv_sec + + 1.0e-9 * (mrx_time->tv_nsec - nd->mtx_time.tv_nsec); org = tv->tv_sec + (1.0e-6 * tv->tv_usec) - m_delta + OFFSET_1900_1970; rec = ntohl(msg->rectime.seconds) + @@ -329,18 +335,19 @@ static void decode_msg(void *base, size_t len, struct timeval *tv, /* Remove the timeout, as timeserver has responded */ - reset_timeout(); + reset_timeout(nd); /* * Now poll the server every transmit_delay seconds * for time correction. */ - if (poll_id > 0) - g_source_remove(poll_id); + if (nd->poll_id > 0) + g_source_remove(nd->poll_id); - DBG("Timeserver %s, next sync in %d seconds", timeserver, transmit_delay); + DBG("Timeserver %s, next sync in %d seconds", nd->timeserver, + transmit_delay); - poll_id = g_timeout_add_seconds(transmit_delay, next_poll, NULL); + nd->poll_id = g_timeout_add_seconds(transmit_delay, next_poll, nd); #if defined TIZEN_EXT //send the dbus message to alram-manager @@ -435,18 +442,22 @@ static void decode_msg(void *base, size_t len, struct timeval *tv, tmx.status |= STA_DEL; if (adjtimex(&tmx) < 0) { - connman_error("Failed to adjust time"); + connman_error("Failed to adjust time: %s (%d)", strerror(errno), errno); + nd->cb(false, nd->user_data); return; } DBG("interval/delta/delay/drift %fs/%+.3fs/%.3fs/%+ldppm", - LOGTOD(msg->poll), offset, delay, tmx.freq / 65536); + LOGTOD(msg->poll), offset, delay, tmx.freq / 65536); + + nd->cb(true, nd->user_data); #endif } static gboolean received_data(GIOChannel *channel, GIOCondition condition, gpointer user_data) { + struct ntp_data *nd = user_data; unsigned char buf[128]; struct sockaddr_in6 sender_addr; struct msghdr msg; @@ -463,7 +474,7 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition, if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { connman_error("Problem with timer server channel"); - channel_watch = 0; + nd->channel_watch = 0; return FALSE; } @@ -486,11 +497,11 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition, if (sender_addr.sin6_family == AF_INET) { size = 4; - addr_ptr = &((struct sockaddr_in *)×erver_addr)->sin_addr; + addr_ptr = &((struct sockaddr_in *)&nd->timeserver_addr)->sin_addr; src_ptr = &((struct sockaddr_in *)&sender_addr)->sin_addr; } else if (sender_addr.sin6_family == AF_INET6) { size = 16; - addr_ptr = &((struct sockaddr_in6 *)×erver_addr)->sin6_addr; + addr_ptr = &((struct sockaddr_in6 *)&nd->timeserver_addr)->sin6_addr; src_ptr = &((struct sockaddr_in6 *)&sender_addr)->sin6_addr; } else { connman_error("Not a valid family type"); @@ -514,12 +525,12 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition, } } - decode_msg(iov.iov_base, iov.iov_len, tv, &mrx_time); + decode_msg(nd, iov.iov_base, iov.iov_len, tv, &mrx_time); return TRUE; } -static void start_ntp(char *server) +static void start_ntp(struct ntp_data *nd) { GIOChannel *channel; struct addrinfo hint; @@ -532,14 +543,11 @@ static void start_ntp(char *server) int tos = IPTOS_LOWDELAY, timestamp = 1; int ret; - if (!server) - return; - memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_UNSPEC; hint.ai_socktype = SOCK_DGRAM; hint.ai_flags = AI_NUMERICHOST | AI_PASSIVE; - ret = getaddrinfo(server, NULL, &hint, &info); + ret = getaddrinfo(nd->timeserver, NULL, &hint, &info); if (ret) { connman_error("cannot get server info"); @@ -548,18 +556,18 @@ static void start_ntp(char *server) family = info->ai_family; - memcpy(×erver_addr, info->ai_addr, info->ai_addrlen); + memcpy(&ntp_data->timeserver_addr, info->ai_addr, info->ai_addrlen); freeaddrinfo(info); memset(&in6addr, 0, sizeof(in6addr)); if (family == AF_INET) { - ((struct sockaddr_in *)×erver_addr)->sin_port = htons(123); + ((struct sockaddr_in *)&ntp_data->timeserver_addr)->sin_port = htons(123); in4addr = (struct sockaddr_in *)&in6addr; in4addr->sin_family = family; addr = (struct sockaddr *)in4addr; size = sizeof(struct sockaddr_in); } else if (family == AF_INET6) { - timeserver_addr.sin6_port = htons(123); + ntp_data->timeserver_addr.sin6_port = htons(123); in6addr.sin6_family = family; addr = (struct sockaddr *)&in6addr; size = sizeof(in6addr); @@ -568,96 +576,90 @@ static void start_ntp(char *server) return; } - DBG("server %s family %d", server, family); + DBG("server %s family %d", nd->timeserver, family); - if (channel_watch > 0) + if (nd->channel_watch > 0) goto send; - transmit_fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0); + nd->transmit_fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (transmit_fd <= 0) { - connman_error("Failed to open time server socket"); - return; + if (nd->transmit_fd <= 0) { + if (errno != EAFNOSUPPORT) + connman_error("Failed to open time server socket"); } - if (bind(transmit_fd, (struct sockaddr *) addr, size) < 0) { + if (bind(nd->transmit_fd, (struct sockaddr *) addr, size) < 0) { connman_error("Failed to bind time server socket"); - close(transmit_fd); - return; + goto err; } if (family == AF_INET) { - if (setsockopt(transmit_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { + if (setsockopt(nd->transmit_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { connman_error("Failed to set type of service option"); - close(transmit_fd); - return; + goto err; } } - if (setsockopt(transmit_fd, SOL_SOCKET, SO_TIMESTAMP, ×tamp, + if (setsockopt(nd->transmit_fd, SOL_SOCKET, SO_TIMESTAMP, ×tamp, sizeof(timestamp)) < 0) { connman_error("Failed to enable timestamp support"); - close(transmit_fd); - return; + goto err; } - channel = g_io_channel_unix_new(transmit_fd); - if (!channel) { - close(transmit_fd); - return; - } + channel = g_io_channel_unix_new(nd->transmit_fd); + if (!channel) + goto err; g_io_channel_set_encoding(channel, NULL, NULL); g_io_channel_set_buffered(channel, FALSE); g_io_channel_set_close_on_unref(channel, TRUE); - channel_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, + nd->channel_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - received_data, NULL, NULL); + received_data, nd, NULL); g_io_channel_unref(channel); send: - send_packet(transmit_fd, (struct sockaddr*)×erver_addr, NTP_SEND_TIMEOUT); + send_packet(nd, (struct sockaddr*)&ntp_data->timeserver_addr, + NTP_SEND_TIMEOUT); + return; + +err: + if (nd->transmit_fd > 0) + close(nd->transmit_fd); + + nd->cb(false, nd->user_data); } -int __connman_ntp_start(char *server) +int __connman_ntp_start(char *server, __connman_ntp_cb_t callback, + void *user_data) { - DBG("%s", server); - if (!server) return -EINVAL; - if (timeserver) - g_free(timeserver); + if (ntp_data) { + connman_warn("ntp_data is not NULL (timerserver %s)", + ntp_data->timeserver); + free_ntp_data(ntp_data); + } + + ntp_data = g_new0(struct ntp_data, 1); - timeserver = g_strdup(server); + ntp_data->timeserver = g_strdup(server); + ntp_data->cb = callback; + ntp_data->user_data = user_data; - start_ntp(timeserver); + start_ntp(ntp_data); return 0; } void __connman_ntp_stop() { - DBG(""); - - if (poll_id > 0) { - g_source_remove(poll_id); - poll_id = 0; - } - - reset_timeout(); - - if (channel_watch > 0) { - g_source_remove(channel_watch); - channel_watch = 0; - transmit_fd = 0; - } - - if (timeserver) { - g_free(timeserver); - timeserver = NULL; + if (ntp_data) { + free_ntp_data(ntp_data); + ntp_data = NULL; } } |