Embed netreqs in dns_reqs and wire_data in netreqs

TODO: make sure the wire_data buffer is filled with the response
This commit is contained in:
Willem Toorop 2015-01-29 12:30:40 +01:00
parent f9a0974e5a
commit 3f046cf573
8 changed files with 179 additions and 111 deletions

View File

@ -1389,9 +1389,9 @@ getdns_context_set_memory_functions(struct getdns_context *context,
static void static void
cancel_dns_req(getdns_dns_req *req) cancel_dns_req(getdns_dns_req *req)
{ {
getdns_network_req *netreq; getdns_network_req *netreq, **netreq_p;
for (netreq = req->first_req; netreq; netreq = netreq->next) for (netreq_p = req->netreqs; (netreq = *netreq_p); netreq_p++)
if (netreq->unbound_id != -1) { if (netreq->unbound_id != -1) {
ub_cancel(req->context->unbound_ctx, ub_cancel(req->context->unbound_ctx,
netreq->unbound_id); netreq->unbound_id);
@ -1921,12 +1921,12 @@ getdns_context_local_namespace_resolve(
ldns_rr_list *result_list = NULL; ldns_rr_list *result_list = NULL;
host_name_addrs *hnas; host_name_addrs *hnas;
ldns_rdf *query_name; ldns_rdf *query_name;
int ipv4 = dnsreq->first_req->request_type == GETDNS_RRTYPE_A || int ipv4 = dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A ||
(dnsreq->first_req->next && (dnsreq->netreqs[1] &&
dnsreq->first_req->next->request_type == GETDNS_RRTYPE_A); dnsreq->netreqs[1]->request_type == GETDNS_RRTYPE_A);
int ipv6 = dnsreq->first_req->request_type == GETDNS_RRTYPE_AAAA || int ipv6 = dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_AAAA ||
(dnsreq->first_req->next && (dnsreq->netreqs[1] &&
dnsreq->first_req->next->request_type == GETDNS_RRTYPE_AAAA); dnsreq->netreqs[1]->request_type == GETDNS_RRTYPE_AAAA);
if (!ipv4 && !ipv6) if (!ipv4 && !ipv6)
return GETDNS_RETURN_GENERIC_ERROR; return GETDNS_RETURN_GENERIC_ERROR;

View File

@ -272,7 +272,7 @@ static void destroy_chain(struct validation_chain *chain)
static void static void
getdns_get_validation_chain(getdns_dns_req *dns_req, uint64_t *timeout) getdns_get_validation_chain(getdns_dns_req *dns_req, uint64_t *timeout)
{ {
getdns_network_req *netreq = dns_req->first_req; getdns_network_req **netreq_p, *netreq;
struct validation_chain *chain = create_chain(dns_req, timeout); struct validation_chain *chain = create_chain(dns_req, timeout);
if (! chain) { if (! chain) {
@ -280,7 +280,7 @@ getdns_get_validation_chain(getdns_dns_req *dns_req, uint64_t *timeout)
dns_req, create_getdns_response(dns_req)); dns_req, create_getdns_response(dns_req));
return; return;
} }
while (netreq) { for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) {
size_t i; size_t i;
ldns_rr_list *answer = ldns_pkt_answer(netreq->result); ldns_rr_list *answer = ldns_pkt_answer(netreq->result);
ldns_rr_list *authority = ldns_pkt_authority(netreq->result); ldns_rr_list *authority = ldns_pkt_authority(netreq->result);
@ -296,7 +296,6 @@ getdns_get_validation_chain(getdns_dns_req *dns_req, uint64_t *timeout)
launch_chain_link_lookup(chain, launch_chain_link_lookup(chain,
ldns_rdf2str(ldns_rr_rdf(rr, 7))); ldns_rdf2str(ldns_rr_rdf(rr, 7)));
} }
netreq = netreq->next;
} }
callback_on_complete_chain(chain); callback_on_complete_chain(chain);
} }

View File

@ -81,10 +81,10 @@ handle_network_request_error(getdns_network_req * netreq, int err)
void void
priv_getdns_check_dns_req_complete(getdns_dns_req *dns_req) priv_getdns_check_dns_req_complete(getdns_dns_req *dns_req)
{ {
getdns_network_req *netreq; getdns_network_req **netreq_p, *netreq;
int results_found = 0; int results_found = 0;
for (netreq = dns_req->first_req; netreq; netreq = netreq->next) for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++)
if (netreq->state != NET_REQ_FINISHED && if (netreq->state != NET_REQ_FINISHED &&
netreq->state != NET_REQ_CANCELED) netreq->state != NET_REQ_CANCELED)
return; return;
@ -168,7 +168,7 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
getdns_callback_t callbackfn, int usenamespaces) getdns_callback_t callbackfn, int usenamespaces)
{ {
getdns_return_t r = GETDNS_RETURN_GOOD; getdns_return_t r = GETDNS_RETURN_GOOD;
getdns_network_req *netreq; getdns_network_req *netreq, **netreq_p;
getdns_dns_req *req; getdns_dns_req *req;
getdns_dict *localnames_response; getdns_dict *localnames_response;
size_t i; size_t i;
@ -201,7 +201,9 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
if (!usenamespaces) if (!usenamespaces)
/* issue all network requests */ /* issue all network requests */
for (netreq = req->first_req; !r && netreq; netreq = netreq->next) for ( netreq_p = req->netreqs
; !r && (netreq = *netreq_p)
; netreq_p++)
r = submit_network_request(netreq); r = submit_network_request(netreq);
else for (i = 0; i < context->namespace_count; i++) { else for (i = 0; i < context->namespace_count; i++) {
@ -221,11 +223,10 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
if this means we go onto the next namespace instead if this means we go onto the next namespace instead
of returning */ of returning */
r = GETDNS_RETURN_GOOD; r = GETDNS_RETURN_GOOD;
netreq = req->first_req; for ( netreq_p = req->netreqs
while (!r && netreq) { ; !r && (netreq = *netreq_p)
; netreq_p++)
r = submit_network_request(netreq); r = submit_network_request(netreq);
netreq = netreq->next;
}
break; break;
} else } else
r = GETDNS_RETURN_BAD_CONTEXT; r = GETDNS_RETURN_BAD_CONTEXT;

View File

@ -38,31 +38,24 @@
#include "util-internal.h" #include "util-internal.h"
#include "gldns/rrdef.h" #include "gldns/rrdef.h"
void static void
network_req_free(getdns_network_req * net_req) network_req_cleanup(getdns_network_req *net_req)
{ {
if (!net_req) { assert(net_req);
return;
} if (net_req->result)
if (net_req->result) {
ldns_pkt_free(net_req->result); ldns_pkt_free(net_req->result);
}
GETDNS_FREE(net_req->owner->my_mf, net_req); if (net_req->response && net_req->response != net_req->wire_data)
GETDNS_FREE(net_req->owner->my_mf, net_req->response);
} }
getdns_network_req * static void
network_req_new(getdns_dns_req * owner, network_req_init(getdns_network_req *net_req,
uint16_t request_type, getdns_dns_req *owner, uint16_t request_type,
uint16_t request_class, struct getdns_dict *extensions) uint16_t request_class, size_t wire_data_sz)
{ {
getdns_network_req *net_req = GETDNS_MALLOC( owner->my_mf
, getdns_network_req);
if (!net_req) {
return NULL;
}
net_req->result = NULL; net_req->result = NULL;
net_req->next = NULL;
net_req->request_type = request_type; net_req->request_type = request_type;
net_req->request_class = request_class; net_req->request_class = request_class;
@ -70,8 +63,6 @@ network_req_new(getdns_dns_req * owner,
net_req->state = NET_REQ_NOT_SENT; net_req->state = NET_REQ_NOT_SENT;
net_req->owner = owner; net_req->owner = owner;
/* TODO: records and other extensions */
net_req->upstream = NULL; net_req->upstream = NULL;
net_req->fd = -1; net_req->fd = -1;
memset(&net_req->event, 0, sizeof(net_req->event)); memset(&net_req->event, 0, sizeof(net_req->event));
@ -79,16 +70,18 @@ network_req_new(getdns_dns_req * owner,
net_req->query_id = 0; net_req->query_id = 0;
net_req->max_udp_payload_size = 0; net_req->max_udp_payload_size = 0;
net_req->write_queue_tail = NULL; net_req->write_queue_tail = NULL;
return net_req;
net_req->wire_data_sz = wire_data_sz;
net_req->response = NULL;
} }
void void
dns_req_free(getdns_dns_req * req) dns_req_free(getdns_dns_req * req)
{ {
getdns_network_req **net_req;
if (!req) { if (!req) {
return; return;
} }
getdns_network_req *net_req = NULL;
/* free extensions */ /* free extensions */
getdns_dict_destroy(req->extensions); getdns_dict_destroy(req->extensions);
@ -96,14 +89,11 @@ dns_req_free(getdns_dns_req * req)
if (req->upstreams && --req->upstreams->referenced == 0) if (req->upstreams && --req->upstreams->referenced == 0)
GETDNS_FREE(req->upstreams->mf, req->upstreams); GETDNS_FREE(req->upstreams->mf, req->upstreams);
/* free network requests */ /* cleanup network requests */
net_req = req->first_req; for (net_req = req->netreqs; *net_req; net_req++)
while (net_req) { network_req_cleanup(*net_req);
getdns_network_req *next = net_req->next;
network_req_free(net_req);
net_req = next;
}
/* clear timeout event */
if (req->timeout.timeout_cb) { if (req->timeout.timeout_cb) {
req->loop->vmt->clear(req->loop, &req->timeout); req->loop->vmt->clear(req->loop, &req->timeout);
req->timeout.timeout_cb = NULL; req->timeout.timeout_cb = NULL;
@ -116,25 +106,47 @@ dns_req_free(getdns_dns_req * req)
/* create a new dns req to be submitted */ /* create a new dns req to be submitted */
getdns_dns_req * getdns_dns_req *
dns_req_new(struct getdns_context *context, getdns_eventloop *loop, dns_req_new(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, struct getdns_dict *extensions) const char *name, uint16_t request_type, getdns_dict *extensions)
{ {
getdns_dns_req *result = NULL; getdns_dns_req *result = NULL;
getdns_network_req *req = NULL;
uint32_t klass = GLDNS_RR_CLASS_IN; uint32_t klass = GLDNS_RR_CLASS_IN;
size_t edns_maximum_udp_payload_size =
getdns_get_maximum_udp_payload_size(context, extensions, NULL);
int a_aaaa_query =
is_extension_set(extensions, "return_both_v4_and_v6") &&
( request_type == GETDNS_RRTYPE_A ||
request_type == GETDNS_RRTYPE_AAAA );
/* Reserve for the buffer at least one more byte
* (to test for udp overflow) (hence the + 1),
* And align on the 8 byte boundry (hence the (x + 7) / 8 * 8)
*/
size_t netreq_sz = ( sizeof(getdns_network_req)
+ edns_maximum_udp_payload_size + 1 + 7) / 8 * 8;
size_t dnsreq_base_sz = ( sizeof(getdns_dns_req)
+ (a_aaaa_query ? 3 : 2)
* sizeof(getdns_network_req *));
uint8_t *region;
result = GETDNS_MALLOC(context->mf, getdns_dns_req); if (! (region = GETDNS_XMALLOC(context->mf, uint8_t,
if (result == NULL) { dnsreq_base_sz + (a_aaaa_query ? 2 : 1) * netreq_sz)))
return NULL; return NULL;
}
result = (getdns_dns_req *)region;
result->netreqs[0] = (getdns_network_req *)(region + dnsreq_base_sz);
if (a_aaaa_query) {
result->netreqs[1] = (getdns_network_req *)
(region + dnsreq_base_sz + netreq_sz);
result->netreqs[2] = NULL;
} else
result->netreqs[1] = NULL;
result->my_mf = context->mf; result->my_mf = context->mf;
result->name = getdns_strdup(&(result->my_mf), name); result->name = getdns_strdup(&(result->my_mf), name);
result->context = context; result->context = context;
result->loop = loop; result->loop = loop;
result->canceled = 0; result->canceled = 0;
result->current_req = NULL;
result->first_req = NULL;
result->trans_id = (uint64_t)(((intptr_t) result) ^ ldns_get_random()); result->trans_id = (uint64_t)(((intptr_t) result) ^ ldns_get_random());
getdns_dict_copy(extensions, &result->extensions); getdns_dict_copy(extensions, &result->extensions);
@ -152,32 +164,14 @@ dns_req_new(struct getdns_context *context, getdns_eventloop *loop,
if (result->upstreams) if (result->upstreams)
result->upstreams->referenced++; result->upstreams->referenced++;
/* create the requests */ network_req_init(result->netreqs[0], result, request_type,
req = network_req_new(result, request_type, klass, extensions); klass, netreq_sz - sizeof(getdns_network_req));
if (!req) {
dns_req_free(result);
return NULL;
}
result->current_req = req; if (a_aaaa_query)
result->first_req = req; network_req_init(result->netreqs[1], result,
( request_type == GETDNS_RRTYPE_A
/* tack on A or AAAA if needed */ ? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A ),
if (is_extension_set(extensions, "return_both_v4_and_v6") && klass, netreq_sz - sizeof(getdns_network_req));
(request_type == GETDNS_RRTYPE_A ||
request_type == GETDNS_RRTYPE_AAAA)) {
uint16_t next_req_type = (request_type == GETDNS_RRTYPE_A) ?
GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A;
getdns_network_req *next_req = network_req_new(result,
next_req_type, LDNS_RR_CLASS_IN, extensions);
if (!next_req) {
dns_req_free(result);
return NULL;
}
req->next = next_req;
}
return result; return result;
} }

View File

@ -170,7 +170,6 @@ getdns_make_query_pkt_buf(const getdns_network_req *netreq, uint8_t *buf,
if (len < 11) if (len < 11)
return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
*omax_udp_payload_size = edns_maximum_udp_payload_size;
buf[0] = 0; /* dname for . */ buf[0] = 0; /* dname for . */
gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT); gldns_write_uint16(buf + 1, GLDNS_RR_TYPE_OPT);
gldns_write_uint16(buf + 3, gldns_write_uint16(buf + 3,

View File

@ -191,9 +191,6 @@ typedef struct getdns_network_req
int secure; int secure;
int bogus; int bogus;
/* next request to issue after this one */
struct getdns_network_req *next;
/* For stub resolving */ /* For stub resolving */
struct getdns_upstream *upstream; struct getdns_upstream *upstream;
int fd; int fd;
@ -206,6 +203,14 @@ typedef struct getdns_network_req
/* Network requests scheduled to write after me */ /* Network requests scheduled to write after me */
struct getdns_network_req *write_queue_tail; struct getdns_network_req *write_queue_tail;
/* When more space is needed for the wire_data response than is
* available in wire_data[], it will be allocated seperately.
* response will then not point to wire_data anymore.
*/
uint8_t *response;
size_t wire_data_sz;
uint8_t wire_data[];
} getdns_network_req; } getdns_network_req;
/** /**
@ -222,12 +227,6 @@ typedef struct getdns_dns_req {
/* canceled flag */ /* canceled flag */
int canceled; int canceled;
/* current network request */
struct getdns_network_req *current_req;
/* first request in list */
struct getdns_network_req *first_req;
/* context that owns the request */ /* context that owns the request */
struct getdns_context *context; struct getdns_context *context;
@ -256,6 +255,16 @@ typedef struct getdns_dns_req {
/* Stuff for stub resolving */ /* Stuff for stub resolving */
struct getdns_upstreams *upstreams; struct getdns_upstreams *upstreams;
/* network requests for this dns request.
* The array is terminated with NULL.
*
* Memory for these netreqs has been allocated by the same malloc
* operation that reserved space for this getdns_dns_req.
* They will thus be freed as part of the desctruction of this struct,
* and do not need to be freed seperately.
*/
getdns_network_req *netreqs[];
} getdns_dns_req; } getdns_dns_req;
#define GETDNS_XMALLOC(obj, type, count) \ #define GETDNS_XMALLOC(obj, type, count) \
@ -294,13 +303,6 @@ typedef struct getdns_dns_req {
/* utility methods */ /* utility methods */
/* network request utilities */
void network_req_free(getdns_network_req * net_req);
getdns_network_req *network_req_new(getdns_dns_req * owner,
uint16_t request_type,
uint16_t request_class, struct getdns_dict *extensions);
/* dns request utils */ /* dns request utils */
getdns_dns_req *dns_req_new(getdns_context *context, getdns_eventloop *loop, getdns_dns_req *dns_req_new(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions); const char *name, uint16_t request_type, getdns_dict *extensions);

View File

@ -544,7 +544,7 @@ create_getdns_response(struct getdns_dns_req * completed_request)
struct getdns_list *just_addrs = NULL; struct getdns_list *just_addrs = NULL;
struct getdns_list *replies_tree = getdns_list_create_with_context( struct getdns_list *replies_tree = getdns_list_create_with_context(
completed_request->context); completed_request->context);
getdns_network_req *netreq; getdns_network_req *netreq, **netreq_p;
char *canonical_name = NULL; char *canonical_name = NULL;
getdns_return_t r = 0; getdns_return_t r = 0;
int nreplies = 0, nanswers = 0, nsecure = 0, ninsecure = 0, nbogus = 0; int nreplies = 0, nanswers = 0, nsecure = 0, ninsecure = 0, nbogus = 0;
@ -562,13 +562,11 @@ create_getdns_response(struct getdns_dns_req * completed_request)
completed_request->extensions, "dnssec_return_status") || completed_request->extensions, "dnssec_return_status") ||
completed_request->return_dnssec_status == GETDNS_EXTENSION_TRUE; completed_request->return_dnssec_status == GETDNS_EXTENSION_TRUE;
if (completed_request->first_req && if (completed_request->netreqs[0]->request_type == GETDNS_RRTYPE_A ||
(completed_request->first_req->request_class == GETDNS_RRTYPE_A || completed_request->netreqs[0]->request_type == GETDNS_RRTYPE_AAAA)
completed_request->first_req->request_class ==
GETDNS_RRTYPE_AAAA)) {
just_addrs = getdns_list_create_with_context( just_addrs = getdns_list_create_with_context(
completed_request->context); completed_request->context);
}
do { do {
canonical_name = get_canonical_name(completed_request->name); canonical_name = get_canonical_name(completed_request->name);
r = getdns_dict_util_set_string(result, GETDNS_STR_KEY_CANONICAL_NM, r = getdns_dict_util_set_string(result, GETDNS_STR_KEY_CANONICAL_NM,
@ -584,9 +582,9 @@ create_getdns_response(struct getdns_dns_req * completed_request)
break; break;
} }
for ( netreq = completed_request->first_req for ( netreq_p = completed_request->netreqs
; netreq && r == GETDNS_RETURN_GOOD ; ! r && (netreq = *netreq_p)
; netreq = netreq->next ) { ; netreq_p++) {
if (! netreq->result) if (! netreq->result)
continue; continue;
@ -959,7 +957,7 @@ validate_dname(const char* dname) {
} /* validate_dname */ } /* validate_dname */
int int
is_extension_set(struct getdns_dict *extensions, const char *extension) is_extension_set(getdns_dict *extensions, const char *extension)
{ {
getdns_return_t r; getdns_return_t r;
uint32_t value; uint32_t value;
@ -971,4 +969,76 @@ is_extension_set(struct getdns_dict *extensions, const char *extension)
return r == GETDNS_RETURN_GOOD && value == GETDNS_EXTENSION_TRUE; return r == GETDNS_RETURN_GOOD && value == GETDNS_EXTENSION_TRUE;
} }
size_t
getdns_get_maximum_udp_payload_size(getdns_context *context,
getdns_dict *extensions, getdns_upstream *upstream)
{
int dnssec_return_status
= is_extension_set(extensions, "dnssec_return_status");
int dnssec_return_only_secure
= is_extension_set(extensions, "dnssec_return_only_secure");
int dnssec_return_validation_chain
= is_extension_set(extensions, "dnssec_return_validation_chain");
int dnssec_extension_set = dnssec_return_status
|| dnssec_return_only_secure || dnssec_return_validation_chain;
uint32_t edns_do_bit;
int edns_maximum_udp_payload_size;
uint32_t get_edns_maximum_udp_payload_size;
uint32_t edns_extended_rcode;
uint32_t edns_version;
getdns_dict *add_opt_parameters;
int have_add_opt_parameters;
getdns_list *options;
size_t noptions = 0;
int with_opt;
have_add_opt_parameters = getdns_dict_get_dict(extensions,
"add_opt_parameters", &add_opt_parameters) == GETDNS_RETURN_GOOD;
if (dnssec_extension_set) {
edns_maximum_udp_payload_size =
( upstream && upstream->addr.ss_family == AF_INET6 )
? 1232 : 1432;
edns_extended_rcode = 0;
edns_version = 0;
edns_do_bit = 1;
} else {
edns_maximum_udp_payload_size =
context->edns_maximum_udp_payload_size;
edns_extended_rcode = context->edns_extended_rcode;
edns_version = context->edns_version;
edns_do_bit = context->edns_do_bit;
if (have_add_opt_parameters) {
if (!getdns_dict_get_int(add_opt_parameters,
"maximum_udp_payload_size",
&get_edns_maximum_udp_payload_size))
edns_maximum_udp_payload_size =
get_edns_maximum_udp_payload_size;
(void) getdns_dict_get_int(add_opt_parameters,
"extended_rcode", &edns_extended_rcode);
(void) getdns_dict_get_int(add_opt_parameters,
"version", &edns_version);
(void) getdns_dict_get_int(add_opt_parameters,
"do_bit", &edns_do_bit);
}
}
if (have_add_opt_parameters && getdns_dict_get_list(
add_opt_parameters, "options", &options) == GETDNS_RETURN_GOOD)
(void) getdns_list_get_length(options, &noptions);
with_opt = edns_do_bit != 0 || edns_maximum_udp_payload_size != -1 ||
edns_extended_rcode != 0 || edns_version != 0 || noptions;
return ! with_opt ? 512
: edns_maximum_udp_payload_size == -1 ?
(upstream && upstream->addr.ss_family==AF_INET6 ) ? 1232 : 1432
: edns_maximum_udp_payload_size > 512 ?
edns_maximum_udp_payload_size : 512;
}
/* util-internal.c */ /* util-internal.c */

View File

@ -147,7 +147,10 @@ create_list_from_rr_list(struct getdns_context *context, ldns_rr_list * rr_list)
* @param extension name of extension to check * @param extension name of extension to check
* @return int with value 1 if set to GETDNS_EXTENSION_TRUE and 0 otherwise * @return int with value 1 if set to GETDNS_EXTENSION_TRUE and 0 otherwise
*/ */
int is_extension_set(struct getdns_dict *extensions, const char *extension); int is_extension_set(getdns_dict *extensions, const char *extension);
size_t getdns_get_maximum_udp_payload_size(getdns_context *context,
getdns_dict *extensions, getdns_upstream *upstream);
#define DEBUG_ON(...) do { \ #define DEBUG_ON(...) do { \
struct timeval tv; \ struct timeval tv; \