Retry stub with different upstream after timeout

Backing off the broken upsteams so they are tried again (increasingly less)
This commit is contained in:
Willem Toorop 2014-10-16 14:24:13 +02:00
parent 29d5b3e06c
commit 623c9b04a5
5 changed files with 68 additions and 22 deletions

View File

@ -240,10 +240,11 @@ upstreams_create(getdns_context *context, size_t size)
{ {
getdns_upstreams *r = (void *) GETDNS_XMALLOC(context->mf, char, getdns_upstreams *r = (void *) GETDNS_XMALLOC(context->mf, char,
sizeof(getdns_upstreams) + sizeof(getdns_upstreams) +
sizeof(struct getdns_upstream) * size); sizeof(getdns_upstream) * size);
r->mf = context->mf; r->mf = context->mf;
r->referenced = 1; r->referenced = 1;
r->count = 0; r->count = 0;
r->current = 0;
return r; return r;
} }
@ -253,7 +254,7 @@ upstreams_resize(getdns_upstreams *upstreams, size_t size)
getdns_upstreams *r = (void *) GETDNS_XREALLOC( getdns_upstreams *r = (void *) GETDNS_XREALLOC(
upstreams->mf, upstreams, char, upstreams->mf, upstreams, char,
sizeof(getdns_upstreams) + sizeof(getdns_upstreams) +
sizeof(struct getdns_upstream) * size); sizeof(getdns_upstream) * size);
return r; return r;
} }
@ -265,13 +266,13 @@ upstreams_dereference(getdns_upstreams *upstreams)
} }
static size_t static size_t
upstream_addr_len(struct getdns_upstream *upstream) upstream_addr_len(getdns_upstream *upstream)
{ {
return upstream->addr.ss_family == AF_INET ? 4 : 16; return upstream->addr.ss_family == AF_INET ? 4 : 16;
} }
static uint8_t* static uint8_t*
upstream_addr(struct getdns_upstream *upstream) upstream_addr(getdns_upstream *upstream)
{ {
return upstream->addr.ss_family == AF_INET return upstream->addr.ss_family == AF_INET
? (void *)&((struct sockaddr_in*)&upstream->addr)->sin_addr ? (void *)&((struct sockaddr_in*)&upstream->addr)->sin_addr
@ -279,7 +280,7 @@ upstream_addr(struct getdns_upstream *upstream)
} }
static in_port_t static in_port_t
upstream_port(struct getdns_upstream *upstream) upstream_port(getdns_upstream *upstream)
{ {
return ntohs(upstream->addr.ss_family == AF_INET return ntohs(upstream->addr.ss_family == AF_INET
? ((struct sockaddr_in *)&upstream->addr)->sin_port ? ((struct sockaddr_in *)&upstream->addr)->sin_port
@ -287,7 +288,7 @@ upstream_port(struct getdns_upstream *upstream)
} }
static uint32_t * static uint32_t *
upstream_scope_id(struct getdns_upstream *upstream) upstream_scope_id(getdns_upstream *upstream)
{ {
return upstream->addr.ss_family == AF_INET ? NULL return upstream->addr.ss_family == AF_INET ? NULL
: (upstream_addr(upstream)[0] == 0xFE && : (upstream_addr(upstream)[0] == 0xFE &&
@ -296,7 +297,7 @@ upstream_scope_id(struct getdns_upstream *upstream)
} }
static void static void
upstream_ntop_buf(struct getdns_upstream *upstream, char *buf, size_t len) upstream_ntop_buf(getdns_upstream *upstream, char *buf, size_t len)
{ {
/* Also possible but prints scope_id by name (nor parsed by unbound) /* Also possible but prints scope_id by name (nor parsed by unbound)
* *
@ -314,7 +315,7 @@ upstream_ntop_buf(struct getdns_upstream *upstream, char *buf, size_t len)
} }
static getdns_dict * static getdns_dict *
upstream_dict(getdns_context *context, struct getdns_upstream *upstream) upstream_dict(getdns_context *context, getdns_upstream *upstream)
{ {
getdns_dict *r = getdns_dict_create_with_context(context); getdns_dict *r = getdns_dict_create_with_context(context);
char addrstr[1024], *b; char addrstr[1024], *b;
@ -346,12 +347,13 @@ net_req_query_id_cmp(const void *id1, const void *id2)
} }
static void static void
upstream_init(struct getdns_upstream *upstream, struct addrinfo *ai) upstream_init(getdns_upstream *upstream, struct addrinfo *ai)
{ {
assert(upstream && ai); assert(upstream && ai);
upstream->addr_len = ai->ai_addrlen; upstream->addr_len = ai->ai_addrlen;
(void) memcpy(&upstream->addr, ai->ai_addr, ai->ai_addrlen); (void) memcpy(&upstream->addr, ai->ai_addr, ai->ai_addrlen);
upstream->to_retry = 2; upstream->to_retry = 2;
upstream->back_off = 1;
upstream->tcp_fd = -1; upstream->tcp_fd = -1;
(void) memset(&upstream->tcp_event, 0, sizeof(upstream->tcp_event)); (void) memset(&upstream->tcp_event, 0, sizeof(upstream->tcp_event));
getdns_rbtree_init(&upstream->netreq_by_query_id, getdns_rbtree_init(&upstream->netreq_by_query_id,
@ -372,7 +374,7 @@ set_os_defaults(struct getdns_context *context)
struct getdns_bindata bindata; struct getdns_bindata bindata;
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *result; struct addrinfo *result;
struct getdns_upstream *upstream; getdns_upstream *upstream;
int s; int s;
if(context->fchg_resolvconf == NULL) { if(context->fchg_resolvconf == NULL) {
@ -1275,7 +1277,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
uint32_t port; uint32_t port;
getdns_bindata *scope_id; getdns_bindata *scope_id;
struct addrinfo *ai; struct addrinfo *ai;
struct getdns_upstream *upstream; getdns_upstream *upstream;
upstream = &upstreams->upstreams[upstreams->count]; upstream = &upstreams->upstreams[upstreams->count];
if ((r = getdns_list_get_dict(upstream_list, i, &dict))) if ((r = getdns_list_get_dict(upstream_list, i, &dict)))
@ -1552,7 +1554,7 @@ ub_setup_stub(struct ub_ctx *ctx, getdns_upstreams *upstreams)
{ {
getdns_return_t r = GETDNS_RETURN_GOOD; getdns_return_t r = GETDNS_RETURN_GOOD;
size_t i; size_t i;
struct getdns_upstream *upstream; getdns_upstream *upstream;
char addr[1024]; char addr[1024];
(void) ub_ctx_set_fwd(ctx, NULL); (void) ub_ctx_set_fwd(ctx, NULL);
@ -1627,7 +1629,7 @@ set_ldns_nameservers(struct getdns_context *context,
{ {
getdns_return_t r = GETDNS_RETURN_GOOD; getdns_return_t r = GETDNS_RETURN_GOOD;
size_t i; size_t i;
struct getdns_upstream *upstream; getdns_upstream *upstream;
ldns_rdf *pop, *ns_rdf; ldns_rdf *pop, *ns_rdf;
uint16_t port = 53; uint16_t port = 53;
@ -1992,7 +1994,7 @@ priv_get_context_settings(getdns_context* context) {
r |= priv_dict_set_list_if_not_null(result, "suffix", context->suffix); r |= priv_dict_set_list_if_not_null(result, "suffix", context->suffix);
if (context->upstreams->count > 0) { if (context->upstreams->count > 0) {
size_t i; size_t i;
struct getdns_upstream *upstream; getdns_upstream *upstream;
getdns_list *upstreams = getdns_list *upstreams =
getdns_list_create_with_context(context); getdns_list_create_with_context(context);

View File

@ -69,20 +69,22 @@ struct filechg {
struct stat *prevstat; struct stat *prevstat;
}; };
struct getdns_upstream { typedef struct getdns_upstream {
socklen_t addr_len; socklen_t addr_len;
struct sockaddr_storage addr; struct sockaddr_storage addr;
int to_retry; int to_retry;
int back_off;
int tcp_fd; int tcp_fd;
getdns_eventloop_event tcp_event; getdns_eventloop_event tcp_event;
getdns_rbtree_t netreq_by_query_id; getdns_rbtree_t netreq_by_query_id;
}; } getdns_upstream;
typedef struct getdns_upstreams { typedef struct getdns_upstreams {
struct mem_funcs mf; struct mem_funcs mf;
size_t referenced; size_t referenced;
size_t count; size_t count;
struct getdns_upstream upstreams[]; size_t current;
getdns_upstream upstreams[];
} getdns_upstreams; } getdns_upstreams;
struct getdns_context { struct getdns_context {
@ -96,7 +98,7 @@ struct getdns_context {
getdns_append_name_t append_name; getdns_append_name_t append_name;
struct getdns_list *suffix; struct getdns_list *suffix;
struct getdns_list *dnssec_trust_anchors; struct getdns_list *dnssec_trust_anchors;
getdns_upstreams *upstreams; getdns_upstreams *upstreams;
getdns_transport_t dns_transport; getdns_transport_t dns_transport;
uint16_t limit_outstanding_queries; uint16_t limit_outstanding_queries;
uint32_t dnssec_allowed_skew; uint32_t dnssec_allowed_skew;

View File

@ -149,7 +149,6 @@ dns_req_new(struct getdns_context *context, getdns_eventloop *loop,
result->upstreams = context->upstreams; result->upstreams = context->upstreams;
if (result->upstreams) if (result->upstreams)
result->upstreams->referenced++; result->upstreams->referenced++;
result->ns_index = 0;
/* create the requests */ /* create the requests */
req = network_req_new(result, request_type, klass, extensions); req = network_req_new(result, request_type, klass, extensions);

View File

@ -269,6 +269,12 @@ stub_resolve_timeout_cb(void *userarg)
getdns_network_req *netreq = (getdns_network_req *)userarg; getdns_network_req *netreq = (getdns_network_req *)userarg;
getdns_dns_req *dns_req = netreq->owner; getdns_dns_req *dns_req = netreq->owner;
if (! --netreq->upstream->to_retry)
netreq->upstream->to_retry = -(netreq->upstream->back_off *= 2);
if (++dns_req->upstreams->current > dns_req->upstreams->count)
dns_req->upstreams->current = 0;
(void) getdns_context_request_timed_out(dns_req); (void) getdns_context_request_timed_out(dns_req);
} }
@ -300,6 +306,7 @@ stub_resolve_read_cb(void *userarg)
close(netreq->udp_fd); close(netreq->udp_fd);
netreq->state = NET_REQ_FINISHED; netreq->state = NET_REQ_FINISHED;
ldns_wire2pkt(&(netreq->result), pkt, read); ldns_wire2pkt(&(netreq->result), pkt, read);
dns_req->upstreams->current = 0;
/* Do the dnssec here */ /* Do the dnssec here */
netreq->secure = 0; netreq->secure = 0;
@ -361,12 +368,47 @@ done:
return; return;
} }
static getdns_upstream *
pick_upstream(getdns_dns_req *dns_req)
{
getdns_upstream *upstream;
size_t i;
if (!dns_req->upstreams->count)
return NULL;
for (i = 0; i < dns_req->upstreams->count; i++)
if (dns_req->upstreams->upstreams[i].to_retry <= 0)
dns_req->upstreams->upstreams[i].to_retry++;
i = dns_req->upstreams->current;
do {
if (dns_req->upstreams->upstreams[i].to_retry > 0) {
dns_req->upstreams->current = i;
return &dns_req->upstreams->upstreams[i];
}
if (++i > dns_req->upstreams->count)
i = 0;
} while (i != dns_req->upstreams->current);
upstream = dns_req->upstreams->upstreams;
for (i = 1; i < dns_req->upstreams->count; i++)
if (dns_req->upstreams->upstreams[i].back_off <
upstream->back_off)
upstream = &dns_req->upstreams->upstreams[i];
upstream->back_off++;
upstream->to_retry = 1;
dns_req->upstreams->current = upstream - dns_req->upstreams->upstreams;
return upstream;
}
getdns_return_t getdns_return_t
priv_getdns_submit_stub_request(getdns_network_req *netreq) priv_getdns_submit_stub_request(getdns_network_req *netreq)
{ {
getdns_dns_req *dns_req = netreq->owner; getdns_dns_req *dns_req = netreq->owner;
struct getdns_upstream *upstream; getdns_upstream *upstream;
/* TODO: TCP */ /* TODO: TCP */
if (dns_req->context->dns_transport != GETDNS_TRANSPORT_UDP_ONLY && if (dns_req->context->dns_transport != GETDNS_TRANSPORT_UDP_ONLY &&
@ -374,7 +416,9 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP) GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP)
return GETDNS_RETURN_GENERIC_ERROR; return GETDNS_RETURN_GENERIC_ERROR;
upstream = &dns_req->upstreams->upstreams[dns_req->ns_index]; if (!(upstream = pick_upstream(dns_req)))
return GETDNS_RETURN_GENERIC_ERROR;
if ((netreq->udp_fd = socket( if ((netreq->udp_fd = socket(
upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1)
return GETDNS_RETURN_GENERIC_ERROR; return GETDNS_RETURN_GENERIC_ERROR;

View File

@ -231,7 +231,6 @@ typedef struct getdns_dns_req
/* Stuff for stub resolving */ /* Stuff for stub resolving */
struct getdns_upstreams *upstreams; struct getdns_upstreams *upstreams;
size_t ns_index;
} getdns_dns_req; } getdns_dns_req;