X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftimeserver.c;h=2df609f3907d30a0630333c94747eab213366971;hb=8a2395563cbaef0b56da21d56df2eea10a2c3c20;hp=9a5827a2a2c269d71f36a86b84758869b3983d47;hpb=87aec23ff8b680fde1a26a5883aa6576f0a15a1a;p=platform%2Fupstream%2Fconnman.git diff --git a/src/timeserver.c b/src/timeserver.c old mode 100644 new mode 100755 index 9a5827a..2df609f --- 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-2013 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 @@ -29,28 +29,64 @@ #include #include #include +#include #include "connman.h" +#define TS_RECHECK_INTERVAL 7200 + +static struct connman_service *ts_service; +static GSList *timeservers_list = NULL; static GSList *ts_list = NULL; +static char *ts_current = NULL; +static int ts_recheck_id = 0; +static int ts_backoff_id = 0; +static bool ts_is_synced = false; static GResolv *resolv = NULL; static int resolv_id = 0; +static void sync_next(void); + static void resolv_debug(const char *str, void *data) { connman_info("%s: %s\n", (const char *) data, str); } + +static void ntp_callback(bool success, void *user_data) +{ + dbus_uint64_t timestamp; + struct timeval tv; + + DBG("success %d", success); + + __connman_timeserver_set_synced(success); + if (!success) { + sync_next(); + return; + } + + if (gettimeofday(&tv, NULL) < 0) { + connman_warn("Failed to get current time"); + } + + timestamp = tv.tv_sec; + connman_dbus_property_changed_basic( + CONNMAN_MANAGER_PATH, + CONNMAN_CLOCK_INTERFACE, "Time", + DBUS_TYPE_UINT64, ×tamp); +} + static void save_timeservers(char **servers) { GKeyFile *keyfile; int cnt; keyfile = __connman_storage_load_global(); - if (keyfile == NULL) + if (!keyfile) keyfile = g_key_file_new(); - for (cnt = 0; servers != NULL && servers[cnt] != NULL; cnt++); + for (cnt = 0; servers && servers[cnt]; cnt++); g_key_file_set_string_list(keyfile, "global", "Timeservers", (const gchar **)servers, cnt); @@ -58,102 +94,155 @@ static void save_timeservers(char **servers) __connman_storage_save_global(keyfile); g_key_file_free(keyfile); - - return; } -static char **load_timeservers() +static char **load_timeservers(void) { GKeyFile *keyfile; - GError *error = NULL; char **servers = NULL; keyfile = __connman_storage_load_global(); - if (keyfile == NULL) + if (!keyfile) return NULL; servers = g_key_file_get_string_list(keyfile, "global", - "Timeservers", NULL, &error); - if (error) { - DBG("Error loading timeservers: %s", error->message); - g_error_free(error); - } + "Timeservers", NULL, NULL); g_key_file_free(keyfile); return servers; } -static void resolv_result(GResolvResultStatus status, char **results, gpointer user_data) +static void resolv_result(GResolvResultStatus status, char **results, + gpointer user_data) { int i; +#if defined TIZEN_EXT + gchar *server = NULL; + + server = g_strdup((gchar *)user_data); + ts_list = g_slist_append(ts_list, server); + + if (!simplified_log) + DBG("added server %s", server); + + if (!simplified_log) +#endif DBG("status %d", status); if (status == G_RESOLV_RESULT_STATUS_SUCCESS) { - if (results != NULL) { + if (results) { + /* prepend the results in reverse order */ + for (i = 0; results[i]; i++) - DBG("result: %s", results[i]); + /* count */; + i--; - __connman_ntp_start(results[0]); + for (; i >= 0; i--) { + DBG("result[%d]: %s", i, results[i]); - return; + ts_list = __connman_timeserver_add_list( + ts_list, results[i]); + } } } - /* If resolving fails, move to the next server */ - __connman_timeserver_sync_next(); + 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. + * Once the timeserver list (timeserver_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 an + * IP for the NTP server, we start querying it for time corrections. */ -void __connman_timeserver_sync_next() +static void timeserver_sync_start(void) { - char *server; - int ret; - struct addrinfo hints; - struct addrinfo *addr; + GSList *list; - __connman_ntp_stop(); + for (list = timeservers_list; list; list = list->next) { + char *timeserver = list->data; - /* Get the 1st server in the list */ - if (ts_list == NULL) - return; + ts_list = g_slist_prepend(ts_list, g_strdup(timeserver)); + } + ts_list = g_slist_reverse(ts_list); + + sync_next(); +} - server = ts_list->data; +static gboolean timeserver_sync_restart(gpointer user_data) +{ + timeserver_sync_start(); + ts_backoff_id = 0; - ts_list = g_slist_delete_link(ts_list, ts_list); + return FALSE; +} - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = AI_NUMERICHOST; - addr = NULL; +/* + * Select the next time server from the working list (ts_list) because + * for some reason the first time server in the list didn't work. If + * none of the server did work we start over with the first server + * with a backoff. + */ +static void sync_next(void) +{ + if (ts_current) { + g_free(ts_current); + ts_current = NULL; + } - ret = getaddrinfo(server, NULL, &hints, &addr); - freeaddrinfo(addr); + __connman_ntp_stop(); - /* if its a IP , directly query it. */ - if (ret == 0) { - DBG("Using timeservers %s", server); + while (ts_list) { + ts_current = ts_list->data; + ts_list = g_slist_delete_link(ts_list, ts_list); - __connman_ntp_start(server); + /* if it's an IP, directly query it. */ + if (connman_inet_check_ipaddress(ts_current) > 0) { + DBG("Using timeserver %s", ts_current); + __connman_ntp_start(ts_current, ntp_callback, NULL); + return; + } +#if defined TIZEN_EXT + if (ts_current[0] == '\0') { + DBG("current time server is empty. ignore next time server.."); + return; + } - g_free(server); + if (!simplified_log) +#endif + DBG("Resolving timeserver %s", ts_current); +#if defined TIZEN_EXT + resolv_id = g_resolv_lookup_hostname(resolv, ts_current, + resolv_result, ts_current); +#else + resolv_id = g_resolv_lookup_hostname(resolv, ts_current, + resolv_result, NULL); +#endif return; } - DBG("Resolving server %s", server); + DBG("No timeserver could be used, restart probing in 5 seconds"); + ts_backoff_id = g_timeout_add_seconds(5, timeserver_sync_restart, NULL); +} - resolv_id = g_resolv_lookup_hostname(resolv, server, - resolv_result, NULL); +GSList *__connman_timeserver_add_list(GSList *server_list, + const char *timeserver) +{ + GSList *list = server_list; - g_free(server); + if (!timeserver) + return server_list; - return; + while (list) { + 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)); } /* @@ -172,64 +261,125 @@ GSList *__connman_timeserver_get_all(struct connman_service *service) char **fallback_ts; int index, i; + if (__connman_clock_timeupdates() == TIME_UPDATES_MANUAL) + return NULL; + 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; + for (i = 0; service_ts_config && service_ts_config[i]; i++) - list = g_slist_prepend(list, g_strdup(service_ts_config[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 = g_slist_prepend(list, g_strdup(service_ts[i])); + /* Then add Service Timeservers via DHCP to the list */ + for (i = 0; service_ts && service_ts[i]; i++) + list = __connman_timeserver_add_list(list, service_ts[i]); - network = __connman_service_get_network(service); - - index = connman_network_get_index(network); - - service_gw = __connman_ipconfig_get_gateway_from_index(index); - - /* Then add Service Gateway to the list */ - if (service_gw != NULL) - list = g_slist_prepend(list, g_strdup(service_gw)); + /* + * Then add Service Gateway to the list, if UseGatewaysAsTimeservers + * configuration option is set to true. + */ + if (connman_setting_get_bool("UseGatewaysAsTimeservers")) { + network = __connman_service_get_network(service); + if (network) { + index = connman_network_get_index(network); + service_gw = __connman_ipconfig_get_gateway_from_index(index, + CONNMAN_IPCONFIG_TYPE_ALL); + + if (service_gw) + list = __connman_timeserver_add_list(list, service_gw); + } + } /* Then add Global Timeservers to the list */ timeservers = load_timeservers(); - for (i = 0; timeservers != NULL && timeservers[i] != NULL; i++) - list = g_slist_prepend(list, g_strdup(timeservers[i])); + for (i = 0; timeservers && timeservers[i]; i++) + list = __connman_timeserver_add_list(list, timeservers[i]); g_strfreev(timeservers); 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 = g_slist_prepend(list, g_strdup(fallback_ts[i])); + for (i = 0; fallback_ts && fallback_ts[i]; i++) + list = __connman_timeserver_add_list(list, fallback_ts[i]); return g_slist_reverse(list); } -/* - * 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) +static gboolean ts_recheck(gpointer user_data) { struct connman_service *service; + GSList *ts; - if (default_service != NULL) - service = default_service; - else - service = __connman_service_get_default(); + ts = __connman_timeserver_get_all(connman_service_get_default()); - if (service == NULL) - return -EINVAL; + if (!ts) { + DBG("timeservers disabled"); + + return TRUE; + } + + if (g_strcmp0(ts_current, ts->data) != 0) { + DBG("current %s preferred %s", ts_current, (char *)ts->data); + + g_slist_free_full(ts, g_free); + + service = connman_service_get_default(); + __connman_timeserver_sync(service); + + return FALSE; + } + + DBG(""); + + g_slist_free_full(ts, g_free); + + return TRUE; +} + +static void ts_recheck_disable(void) +{ + if (ts_recheck_id == 0) + return; + + g_source_remove(ts_recheck_id); + ts_recheck_id = 0; + + if (ts_backoff_id) { + g_source_remove(ts_backoff_id); + ts_backoff_id = 0; + } + + if (ts_current) { + g_free(ts_current); + ts_current = NULL; + } +} + +static void ts_recheck_enable(void) +{ + if (ts_recheck_id > 0) + return; + + ts_recheck_id = g_timeout_add_seconds(TS_RECHECK_INTERVAL, ts_recheck, + NULL); +} + +static void ts_reset(struct connman_service *service) +{ + char **nameservers; + int i; + + if (!resolv) + return; + + __connman_timeserver_set_synced(false); - if (resolv == NULL) - return 0; /* * Before we start creating the new timeserver list we must stop * any ongoing ntp query and server resolution. @@ -237,21 +387,72 @@ int __connman_timeserver_sync(struct connman_service *default_service) __connman_ntp_stop(); + ts_recheck_disable(); + if (resolv_id > 0) g_resolv_cancel_lookup(resolv, resolv_id); - g_slist_free_full(ts_list, g_free); + g_resolv_flush_nameservers(resolv); + + nameservers = connman_service_get_nameservers(service); + if (nameservers) { + for (i = 0; nameservers[i]; i++) + g_resolv_add_nameserver(resolv, nameservers[i], 53, 0); + + g_strfreev(nameservers); + } + + g_slist_free_full(timeservers_list, g_free); + + timeservers_list = __connman_timeserver_get_all(service); - ts_list = __connman_timeserver_get_all(service); + __connman_service_timeserver_changed(service, timeservers_list); - if (ts_list == NULL) { + if (!timeservers_list) { DBG("No timeservers set."); - return 0; + return; } - __connman_timeserver_sync_next(); + ts_recheck_enable(); - return 0; + ts_service = service; + timeserver_sync_start(); +} + +void __connman_timeserver_sync(struct connman_service *service) +{ + if (!service || ts_service == service) + return; + + ts_reset(service); +} + +void __connman_timeserver_conf_update(struct connman_service *service) +{ + if (!service || (ts_service && ts_service != service)) + return; + + ts_reset(service); +} + + +bool __connman_timeserver_is_synced(void) +{ + return ts_is_synced; +} + +void __connman_timeserver_set_synced(bool status) +{ + dbus_bool_t is_synced; + + if (ts_is_synced == status) + return; + + ts_is_synced = status; + is_synced = status; + connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH, + CONNMAN_CLOCK_INTERFACE, "TimeserverSynced", + DBUS_TYPE_BOOLEAN, &is_synced); } static int timeserver_start(struct connman_service *service) @@ -266,21 +467,19 @@ static int timeserver_start(struct connman_service *service) return -EINVAL; nameservers = connman_service_get_nameservers(service); - if (nameservers == NULL) - return -EINVAL; /* Stop an already ongoing resolution, if there is one */ - if (resolv != NULL && resolv_id > 0) + if (resolv && resolv_id > 0) g_resolv_cancel_lookup(resolv, resolv_id); /* get rid of the old resolver */ - if (resolv != NULL) { + if (resolv) { g_resolv_unref(resolv); resolv = NULL; } resolv = g_resolv_new(i); - if (resolv == NULL) { + if (!resolv) { g_strfreev(nameservers); return -ENOMEM; } @@ -288,35 +487,49 @@ static int timeserver_start(struct connman_service *service) 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); + if (nameservers) { + for (i = 0; nameservers[i]; i++) + g_resolv_add_nameserver(resolv, nameservers[i], 53, 0); + + g_strfreev(nameservers); + } - g_strfreev(nameservers); + __connman_timeserver_sync(service); - return __connman_timeserver_sync(service); + return 0; } -static void timeserver_stop() +static void timeserver_stop(void) { DBG(" "); - if (resolv != NULL) { + ts_service = NULL; + + if (resolv) { g_resolv_unref(resolv); resolv = NULL; } - g_slist_free_full(ts_list, g_free); + g_slist_free_full(timeservers_list, g_free); + timeservers_list = NULL; + g_slist_free_full(ts_list, g_free); ts_list = NULL; __connman_ntp_stop(); + + ts_recheck_disable(); } int __connman_timeserver_system_set(char **servers) { + struct connman_service *service; + save_timeservers(servers); - __connman_timeserver_sync(NULL); + service = connman_service_get_default(); + if (service) + ts_reset(service); return 0; } @@ -331,13 +544,13 @@ char **__connman_timeserver_system_get() static void default_changed(struct connman_service *default_service) { - if (default_service != NULL) + if (default_service) timeserver_start(default_service); else timeserver_stop(); } -static struct connman_notifier timeserver_notifier = { +static const struct connman_notifier timeserver_notifier = { .name = "timeserver", .default_changed = default_changed, };