X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftimeserver.c;h=2601d3631ab9a076bf2c770c5ef25fcba55c8b93;hb=0e9992014e61671dc81685b7ce87c2da39b877fc;hp=d31801f0d339d0de4748043374fec4d15f8da946;hpb=10646e851b488a2da6d24c64792c7956bdefa54e;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/timeserver.c b/src/timeserver.c index d31801f..2601d36 100644 --- a/src/timeserver.c +++ b/src/timeserver.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -28,15 +28,14 @@ #include #include #include +#include #include "connman.h" -static char **system_timeservers = NULL; -static char **timeservers = NULL; +static GSList *ts_list = NULL; static GResolv *resolv = NULL; static int resolv_id = 0; -static volatile int count; static void resolv_debug(const char *str, void *data) { @@ -85,48 +84,12 @@ static char **load_timeservers() return servers; } -/* Restart NTP procedure */ -static void connman_timeserver_restart() -{ - /* If service timeservers are in use, dont restart ntp */ - if (timeservers != NULL) - return; - - if (resolv == NULL) { - DBG("No online service."); - return; - } - - /* Cancel current lookup */ - if(resolv_id > 0) - g_resolv_cancel_lookup(resolv, resolv_id); - - /* Reload system timeserver list */ - if (system_timeservers != NULL) { - g_strfreev(system_timeservers); - system_timeservers = NULL; - } - - system_timeservers = load_timeservers(); - - if (system_timeservers == NULL) - return; - - __connman_ntp_stop(); - - count = 0; - - __connman_timeserver_sync_next(); -} - static void resolv_result(GResolvResultStatus status, char **results, gpointer user_data) { int i; DBG("status %d", status); - __sync_fetch_and_add(&count, 1); - if (status == G_RESOLV_RESULT_STATUS_SUCCESS) { if (results != NULL) { for (i = 0; results[i]; i++) @@ -138,189 +101,243 @@ static void resolv_result(GResolvResultStatus status, char **results, gpointer u } } + /* If resolving fails, move to the next server */ __connman_timeserver_sync_next(); } +/* + * Once the timeserver list (ts_list) is created, we start querying the + * servers one by one. If resolving fails on one of them, we move to the + * next one. The user can enter either an IP address or a URL for the + * timeserver. We only resolve the urls. Once we have a IP for the NTP + * server, we start querying it for time corrections. + */ void __connman_timeserver_sync_next() { - if (system_timeservers == NULL || - system_timeservers[count] == NULL) - return; + char *server; + int ret; + struct addrinfo hints; + struct addrinfo *addr; - DBG("Trying timeserver %s", system_timeservers[count]); + __connman_ntp_stop(); - if (resolv) - resolv_id = g_resolv_lookup_hostname(resolv, - system_timeservers[count], resolv_result, - NULL); -} + /* Get the 1st server in the list */ + if (ts_list == NULL) + return; -int __connman_timeserver_sync(struct connman_service *service) -{ - char **nameservers = NULL; - int i; + server = ts_list->data; - DBG("service %p", service); + ts_list = g_slist_delete_link(ts_list, ts_list); - i = __connman_service_get_index(service); - if (i < 0) - return -EINVAL; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_NUMERICHOST; + addr = NULL; - nameservers = connman_service_get_nameservers(service); - if (nameservers == NULL) - return -EINVAL; + ret = getaddrinfo(server, NULL, &hints, &addr); + freeaddrinfo(addr); - resolv = g_resolv_new(i); - if (resolv == NULL) - return -ENOMEM; + /* if its a IP , directly query it. */ + if (ret == 0) { + DBG("Using timeservers %s", server); - if (getenv("CONNMAN_RESOLV_DEBUG")) - g_resolv_set_debug(resolv, resolv_debug, "RESOLV"); + __connman_ntp_start(server); - for (i = 0; nameservers[i] != NULL; i++) - g_resolv_add_nameserver(resolv, nameservers[i], 53, 0); + g_free(server); + return; + } - count = 0; + DBG("Resolving server %s", server); - system_timeservers = load_timeservers(); + resolv_id = g_resolv_lookup_hostname(resolv, server, + resolv_result, NULL); - timeservers = connman_service_get_timeservers(service); + g_free(server); - if (timeservers != NULL && timeservers[0] != NULL) { - DBG("Using service tiemservers"); - __connman_ntp_start(timeservers[0]); - return 0; - } + return; +} - if (system_timeservers == NULL || system_timeservers[count] == NULL) { - DBG("No timeservers set."); - return 0; - } +GSList *__connman_timeserver_add_list(GSList *server_list, + const char *timeserver) +{ + GSList *list = server_list; - DBG("Trying server %s", system_timeservers[count]); + if (timeserver == NULL) + return server_list; - resolv_id = g_resolv_lookup_hostname(resolv, system_timeservers[count], - resolv_result, NULL); - return 0; + while (list != NULL) { + char *existing_server = list->data; + if (strcmp(timeserver, existing_server) == 0) + return server_list; + list = g_slist_next(list); + } + return g_slist_prepend(server_list, g_strdup(timeserver)); } -void __connman_timeserver_stop() +/* + * __connman_timeserver_get_all function creates the timeserver + * list which will be used to determine NTP server for time corrections. + * The service settings take priority over the global timeservers. + */ +GSList *__connman_timeserver_get_all(struct connman_service *service) { - DBG(" "); - - if (resolv != NULL) { - g_resolv_unref(resolv); - resolv = NULL; + GSList *list = NULL; + struct connman_network *network; + char **timeservers; + char **service_ts; + char **service_ts_config; + const char *service_gw; + char **fallback_ts; + int index, i; + + service_ts_config = connman_service_get_timeservers_config(service); + + /* First add Service Timeservers.Configuration to the list */ + for (i = 0; service_ts_config != NULL && service_ts_config[i] != NULL; + i++) + list = __connman_timeserver_add_list(list, + service_ts_config[i]); + + service_ts = connman_service_get_timeservers(service); + + /* First add Service Timeservers via DHCP to the list */ + for (i = 0; service_ts != NULL && service_ts[i] != NULL; i++) + list = __connman_timeserver_add_list(list, service_ts[i]); + + network = __connman_service_get_network(service); + if (network != NULL) { + index = connman_network_get_index(network); + service_gw = __connman_ipconfig_get_gateway_from_index(index, + CONNMAN_IPCONFIG_TYPE_ALL); + + /* Then add Service Gateway to the list */ + if (service_gw != NULL) + list = __connman_timeserver_add_list(list, service_gw); } - if (system_timeservers != NULL) { - g_strfreev(system_timeservers); - system_timeservers = NULL; - } + /* Then add Global Timeservers to the list */ + timeservers = load_timeservers(); - timeservers = NULL; + for (i = 0; timeservers != NULL && timeservers[i] != NULL; i++) + list = __connman_timeserver_add_list(list, timeservers[i]); - count = 0; + g_strfreev(timeservers); - __connman_ntp_stop(); + fallback_ts = connman_setting_get_string_list("FallbackTimeservers"); + + /* Lastly add the fallback servers */ + for (i = 0; fallback_ts != NULL && fallback_ts[i] != NULL; i++) + list = __connman_timeserver_add_list(list, fallback_ts[i]); + + return g_slist_reverse(list); } -int __connman_timeserver_system_append(const char *server) +/* + * This function must be called everytime the default service changes, the + * service timeserver(s) or gatway changes or the global timeserver(s) changes. + */ +int __connman_timeserver_sync(struct connman_service *default_service) { - int len; - char **servers = NULL; + struct connman_service *service; - if (server == NULL) { - save_timeservers(servers); - goto restart; - } + if (default_service != NULL) + service = default_service; + else + service = __connman_service_get_default(); - DBG("server %s", server); + if (service == NULL) + return -EINVAL; - servers = load_timeservers(); + if (resolv == NULL) + return 0; + /* + * Before we start creating the new timeserver list we must stop + * any ongoing ntp query and server resolution. + */ - if (servers != NULL) { - int i; + __connman_ntp_stop(); - for (i = 0; servers[i] != NULL; i++) - if (g_strcmp0(servers[i], server) == 0) { - g_strfreev(servers); - return -EEXIST; - } + if (resolv_id > 0) + g_resolv_cancel_lookup(resolv, resolv_id); - len = g_strv_length(servers); - servers = g_try_renew(char *, servers, len + 2); - } else { - len = 0; - servers = g_try_new0(char *, len + 2); - } + g_slist_free_full(ts_list, g_free); - if (servers == NULL) - return -ENOMEM; + ts_list = __connman_timeserver_get_all(service); - servers[len] = g_strdup(server); - servers[len + 1] = NULL; + __connman_service_timeserver_changed(service, ts_list); - save_timeservers(servers); + if (ts_list == NULL) { + DBG("No timeservers set."); + return 0; + } - g_strfreev(servers); -restart: - connman_timeserver_restart(); + __connman_timeserver_sync_next(); return 0; } -int __connman_timeserver_system_remove(const char *server) +static int timeserver_start(struct connman_service *service) { - char **servers; - char **temp; - int len, i, j; - - if (server == NULL) - return -EINVAL; + char **nameservers; + int i; - DBG("server %s", server); + DBG("service %p", service); - servers = load_timeservers(); + i = __connman_service_get_index(service); + if (i < 0) + return -EINVAL; - if (servers == NULL) - return 0; + nameservers = connman_service_get_nameservers(service); + if (nameservers == NULL) + return -EINVAL; - len = g_strv_length(servers); - if (len == 1) { - if (g_strcmp0(servers[0], server) != 0) { - g_strfreev(servers); - return 0; - } + /* Stop an already ongoing resolution, if there is one */ + if (resolv != NULL && resolv_id > 0) + g_resolv_cancel_lookup(resolv, resolv_id); - g_strfreev(servers); - servers = NULL; - save_timeservers(servers); - return 0; + /* get rid of the old resolver */ + if (resolv != NULL) { + g_resolv_unref(resolv); + resolv = NULL; } - temp = g_try_new0(char *, len - 1); - if (temp == NULL) { - g_strfreev(servers); - return -ENOMEM; + resolv = g_resolv_new(i); + if (resolv == NULL) { + g_strfreev(nameservers); + return -ENOMEM; } - for (i = 0, j = 0; i < len; i++) { - if (g_strcmp0(servers[i], server) != 0) { - temp[j] = g_strdup(servers[i]); - j++; - } + if (getenv("CONNMAN_RESOLV_DEBUG")) + g_resolv_set_debug(resolv, resolv_debug, "RESOLV"); + + for (i = 0; nameservers[i] != NULL; i++) + g_resolv_add_nameserver(resolv, nameservers[i], 53, 0); + + g_strfreev(nameservers); + + return __connman_timeserver_sync(service); +} + +static void timeserver_stop() +{ + DBG(" "); + + if (resolv != NULL) { + g_resolv_unref(resolv); + resolv = NULL; } - temp[len - 1] = NULL; - g_strfreev(servers); - servers = g_strdupv(temp); - g_strfreev(temp); + g_slist_free_full(ts_list, g_free); + + ts_list = NULL; + + __connman_ntp_stop(); +} +int __connman_timeserver_system_set(char **servers) +{ save_timeservers(servers); - g_strfreev(servers); - connman_timeserver_restart(); + __connman_timeserver_sync(NULL); return 0; } @@ -333,14 +350,31 @@ char **__connman_timeserver_system_get() return servers; } +static void default_changed(struct connman_service *default_service) +{ + if (default_service != NULL) + timeserver_start(default_service); + else + timeserver_stop(); +} + +static struct connman_notifier timeserver_notifier = { + .name = "timeserver", + .default_changed = default_changed, +}; + int __connman_timeserver_init(void) { DBG(""); + connman_notifier_register(×erver_notifier); + return 0; } void __connman_timeserver_cleanup(void) { DBG(""); + + connman_notifier_unregister(×erver_notifier); }