diff options
Diffstat (limited to 'src/timeserver.c')
-rwxr-xr-x | src/timeserver.c | 180 |
1 files changed, 113 insertions, 67 deletions
diff --git a/src/timeserver.c b/src/timeserver.c index e4cfc062..c6103466 100755 --- a/src/timeserver.c +++ b/src/timeserver.c @@ -34,17 +34,31 @@ #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 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) +{ + DBG("success %d", success); + + if (!success) + sync_next(); +} + static void save_timeservers(char **servers) { GKeyFile *keyfile; @@ -62,8 +76,6 @@ static void save_timeservers(char **servers) __connman_storage_save_global(keyfile); g_key_file_free(keyfile); - - return; } static char **load_timeservers(void) @@ -101,35 +113,60 @@ static void resolv_result(GResolvResultStatus status, char **results, if (status == G_RESOLV_RESULT_STATUS_SUCCESS) { if (results) { - for (i = 0; results[i]; i++) { + /* prepend the results in reverse order */ + + for (i = 0; results[i]; i++) + /* count */; + i--; + + for (; i >= 0; i--) { DBG("result[%d]: %s", i, results[i]); - if (i == 0) - continue; ts_list = __connman_timeserver_add_list( - ts_list, results[i]); + ts_list, results[i]); } + } + } - DBG("Using timeserver %s", results[0]); + sync_next(); +} - __connman_ntp_start(results[0]); +/* + * 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. + */ +static void timeserver_sync_start(void) +{ + GSList *list; - return; - } + for (list = timeservers_list; list; list = list->next) { + char *timeserver = list->data; + + ts_list = g_slist_prepend(ts_list, g_strdup(timeserver)); } + ts_list = g_slist_reverse(ts_list); + + sync_next(); +} + +static gboolean timeserver_sync_restart(gpointer user_data) +{ + timeserver_sync_start(); + ts_backoff_id = 0; - /* If resolving fails, move to the next server */ - __connman_timeserver_sync_next(); + return FALSE; } /* - * 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 an IP for the NTP - * server, we start querying it for time corrections. + * 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. */ -void __connman_timeserver_sync_next() +static void sync_next(void) { if (ts_current) { g_free(ts_current); @@ -138,34 +175,30 @@ void __connman_timeserver_sync_next() __connman_ntp_stop(); - /* Get the 1st server in the list */ - if (!ts_list) - return; - - ts_current = ts_list->data; - - ts_list = g_slist_delete_link(ts_list, ts_list); - - /* if it's an IP, directly query it. */ - if (connman_inet_check_ipaddress(ts_current) > 0) { - DBG("Using timeserver %s", ts_current); + while (ts_list) { + ts_current = ts_list->data; + ts_list = g_slist_delete_link(ts_list, ts_list); - __connman_ntp_start(ts_current); - - return; - } - - DBG("Resolving timeserver %s", ts_current); + /* 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; + } + DBG("Resolving timeserver %s", ts_current); #if defined TIZEN_EXT - resolv_id = g_resolv_lookup_hostname(resolv, ts_current, + resolv_id = g_resolv_lookup_hostname(resolv, ts_current, resolv_result, ts_current); #else - resolv_id = g_resolv_lookup_hostname(resolv, ts_current, + resolv_id = g_resolv_lookup_hostname(resolv, ts_current, resolv_result, NULL); #endif + return; + } - return; + DBG("No timeserver could be used, restart probing in 5 seconds"); + ts_backoff_id = g_timeout_add_seconds(5, timeserver_sync_restart, NULL); } GSList *__connman_timeserver_add_list(GSList *server_list, @@ -218,22 +251,22 @@ GSList *__connman_timeserver_get_all(struct connman_service *service) for (i = 0; service_ts && service_ts[i]; i++) list = __connman_timeserver_add_list(list, service_ts[i]); -#if defined TIZEN_EXT - if (connman_setting_get_bool("UseGatewayTimeserver")) { -#endif - 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); - - /* Then add Service Gateway to the list */ - if (service_gw) - list = __connman_timeserver_add_list(list, service_gw); - } -#if defined TIZEN_EXT + /* + * 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); + } } -#endif + /* Then add Global Timeservers to the list */ timeservers = load_timeservers(); @@ -255,7 +288,7 @@ static gboolean ts_recheck(gpointer user_data) { GSList *ts; - ts = __connman_timeserver_get_all(__connman_service_get_default()); + ts = __connman_timeserver_get_all(connman_service_get_default()); if (!ts) { DBG("timeservers disabled"); @@ -288,6 +321,11 @@ static void ts_recheck_disable(void) 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; @@ -316,11 +354,14 @@ int __connman_timeserver_sync(struct connman_service *default_service) if (default_service) service = default_service; else - service = __connman_service_get_default(); + service = connman_service_get_default(); if (!service) return -EINVAL; + if (service == ts_service) + return -EALREADY; + if (!resolv) return 0; /* @@ -346,20 +387,21 @@ int __connman_timeserver_sync(struct connman_service *default_service) g_strfreev(nameservers); - g_slist_free_full(ts_list, g_free); + g_slist_free_full(timeservers_list, g_free); - ts_list = __connman_timeserver_get_all(service); + timeservers_list = __connman_timeserver_get_all(service); - __connman_service_timeserver_changed(service, ts_list); + __connman_service_timeserver_changed(service, timeservers_list); - if (!ts_list) { + if (!timeservers_list) { DBG("No timeservers set."); return 0; } ts_recheck_enable(); - __connman_timeserver_sync_next(); + ts_service = service; + timeserver_sync_start(); return 0; } @@ -376,8 +418,6 @@ static int timeserver_start(struct connman_service *service) return -EINVAL; nameservers = connman_service_get_nameservers(service); - if (!nameservers) - return -EINVAL; /* Stop an already ongoing resolution, if there is one */ if (resolv && resolv_id > 0) @@ -398,10 +438,12 @@ 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]; 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); + } return __connman_timeserver_sync(service); } @@ -410,13 +452,17 @@ static void timeserver_stop(void) { DBG(" "); + 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(); @@ -449,7 +495,7 @@ static void default_changed(struct connman_service *default_service) timeserver_stop(); } -static struct connman_notifier timeserver_notifier = { +static const struct connman_notifier timeserver_notifier = { .name = "timeserver", .default_changed = default_changed, }; |