X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftimeserver.c;h=467da52daf6ddc33e7c870401853695ef0395f2a;hb=0bfab55f1a737afedaffeff652fc3e75ee80f2b4;hp=12b604c6fdc02467fab73f7f475cd1c6e90f53b6;hpb=d76088a3c6104f2569279086752a3f3cf1ea6adc;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/timeserver.c b/src/timeserver.c index 12b604c..467da52 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 @@ -23,83 +23,343 @@ #include #endif +#include + #include +#include +#include +#include #include "connman.h" -static GSList *driver_list = NULL; +static GSList *ts_list = NULL; + +static GResolv *resolv = NULL; +static int resolv_id = 0; -static gint compare_priority(gconstpointer a, gconstpointer b) +static void resolv_debug(const char *str, void *data) +{ + connman_info("%s: %s\n", (const char *) data, str); +} +static void save_timeservers(char **servers) { - const struct connman_timeserver_driver *driver1 = a; - const struct connman_timeserver_driver *driver2 = b; + GKeyFile *keyfile; + int cnt; + + keyfile = __connman_storage_load_global(); + if (keyfile == NULL) + keyfile = g_key_file_new(); + + for (cnt = 0; servers != NULL && servers[cnt] != NULL; cnt++); + + g_key_file_set_string_list(keyfile, "global", "Timeservers", + (const gchar **)servers, cnt); - return driver2->priority - driver1->priority; + __connman_storage_save_global(keyfile); + + g_key_file_free(keyfile); + + return; } -/** - * connman_timeserver_driver_register: - * @driver: timeserver driver definition - * - * Register a new timeserver driver - * - * Returns: %0 on success +static char **load_timeservers() +{ + GKeyFile *keyfile; + char **servers = NULL; + + keyfile = __connman_storage_load_global(); + if (keyfile == NULL) + return NULL; + + servers = g_key_file_get_string_list(keyfile, "global", + "Timeservers", NULL, NULL); + + g_key_file_free(keyfile); + + return servers; +} + +static void resolv_result(GResolvResultStatus status, char **results, gpointer user_data) +{ + int i; + + DBG("status %d", status); + + if (status == G_RESOLV_RESULT_STATUS_SUCCESS) { + if (results != NULL) { + for (i = 0; results[i]; i++) + DBG("result: %s", results[i]); + + __connman_ntp_start(results[0]); + + return; + } + } + + /* 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. */ -int connman_timeserver_driver_register(struct connman_timeserver_driver *driver) +void __connman_timeserver_sync_next() { - DBG("driver %p name %s", driver, driver->name); + char *server; - driver_list = g_slist_insert_sorted(driver_list, driver, - compare_priority); + __connman_ntp_stop(); - return 0; + /* Get the 1st server in the list */ + if (ts_list == NULL) + return; + + server = ts_list->data; + + ts_list = g_slist_delete_link(ts_list, ts_list); + + /* if its a IP , directly query it. */ + if (connman_inet_check_ipaddress(server) > 0) { + DBG("Using timeservers %s", server); + + __connman_ntp_start(server); + + g_free(server); + return; + } + + DBG("Resolving server %s", server); + + resolv_id = g_resolv_lookup_hostname(resolv, server, + resolv_result, NULL); + + g_free(server); + + return; } -/** - * connman_timeserver_driver_unregister: - * @driver: timeserver driver definition - * - * Remove a previously registered timeserver driver +GSList *__connman_timeserver_add_list(GSList *server_list, + const char *timeserver) +{ + GSList *list = server_list; + + if (timeserver == NULL) + return server_list; + + 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)); +} + +/* + * __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. */ -void connman_timeserver_driver_unregister(struct connman_timeserver_driver *driver) +GSList *__connman_timeserver_get_all(struct connman_service *service) { - DBG("driver %p name %s", driver, driver->name); + 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); + } + + /* Then add Global Timeservers to the list */ + timeservers = load_timeservers(); + + for (i = 0; timeservers != NULL && timeservers[i] != NULL; i++) + list = __connman_timeserver_add_list(list, timeservers[i]); + + g_strfreev(timeservers); - driver_list = g_slist_remove(driver_list, driver); + 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); } -/** - * connman_timeserver_append: - * @server: server address - * - * Append time server server address to current 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_append(const char *server) +int __connman_timeserver_sync(struct connman_service *default_service) { - DBG("server %s", server); + struct connman_service *service; - if (server == NULL) + if (default_service != NULL) + service = default_service; + else + service = __connman_service_get_default(); + + if (service == NULL) return -EINVAL; - connman_info("Adding time server %s", server); + if (resolv == NULL) + return 0; + /* + * Before we start creating the new timeserver list we must stop + * any ongoing ntp query and server resolution. + */ + + __connman_ntp_stop(); + + if (resolv_id > 0) + g_resolv_cancel_lookup(resolv, resolv_id); + + g_slist_free_full(ts_list, g_free); + + ts_list = __connman_timeserver_get_all(service); + + __connman_service_timeserver_changed(service, ts_list); + + if (ts_list == NULL) { + DBG("No timeservers set."); + return 0; + } + + __connman_timeserver_sync_next(); return 0; } -/** - * connman_timeserver_remove: - * @server: server address - * - * Remover time server server address from current list - */ -int connman_timeserver_remove(const char *server) +static int timeserver_start(struct connman_service *service) { - DBG("server %s", server); + char **nameservers; + int i; + + DBG("service %p", service); + + i = __connman_service_get_index(service); + if (i < 0) + return -EINVAL; - if (server == NULL) + nameservers = connman_service_get_nameservers(service); + if (nameservers == NULL) return -EINVAL; - connman_info("Removing time server %s", server); + /* Stop an already ongoing resolution, if there is one */ + if (resolv != NULL && resolv_id > 0) + g_resolv_cancel_lookup(resolv, resolv_id); + + /* get rid of the old resolver */ + if (resolv != NULL) { + g_resolv_unref(resolv); + resolv = NULL; + } + + resolv = g_resolv_new(i); + if (resolv == NULL) { + g_strfreev(nameservers); + return -ENOMEM; + } + + 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; + } + + g_slist_free_full(ts_list, g_free); + + ts_list = NULL; + + __connman_ntp_stop(); +} + +int __connman_timeserver_system_set(char **servers) +{ + save_timeservers(servers); + + __connman_timeserver_sync(NULL); + + return 0; +} + +char **__connman_timeserver_system_get() +{ + char **servers; + + servers = load_timeservers(); + 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); +}