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
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) {
ub_cancel(req->context->unbound_ctx,
netreq->unbound_id);
@ -1921,12 +1921,12 @@ getdns_context_local_namespace_resolve(
ldns_rr_list *result_list = NULL;
host_name_addrs *hnas;
ldns_rdf *query_name;
int ipv4 = dnsreq->first_req->request_type == GETDNS_RRTYPE_A ||
(dnsreq->first_req->next &&
dnsreq->first_req->next->request_type == GETDNS_RRTYPE_A);
int ipv6 = dnsreq->first_req->request_type == GETDNS_RRTYPE_AAAA ||
(dnsreq->first_req->next &&
dnsreq->first_req->next->request_type == GETDNS_RRTYPE_AAAA);
int ipv4 = dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A ||
(dnsreq->netreqs[1] &&
dnsreq->netreqs[1]->request_type == GETDNS_RRTYPE_A);
int ipv6 = dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_AAAA ||
(dnsreq->netreqs[1] &&
dnsreq->netreqs[1]->request_type == GETDNS_RRTYPE_AAAA);
if (!ipv4 && !ipv6)
return GETDNS_RETURN_GENERIC_ERROR;

View File

@ -272,7 +272,7 @@ static void destroy_chain(struct validation_chain *chain)
static void
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);
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));
return;
}
while (netreq) {
for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) {
size_t i;
ldns_rr_list *answer = ldns_pkt_answer(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,
ldns_rdf2str(ldns_rr_rdf(rr, 7)));
}
netreq = netreq->next;
}
callback_on_complete_chain(chain);
}

View File

@ -81,10 +81,10 @@ handle_network_request_error(getdns_network_req * netreq, int err)
void
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;
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 &&
netreq->state != NET_REQ_CANCELED)
return;
@ -168,7 +168,7 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
getdns_callback_t callbackfn, int usenamespaces)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
getdns_network_req *netreq;
getdns_network_req *netreq, **netreq_p;
getdns_dns_req *req;
getdns_dict *localnames_response;
size_t i;
@ -201,7 +201,9 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
if (!usenamespaces)
/* 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);
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
of returning */
r = GETDNS_RETURN_GOOD;
netreq = req->first_req;
while (!r && netreq) {
for ( netreq_p = req->netreqs
; !r && (netreq = *netreq_p)
; netreq_p++)
r = submit_network_request(netreq);
netreq = netreq->next;
}
break;
} else
r = GETDNS_RETURN_BAD_CONTEXT;

View File

