timeserver: Periodically wake up to recheck timeservers
authorPatrik Flykt <patrik.flykt@linux.intel.com>
Tue, 21 May 2013 10:32:14 +0000 (13:32 +0300)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Fri, 31 May 2013 08:06:34 +0000 (11:06 +0300)
The current situation is that a failed timeserver name resolution
removes the timeserver immediately from the list of used timeservers
and failing to connect to the nameserver IP address removes the
timeserver after a 2 second delay. Currently no mechanism exists to
re-create the list of nameservers once the list has been exhausted or
the more preferred timeservers have been removed from it.

This implementation combats both problems where less used timeservers
further away end up being used despite a more optimal closer one
becoming available as well as the problem of exhausting the
nameserver list. This is done by periodially waking up and checking
the timeserver in use. If the timeserver in use is not the most
preferred one or the list of timeservers is empty, the timeserver
list is recreated and the timeserver polling procedure is restarted.

src/timeserver.c

index 970b8eb..f3c1220 100644 (file)
 
 #include "connman.h"
 
+#define TS_RECHECK_INTERVAL     7200
+
 static GSList *ts_list = NULL;
+static char *ts_current = NULL;
+static int ts_recheck_id = 0;
 
 static GResolv *resolv = NULL;
 static int resolv_id = 0;
@@ -117,7 +121,10 @@ static void resolv_result(GResolvResultStatus status, char **results, gpointer u
  */
 void __connman_timeserver_sync_next()
 {
-       char *server;
+       if (ts_current != NULL) {
+               g_free(ts_current);
+               ts_current = NULL;
+       }
 
        __connman_ntp_stop();
 
@@ -125,27 +132,24 @@ void __connman_timeserver_sync_next()
        if (ts_list == NULL)
                return;
 
-       server = ts_list->data;
+       ts_current = 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 timeserver %s", server);
+       if (connman_inet_check_ipaddress(ts_current) > 0) {
+               DBG("Using timeserver %s", ts_current);
 
-               __connman_ntp_start(server);
+               __connman_ntp_start(ts_current);
 
-               g_free(server);
                return;
        }
 
-       DBG("Resolving server %s", server);
+       DBG("Resolving server %s", ts_current);
 
-       resolv_id = g_resolv_lookup_hostname(resolv, server,
+       resolv_id = g_resolv_lookup_hostname(resolv, ts_current,
                                                resolv_result, NULL);
 
-       g_free(server);
-
        return;
 }
 
@@ -227,6 +231,58 @@ GSList *__connman_timeserver_get_all(struct connman_service *service)
        return g_slist_reverse(list);
 }
 
+static gboolean ts_recheck(void *user_data)
+{
+       GSList *ts;
+
+       ts = __connman_timeserver_get_all(__connman_service_get_default());
+
+       if (ts == NULL) {
+               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);
+
+               __connman_timeserver_sync(NULL);
+
+               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_current != NULL) {
+               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);
+}
+
 /*
  * This function must be called everytime the default service changes, the
  * service timeserver(s) or gatway changes or the global timeserver(s) changes.
@@ -252,6 +308,8 @@ 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);
 
@@ -266,6 +324,8 @@ int __connman_timeserver_sync(struct connman_service *default_service)
                return 0;
        }
 
+       ts_recheck_enable();
+
         __connman_timeserver_sync_next();
 
        return 0;
@@ -327,6 +387,8 @@ static void timeserver_stop()
        ts_list = NULL;
 
        __connman_ntp_stop();
+
+       ts_recheck_disable();
 }
 
 int __connman_timeserver_system_set(char **servers)