From 6ee357d2304dec43ca6decad222710ba3fa46571 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 25 Apr 2014 16:58:21 +0200 Subject: [PATCH] ntp: use async name resolving for NTP sources Use the new asynchronous call to resolve addresses of NTP servers configured by the server/peer directives. Introduce a callback to be notified when the first resolving attempt ends to correctly finish chronyd initialization (dumpfile reload and reference mode end). --- conf.c | 2 - main.c | 36 +++++++++----- ntp_sources.c | 135 +++++++++++++++++++++++++++++++++++++------------- ntp_sources.h | 9 +++- 4 files changed, 133 insertions(+), 49 deletions(-) diff --git a/conf.c b/conf.c index 3a176e1..e19c5d9 100644 --- a/conf.c +++ b/conf.c @@ -1186,8 +1186,6 @@ CNF_AddSources(void) { NSR_AddUnresolvedSource(ntp_sources[i].params.name, ntp_sources[i].params.port, ntp_sources[i].type, &ntp_sources[i].params.params); } - - NSR_ResolveSources(); } /* ================================================== */ diff --git a/main.c b/main.c index 4de3669..acaaf0d 100644 --- a/main.c +++ b/main.c @@ -123,20 +123,10 @@ signal_cleanup(int x) /* ================================================== */ static void -post_init_ntp_hook(void *anything) +ntp_source_resolving_end(void) { - if (ref_mode == REF_ModeInitStepSlew) { - /* Remove the initstepslew sources and set normal mode */ - NSR_RemoveAllSources(); - ref_mode = REF_ModeNormal; - REF_SetMode(ref_mode); - } + NSR_SetSourceResolvingEndHandler(NULL); - /* Close the pipe to the foreground process so it can exit */ - LOG_CloseParentFd(); - - CNF_AddSources(); - CNF_AddBroadcasts(); if (reload) { /* Note, we want reload to come well after the initialisation from the real time clock - this gives us a fighting chance that the @@ -159,6 +149,28 @@ post_init_ntp_hook(void *anything) /* ================================================== */ +static void +post_init_ntp_hook(void *anything) +{ + if (ref_mode == REF_ModeInitStepSlew) { + /* Remove the initstepslew sources and set normal mode */ + NSR_RemoveAllSources(); + ref_mode = REF_ModeNormal; + REF_SetMode(ref_mode); + } + + /* Close the pipe to the foreground process so it can exit */ + LOG_CloseParentFd(); + + CNF_AddSources(); + CNF_AddBroadcasts(); + + NSR_SetSourceResolvingEndHandler(ntp_source_resolving_end); + NSR_ResolveSources(); +} + +/* ================================================== */ + static void reference_mode_end(int result) { diff --git a/ntp_sources.c b/ntp_sources.c index 7836bfa..1dc5754 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -37,7 +37,7 @@ #include "logging.h" #include "local.h" #include "memory.h" -#include "nameserv.h" +#include "nameserv_async.h" #include "sched.h" /* ================================================== */ @@ -77,9 +77,14 @@ struct UnresolvedSource { static struct UnresolvedSource *unresolved_sources = NULL; static int resolving_interval = 0; static SCH_TimeoutID resolving_id; +static struct UnresolvedSource *resolving_source = NULL; +static NSR_SourceResolvingEndHandler resolving_end_handler = NULL; /* ================================================== */ /* Forward prototypes */ + +static void resolve_sources(void *arg); + static void slew_sources(struct timeval *raw, struct timeval *cooked, @@ -218,42 +223,87 @@ NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParam /* ================================================== */ +static void +name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything) +{ + struct UnresolvedSource *us, **i, *next; + NTP_Remote_Address address; + + us = (struct UnresolvedSource *)anything; + + assert(us == resolving_source); + + switch (status) { + case DNS_TryAgain: + break; + case DNS_Success: + DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(ip_addr)); + address.ip_addr = *ip_addr; + address.port = us->port; + NSR_AddSource(&address, us->type, &us->params); + break; + case DNS_Failure: + LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name); + break; + default: + assert(0); + } + + next = us->next; + + if (status != DNS_TryAgain) { + /* Remove the source from the list */ + for (i = &unresolved_sources; *i; i = &(*i)->next) { + if (*i == us) { + *i = us->next; + Free(us->name); + Free(us); + break; + } + } + } + + resolving_source = next; + + if (next) { + /* Continue with the next source in the list */ + DEBUG_LOG(LOGF_NtpSources, "resolving %s", next->name); + DNS_Name2IPAddressAsync(next->name, name_resolve_handler, next); + } else { + /* This was the last source in the list. If some sources couldn't + be resolved, try again in exponentially increasing interval. */ + if (unresolved_sources) { + if (resolving_interval < 9) + resolving_interval++; + resolving_id = SCH_AddTimeoutByDelay(7 * (1 << resolving_interval), resolve_sources, NULL); + } else { + resolving_interval = 0; + } + + /* This round of resolving is done */ + if (resolving_end_handler) + (resolving_end_handler)(); + } +} + +/* ================================================== */ + static void resolve_sources(void *arg) { - NTP_Remote_Address address; - struct UnresolvedSource *us, **i; - DNS_Status s; + struct UnresolvedSource *us; + + assert(!resolving_source); 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; + /* Start with the first source in the list, name_resolve_handler + will iterate over the rest */ + us = unresolved_sources; - 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; - } + resolving_source = us; + DEBUG_LOG(LOGF_NtpSources, "resolving %s", us->name); + DNS_Name2IPAddressAsync(us->name, name_resolve_handler, us); } /* ================================================== */ @@ -285,14 +335,31 @@ NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParame /* ================================================== */ +void +NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler) +{ + resolving_end_handler = handler; +} + +/* ================================================== */ + void NSR_ResolveSources(void) { /* Try to resolve unresolved sources now */ - if (resolving_interval) { - SCH_RemoveTimeout(resolving_id); - resolving_interval--; - resolve_sources(NULL); + if (unresolved_sources) { + /* Make sure no resolving is currently running */ + if (!resolving_source) { + if (resolving_interval) { + SCH_RemoveTimeout(resolving_id); + resolving_interval--; + } + resolve_sources(NULL); + } + } else { + /* No unresolved sources, we are done */ + if (resolving_end_handler) + (resolving_end_handler)(); } } diff --git a/ntp_sources.h b/ntp_sources.h index cb25e5f..e6cb39f 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -54,7 +54,14 @@ extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type 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 try resolve unresolved sources immediately. */ +/* Function type for handlers to be called back when an attempt + * (possibly unsuccessful) to resolve unresolved sources ends */ +typedef void (*NSR_SourceResolvingEndHandler)(void); + +/* Set the handler, or NULL to disable the notification */ +extern void NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler); + +/* Procedure to start resolving unresolved sources immediately */ extern void NSR_ResolveSources(void); /* Procedure to start all sources */