#ifdef WORKER
#define INITIAL_DNS_RETRY 2 /* seconds between queries */
+/* flags for extended addrinfo version */
+#define GAIR_F_IGNDNSERR 0x0001 /* ignore DNS errors */
+
/*
* you call getaddrinfo_sometime(name, service, &hints, retry, callback_func, context);
* later (*callback_func)(rescode, gai_errno, context, name, service, hints, ai_result) is called.
extern int getaddrinfo_sometime(const char *, const char *,
const struct addrinfo *, int,
gai_sometime_callback, void *);
+extern int getaddrinfo_sometime_ex(const char *, const char *,
+ const struct addrinfo *, int,
+ gai_sometime_callback, void *, u_int);
/*
* In gai_sometime_callback routines, the resulting addrinfo list is
* only available until the callback returns. To hold on to the list
* is managed by the code which calls the *_complete routines.
*/
+
/* === typedefs === */
typedef struct blocking_gai_req_tag { /* marshalled args */
size_t octets;
u_int dns_idx;
time_t scheduled;
time_t earliest;
- struct addrinfo hints;
int retry;
+ struct addrinfo hints;
+ u_int qflags;
gai_sometime_callback callback;
void * context;
size_t nodesize;
static void scheduled_sleep(time_t, time_t,
dnsworker_ctx *);
static void manage_dns_retry_interval(time_t *, time_t *,
- int *,
- time_t *);
+ int *, time_t *,
+ int/*BOOL*/);
static int should_retry_dns(int, int);
#ifdef HAVE_RES_INIT
static void reload_resolv_conf(dnsworker_ctx *);
* invokes provided callback completion function.
*/
int
-getaddrinfo_sometime(
+getaddrinfo_sometime_ex(
const char * node,
const char * service,
const struct addrinfo * hints,
int retry,
gai_sometime_callback callback,
- void * context
+ void * context,
+ u_int qflags
)
{
blocking_gai_req * gai_req;
gai_req->context = context;
gai_req->nodesize = nodesize;
gai_req->servsize = servsize;
+ gai_req->qflags = qflags;
memcpy((char *)gai_req + sizeof(*gai_req), node, nodesize);
memcpy((char *)gai_req + sizeof(*gai_req) + nodesize, service,
return 0;
}
+int
+getaddrinfo_sometime(
+ const char * node,
+ const char * service,
+ const struct addrinfo * hints,
+ int retry,
+ gai_sometime_callback callback,
+ void * context
+ )
+{
+ return getaddrinfo_sometime_ex(node, service, hints, retry,
+ callback, context, 0);
+}
+
static void
getaddrinfo_sometime_complete(
char * service;
char * canon_start;
time_t time_now;
- int again;
+ int again, noerr;
int af;
const char * fam_spec;
int i;
gai_req->dns_idx, humantime(time_now)));
}
} else {
- again = should_retry_dns(gai_resp->retcode,
- gai_resp->gai_errno);
+ noerr = !!(gai_req->qflags & GAIR_F_IGNDNSERR);
+ again = noerr || should_retry_dns(
+ gai_resp->retcode, gai_resp->gai_errno);
/*
* exponential backoff of DNS retries to 64s
*/
gai_strerror(gai_resp->retcode),
gai_resp->retcode);
}
- manage_dns_retry_interval(&gai_req->scheduled,
- &gai_req->earliest, &gai_req->retry,
- &child_ctx->next_dns_timeslot);
+ manage_dns_retry_interval(
+ &gai_req->scheduled, &gai_req->earliest,
+ &gai_req->retry, &child_ctx->next_dns_timeslot,
+ noerr);
if (!queue_blocking_request(
BLOCKING_GETADDRINFO,
gai_req,
if (gni_req->retry > 0)
manage_dns_retry_interval(&gni_req->scheduled,
&gni_req->earliest, &gni_req->retry,
- &child_ctx->next_dns_timeslot);
+ &child_ctx->next_dns_timeslot, FALSE);
if (gni_req->retry > 0 && again) {
if (!queue_blocking_request(
time_t * pscheduled,
time_t * pwhen,
int * pretry,
- time_t * pnext_timeslot
+ time_t * pnext_timeslot,
+ int forever
)
{
time_t now;
time_t when;
int retry;
+ int retmax;
now = time(NULL);
retry = *pretry;
when = max(now + retry, *pnext_timeslot);
*pnext_timeslot = when;
- retry = min(64, retry << 1);
+
+ /* this exponential backoff is slower than doubling up: The
+ * sequence goes 2-3-4-6-8-12-16-24-32... and the upper limit is
+ * 64 seconds for things that should not repeat forever, and
+ * 1024 when repeated forever.
+ */
+ retmax = forever ? 1024 : 64;
+ retry <<= 1;
+ if (retry & (retry - 1))
+ retry &= (retry - 1);
+ else
+ retry -= (retry >> 2);
+ retry = min(retmax, retry);
*pscheduled = now;
*pwhen = when;
#include "ntp_parser.h"
#include "ntpd-opts.h"
+#ifndef IGNORE_DNS_ERRORS
+# define DNSFLAGS 0
+#else
+# define DNSFLAGS GAIR_F_IGNDNSERR
+#endif
+
extern int yyparse(void);
/* Bug 2817 */
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
- getaddrinfo_sometime(*cmdline_servers,
+ getaddrinfo_sometime_ex(*cmdline_servers,
"ntp", &hints,
INITIAL_DNS_RETRY,
&peer_name_resolved,
- (void *)ctx);
+ (void *)ctx, DNSFLAGS);
# else /* !WORKER follows */
msyslog(LOG_ERR,
"hostname %s can not be used, please use IP address instead.",
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
- getaddrinfo_sometime(curr_peer->addr->address,
+ getaddrinfo_sometime_ex(curr_peer->addr->address,
"ntp", &hints,
INITIAL_DNS_RETRY,
- &peer_name_resolved, ctx);
+ &peer_name_resolved, ctx,
+ DNSFLAGS);
# else /* !WORKER follows */
msyslog(LOG_ERR,
"hostname %s can not be used, please use IP address instead.",
DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
if (rescode) {
-#ifndef IGNORE_DNS_ERRORS
free(ctx);
msyslog(LOG_ERR,
"giving up resolving host %s: %s (%d)",
name, gai_strerror(rescode), rescode);
-#else /* IGNORE_DNS_ERRORS follows */
- getaddrinfo_sometime(name, service, hints,
- INITIAL_DNS_RETRY,
- &peer_name_resolved, context);
-#endif
return;
}