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
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);
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;
#include "util.h"
#include "logging.h"
#include "local.h"
+#include "memory.h"
+#include "nameserv.h"
+#include "sched.h"
/* ================================================== */
/* 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
/* ================================================== */
+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
}
}
+ if (resolving_interval) {
+ /* Try to resolve any unresolved sources now */
+ SCH_RemoveTimeout(resolving_id);
+ resolving_interval--;
+ resolve_sources(NULL);
+ }
+
return any;
}
NSR_GetActivityReport(RPT_ActivityReport *report)
{
int i;
+ struct UnresolvedSource *us;
report->online = 0;
report->offline = 0;
&report->burst_online, &report->burst_offline);
}
}
+
+ /* Add unresolved sources to offline count */
+ for (us = unresolved_sources; us; us = us->next) {
+ report->offline++;
+ }
+
return;
}
/* 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);