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.
This commit is contained in:
Miroslav Lichvar 2010-04-26 17:38:09 +02:00
parent 3d260d41b3
commit aa91c608f4
6 changed files with 137 additions and 19 deletions

View file

@ -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);

View 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;
}

View file

@ -49,6 +49,7 @@ typedef enum {
typedef struct {
IPAddr ip_addr;
char *name;
unsigned short port;
SourceParameters params;
} CPS_NTP_Source;

32
conf.c
View file

@ -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;

View 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;
}

View 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);