]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
Add delayed name resolving for servers and peers
authorMiroslav Lichvar <mlichvar@redhat.com>
Mon, 26 Apr 2010 15:38:09 +0000 (17:38 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Tue, 27 Apr 2010 12:35:28 +0000 (14:35 +0200)
Resolving is retried in increasing intervals (maximum is one hour)
until it succeeds or fails with a non-temporary error.

Unresolved sources are included in the activity report as offline
sources and the online command can be used to retry it immediately.

This could be improved by resolving in a separate thread/process
to avoid blocking.

client.c
cmdparse.c
cmdparse.h
conf.c
ntp_sources.c
ntp_sources.h

index c2af79c0f69f2383bf1131a54467ac26923f4abe..899732fb3d4f7931984a7f46a1f3685bff97901d 100644 (file)
--- a/client.c
+++ b/client.c
@@ -902,6 +902,13 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
   status = CPS_ParseNTPSourceAdd(line, &data);
   switch (status) {
     case CPS_Success:
+      /* Don't retry name resolving */
+      if (data.ip_addr.family == IPADDR_UNSPEC) {
+        Free(data.name);
+        fprintf(stderr, "Invalid host/IP address\n");
+        break;
+      }
+
       msg->data.ntp_source.port = htonl((unsigned long) data.port);
       UTI_IPHostToNetwork(&data.ip_addr, &msg->data.ntp_source.ip_addr);
       msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
index 668e08d709052643826a2edef4ecafb1d5ff1cdd..5dad262faa83e462d84df3e10b32e16ceaad32aa 100644 (file)
@@ -33,6 +33,7 @@
 #include "sysincl.h"
 
 #include "cmdparse.h"
+#include "memory.h"
 #include "nameserv.h"
 
 #define MAXLEN 2047
@@ -66,6 +67,10 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
     s = DNS_Name2IPAddress(hostname, &src->ip_addr);
     if (s == DNS_Success) {
       ok = 1;
+      src->name = NULL;
+    } else if (s == DNS_TryAgain) {
+      ok = 1;
+      src->ip_addr.family = IPADDR_UNSPEC;
     }
   }
 
@@ -160,6 +165,13 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
     } while (!done);
   }
 
+  if (ok && src->ip_addr.family == IPADDR_UNSPEC) {
+    n = strlen(hostname);
+    src->name = MallocArray(char, n + 1);
+    strncpy(src->name, hostname, n);
+    src->name[n] = '\0';
+  }
+
   return result;
     
 }
