Register with system bus in container environment
[platform/upstream/connman.git] / src / ntp.c
index 11512a0..0de4df7 100755 (executable)
--- a/src/ntp.c
+++ b/src/ntp.c
@@ -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 *)&timeserver_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 *)&timeserver_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 *)&timeserver_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 *)&timeserver_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
@@ -374,10 +381,10 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
                clock_gettime(CLOCK_REALTIME, &req);
                msg = dbus_message_new_method_call(TIME_BUS_NAME, TIME_PATH,
                        TIME_INTERFACE, TIME_METHOD);
-               dbus_message_append_args(msg, DBUS_TYPE_UINT32, &(cur.tv_sec),
-                       DBUS_TYPE_UINT32, &(cur.tv_nsec),
-                       DBUS_TYPE_UINT32, &(req.tv_sec),
-                       DBUS_TYPE_UINT32, &(req.tv_nsec), DBUS_TYPE_INVALID);
+               dbus_message_append_args(msg, DBUS_TYPE_INT64, &(cur.tv_sec),
+                       DBUS_TYPE_INT64, &(cur.tv_nsec),
+                       DBUS_TYPE_INT64, &(req.tv_sec),
+                       DBUS_TYPE_INT64, &(req.tv_nsec), DBUS_TYPE_INVALID);
                reply = dbus_connection_send_with_reply_and_block(connection, msg,
                                DBUS_TIMEOUT_USE_DEFAULT, &error);
                if(reply == NULL){
@@ -400,6 +407,8 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
                DBG("%lu cur seconds, %lu cur nsecs, %lu req seconds, %lu req nsecs",
                        cur.tv_sec, cur.tv_nsec, req.tv_sec, req.tv_nsec);
                DBG("setting time");
+
+               __connman_clock_set_time_updated(true);
        }
 #else
        if (offset < STEPTIME_MIN_OFFSET && offset > -STEPTIME_MIN_OFFSET) {
@@ -435,18 +444,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 +476,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 +499,11 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
 
        if (sender_addr.sin6_family == AF_INET) {
                size = 4;
-               addr_ptr = &((struct sockaddr_in *)&timeserver_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 *)&timeserver_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 +527,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 +545,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 +558,18 @@ static void start_ntp(char *server)
 
        family = info->ai_family;
 
-       memcpy(&timeserver_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 *)&timeserver_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 +578,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, &timestamp,
+       if (setsockopt(nd->transmit_fd, SOL_SOCKET, SO_TIMESTAMP, &timestamp,
                                                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*)&timeserver_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;
        }
 }