From aa91c608f4c5a1a4ad3acc4b2bfbbfac4e1959dc Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Mon, 26 Apr 2010 17:38:09 +0200 Subject: [PATCH] Add delayed name resolving for servers and peers 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 | 7 ++++ cmdparse.c | 12 +++++++ cmdparse.h | 1 + conf.c | 32 +++++++---------- ntp_sources.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++ ntp_sources.h | 5 +++ 6 files changed, 137 insertions(+), 19 deletions(-) diff --git a/client.c b/client.c index c2af79c..899732f 100644 --- 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); diff --git a/cmdparse.c b/cmdparse.c index 668e08d..5dad262 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -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; } diff --git a/cmdparse.h b/cmdparse.h index 30fea49..7523d8e 100644 --- a/cmdparse.h +++ b/cmdparse.h @@ -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 0f049b5..1556c2f 100644 --- 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, ¶ms); + 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; iname, &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; } diff --git a/ntp_sources.h b/ntp_sources.h index eaef8a8..d69ee0d 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -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);