index 30fea4944bf43102a7ecf38fce907e0a3167ce52..7523d8e43e9c396b9310343c92372304219002d4 100644 (file)
@@ -49,6 +49,7 @@ typedef enum {
 
 typedef struct {
   IPAddr ip_addr;
+  char *name;
   unsigned short port;
   SourceParameters params;
 } CPS_NTP_Source;
diff --git a/conf.c b/conf.c
index 0f049b549bb2c60eab8c7a7618e8b54165f3c888..1556c2fe9ac1eeaaab3c26b8af015b5529d8bdce 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -262,9 +262,7 @@ static int line_number;
 
 typedef struct {
   NTP_Source_Type type;
-  IPAddr ip_addr;
-  unsigned short port;
-  SourceParameters params;
+  CPS_NTP_Source params;
 } NTP_Source;
 
 #define MAX_NTP_SOURCES 64
@@ -355,23 +353,14 @@ CNF_ReadFile(const char *filename)
 static void
 parse_source(const char *line, NTP_Source_Type type)
 {
-  int i;
-  NTP_Source s;
   CPS_Status status;
-  CPS_NTP_Source params;
 
-  s.type = type;
-  status = CPS_ParseNTPSourceAdd(line, &params);
+  ntp_sources[n_ntp_sources].type = type;
+  status = CPS_ParseNTPSourceAdd(line, &ntp_sources[n_ntp_sources].params);
 
   switch (status) {
     case CPS_Success:
-      s.port = params.port;
-      s.ip_addr = params.ip_addr;
-      s.params = params.params;
-
-      i = n_ntp_sources++;
-      ntp_sources[i] = s;
-
+      n_ntp_sources++;
       break;
     case CPS_BadOption:
       LOG(LOGS_WARN, LOGF_Configure, "Unrecognized subcommand at line %d", line_number);
@@ -1191,11 +1180,16 @@ CNF_AddSources(void) {
   int i;
 
   for (i=0; i<n_ntp_sources; i++) {
-    server.ip_addr = ntp_sources[i].ip_addr;
-    memset(&server.local_ip_addr, 0, sizeof (server.local_ip_addr));
-    server.port = ntp_sources[i].port;
+    if (ntp_sources[i].params.ip_addr.family != IPADDR_UNSPEC) {
+      server.ip_addr = ntp_sources[i].params.ip_addr;
+      memset(&server.local_ip_addr, 0, sizeof (server.local_ip_addr));
+      server.port = ntp_sources[i].params.port;
 
-    NSR_AddSource(&server, ntp_sources[i].type, &ntp_sources[i].params);
+      NSR_AddSource(&server, ntp_sources[i].type, &ntp_sources[i].params.params);
+    } else {
+      NSR_AddUnresolvedSource(ntp_sources[i].params.name, ntp_sources[i].params.port,
+          ntp_sources[i].type, &ntp_sources[i].params.params);
+    }
   }
 
   return;
index cc37435ff09143c5a2f001726b3eed7310ae2567..b7151f228fd3fcda3a02f00cb237ef7aaae92515 100644 (file)
@@ -37,6 +37,9 @@
 #include "util.h"
 #include "logging.h"
 #include "local.h"
+#include "memory.h"
+#include "nameserv.h"
+#include "sched.h"
 
 /* ================================================== */
 
@@ -60,6 +63,19 @@ static int n_sources;
 /* The largest number of sources we want to have stored in the hash table */
 #define MAX_SOURCES 64
 
+/* Source with unknown address (which may be resolved later) */
+struct UnresolvedSource {
+  char *name;
+  int port;
+  NTP_Source_Type type;
+  SourceParameters params;
+  struct UnresolvedSource *next;
+};
+
+static struct UnresolvedSource *unresolved_sources = NULL;
+static int resolving_interval = 0;
+static SCH_TimeoutID resolving_id;
+
 /* ================================================== */
 /* Forward prototypes */
 static void
@@ -203,6 +219,75 @@ NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParam
 
 /* ================================================== */
 
+static void
+resolve_sources(void *arg)
+{
+  NTP_Remote_Address address;
+  struct UnresolvedSource *us, **i;
+  DNS_Status s;
+
+  memset(&address.local_ip_addr, 0, sizeof (address.local_ip_addr));
+
+  DNS_Reload();
+
+  for (i = &unresolved_sources; *i; ) {
+    us = *i;
+    s = DNS_Name2IPAddress(us->name, &address.ip_addr);
+    if (s == DNS_TryAgain) {
+      i = &(*i)->next;
+      continue;
+    } else if (s == DNS_Success) {
+      address.port = us->port;
+      NSR_AddSource(&address, us->type, &us->params);
+    } else {
+      LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name);
+    }
+    
+    *i = us->next;
+
+    Free(us->name);
+    Free(us);
+  }
+
+  if (unresolved_sources) {
+    /* Try again later */
+    if (resolving_interval < 9)
+      resolving_interval++;
+    resolving_id = SCH_AddTimeoutByDelay(7 * (1 << resolving_interval), resolve_sources, NULL);
+  } else {
+    resolving_interval = 0;
+  }
+}
+
+/* ================================================== */
+
+/* Procedure to add a new server or peer source, but instead of an IP address
+   only a name is provided */
+void
+NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params)
+{
+  struct UnresolvedSource *us, **i;
+
+  us = MallocNew(struct UnresolvedSource);
+
+  us->name = name;
+  us->port = port;
+  us->type = type;
+  us->params = *params;
+  us->next = NULL;
+
+  for (i = &unresolved_sources; *i; i = &(*i)->next)
+    ;
+  *i = us;
+
+  if (!resolving_interval) {
+    resolving_interval = 2;
+    resolving_id = SCH_AddTimeoutByDelay(7 * (1 << resolving_interval), resolve_sources, NULL);
+  }
+}
+
+/* ================================================== */
+
 /* Procedure to remove a source.  We don't bother whether the port
    address is matched - we're only interested in removing a record for
    the right IP address.  Thus the caller can specify the port number
@@ -311,6 +396,13 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
     }
   }
 
+  if (resolving_interval) {
+    /* Try to resolve any unresolved sources now */
+    SCH_RemoveTimeout(resolving_id);
+    resolving_interval--;
+    resolve_sources(NULL);
+  }
+
   return any;
 }
 
@@ -472,6 +564,7 @@ void
 NSR_GetActivityReport(RPT_ActivityReport *report)
 {
   int i;
+  struct UnresolvedSource *us;
 
   report->online = 0;
   report->offline = 0;
@@ -484,6 +577,12 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
                                     &report->burst_online, &report->burst_offline);
     }
   }
+
+  /* Add unresolved sources to offline count */
+  for (us = unresolved_sources; us; us = us->next) {
+    report->offline++;
+  }
+
   return;
 }
 
index eaef8a8146a452b07a76615be802f4dcb15e7464..d69ee0dea4c739c2aaed798278aacf54e02bb450 100644 (file)
@@ -53,6 +53,11 @@ typedef enum {
 /* Procedure to add a new server or peer source. */
 extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
 
+/* Procedure to add a new server or peer source with currently unknown address.
+   The name will be periodically resolved in exponentially increasing intervals
+   until it succeeds or fails with a non-temporary error. */
+extern void NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params);
+
 /* Procedure to remove a source */
 extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);