@ -38,31 +38,24 @@
#include "util-internal.h"
#include "gldns/rrdef.h"
void
network_req_free(getdns_network_req * net_req)
static void
network_req_cleanup(getdns_network_req *net_req)
{
if (!net_req) {
return;
}
if (net_req->result) {
assert(net_req);
if (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 *
network_req_new(getdns_dns_req * owner,
uint16_t request_type,
uint16_t request_class, struct getdns_dict *extensions)
static void
network_req_init(getdns_network_req *net_req,
getdns_dns_req *owner, uint16_t request_type,
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->next = NULL;
net_req->request_type = request_type;
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->owner = owner;
/* TODO: records and other extensions */
net_req->upstream = NULL;
net_req->fd = -1;
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->max_udp_payload_size = 0;
net_req->write_queue_tail = NULL;
return net_req;
net_req->wire_data_sz = wire_data_sz;
net_req->response = NULL;
}
void
dns_req_free(getdns_dns_req * req)
{
getdns_network_req **net_req;
if (!req) {
return;
}
getdns_network_req *net_req = NULL;
/* free extensions */
getdns_dict_destroy(req->extensions);
@ -96,14 +89,11 @@ dns_req_free(getdns_dns_req * req)
if (req->upstreams && --req->upstreams->referenced == 0)
GETDNS_FREE(req->upstreams->mf, req->upstreams);
/* free network requests */
net_req = req->first_req;
while (net_req) {
getdns_network_req *next = net_req->next;
network_req_free(net_req);
net_req = next;
}
/* cleanup network requests */
for (net_req = req->netreqs; *net_req; net_req++)
network_req_cleanup(*net_req);
/* clear timeout event */
if (req->timeout.timeout_cb) {
req->loop->vmt->clear(req->loop, &req->timeout);
req->timeout.timeout_cb = NULL;
@ -116,25 +106,47 @@ dns_req_free(getdns_dns_req * req)
/* create a new dns req to be submitted */
getdns_dns_req *
dns_req_new(struct getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, struct getdns_dict *extensions)
dns_req_new(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions)
{
getdns_dns_req *result = NULL;
getdns_network_req *req = NULL;
uint32_t klass = GLDNS_RR_CLASS_IN;
result = GETDNS_MALLOC(context->mf, getdns_dns_req);
if (result == NULL) {
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;
if (! (region = GETDNS_XMALLOC(context->mf, uint8_t,
dnsreq_base_sz + (a_aaaa_query ? 2 : 1) * netreq_sz)))
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->name = getdns_strdup(&(result->my_mf), name);
result->context = context;
result->loop = loop;
result->canceled = 0;
result->current_req = NULL;
result->first_req = NULL;
result->trans_id = (uint64_t)(((intptr_t) result) ^ ldns_get_random());
getdns_dict_copy(extensions, &result->extensions);
@ -152,32 +164,14 @@ dns_req_new(struct getdns_context *context, getdns_eventloop *loop,
if (result->upstreams)
result->upstreams->referenced++;
/* create the requests */
req = network_req_new(result, request_type, klass, extensions);
if (!req) {
dns_req_free(result);
return NULL;
}
network_req_init(result->netreqs[0], result, request_type,
klass, netreq_sz - sizeof(getdns_network_req));
result->current_req = req;
result->first_req = req;
/* tack on A or AAAA if needed */
if (is_extension_set(extensions, "return_both_v4_and_v6") &&
(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;
}
if (a_aaaa_query)
network_req_init(result->netreqs[1], result,
( request_type == GETDNS_RRTYPE_A
? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A ),
klass, netreq_sz - sizeof(getdns_network_req));
return result;
}

View File

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

View File

@ -191,9 +191,6 @@ typedef struct getdns_network_req
int secure;
int bogus;
/* next request to issue after this one */
struct getdns_network_req *next;
/* For stub resolving */
struct getdns_upstream *upstream;
int fd;
@ -206,6 +203,14 @@ typedef struct getdns_network_req
/* Network requests scheduled to write after me */
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;
/**
@ -222,12 +227,6 @@ typedef struct getdns_dns_req {
/* canceled flag */
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 */
struct getdns_context *context;
@ -256,6 +255,16 @@ typedef struct getdns_dns_req {
/* Stuff for stub resolving */
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;
#define GETDNS_XMALLOC(obj, type, count) \
@ -294,13 +303,6 @@ typedef struct getdns_dns_req {
/* 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 */
getdns_dns_req *dns_req_new(getdns_context *context, getdns_eventloop *loop,
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 *replies_tree = getdns_list_create_with_context(
completed_request->context);
getdns_network_req *netreq;
getdns_network_req *netreq, **netreq_p;
char *canonical_name = NULL;
getdns_return_t r = 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->return_dnssec_status == GETDNS_EXTENSION_TRUE;
if (completed_request->first_req &&
(completed_request->first_req->request_class == GETDNS_RRTYPE_A ||
completed_request->first_req->request_class ==
GETDNS_RRTYPE_AAAA)) {
if (completed_request->netreqs[0]->request_type == GETDNS_RRTYPE_A ||
completed_request->netreqs[0]->request_type == GETDNS_RRTYPE_AAAA)
just_addrs = getdns_list_create_with_context(
completed_request->context);
}
do {
canonical_name = get_canonical_name(completed_request->name);
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;
}
for ( netreq = completed_request->first_req
; netreq && r == GETDNS_RETURN_GOOD
; netreq = netreq->next ) {
for ( netreq_p = completed_request->netreqs
; ! r && (netreq = *netreq_p)
; netreq_p++) {
if (! netreq->result)
continue;
@ -959,7 +957,7 @@ validate_dname(const char* dname) {
} /* validate_dname */
int
is_extension_set(struct getdns_dict *extensions, const char *extension)
is_extension_set(getdns_dict *extensions, const char *extension)
{
getdns_return_t r;
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;
}
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 */

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
* @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 { \
struct timeval tv; \