Fix callbacks during scheduling in DNSSEC code too

This commit is contained in:
Willem Toorop 2016-04-22 14:09:18 +02:00
parent 15271d0438
commit d61e64c9c7
3 changed files with 35 additions and 11 deletions

View File

@ -736,6 +736,8 @@ typedef struct chain_node chain_node;
struct chain_head {
struct mem_funcs my_mf;
size_t lock;
chain_head *next;
chain_node *parent;
size_t node_count; /* Number of nodes attached directly
@ -857,6 +859,7 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
head = *chain_p = (chain_head *)region;
head->my_mf = *mf;
head->lock = 1;
head->next = NULL;
head->rrset.name = head->name_spc;
memcpy(head->name_spc, rrset->name, dname_len);
@ -1319,6 +1322,7 @@ static void val_chain_node_cb(getdns_dns_req *dnsreq)
default : check_chain_complete(node->chains);
return;
}
node->lock++;
n_signers = 0;
for ( i = rrset_iter_init(&i_spc,netreq->response,netreq->response_len)
; i
@ -1344,6 +1348,7 @@ static void val_chain_node_cb(getdns_dns_req *dnsreq)
*/
val_chain_sched_soa_node(node->parent);
node->lock--;
check_chain_complete(node->chains);
}
@ -1363,17 +1368,21 @@ static void val_chain_node_soa_cb(getdns_dns_req *dnsreq)
! _dname_equal(node->ds.name, rrset->name))
node = node->parent;
if (node)
if (node) {
node->lock++;
val_chain_sched_ds_node(node);
else {
} else {
/* SOA for a different name */
node = (chain_node *)dnsreq->user_pointer;
node->lock++;
val_chain_sched_soa_node(node->parent);
}
} else if (node->parent)
} else if (node->parent) {
node->lock++;
val_chain_sched_soa_node(node->parent);
}
node->lock--;
check_chain_complete(node->chains);
}
@ -3003,7 +3012,7 @@ static size_t count_outstanding_requests(chain_head *head)
if (!head)
return 0;
for ( node = head->parent, count = 0
for ( node = head->parent, count = head->lock
; node
; node = node->parent) {
@ -3245,6 +3254,7 @@ static void check_chain_complete(chain_head *chain)
}
/* Final user callback */
dnsreq->validating = 0;
_getdns_call_user_callback(dnsreq, response_dict);
}
@ -3252,7 +3262,11 @@ static void check_chain_complete(chain_head *chain)
void _getdns_get_validation_chain(getdns_dns_req *dnsreq)
{
getdns_network_req *netreq, **netreq_p;
chain_head *chain = NULL;
chain_head *chain = NULL, *chain_p;
if (dnsreq->validating)
return;
dnsreq->validating = 1;
for (netreq_p = dnsreq->netreqs; (netreq = *netreq_p) ; netreq_p++) {
if (! netreq->response
@ -3277,11 +3291,15 @@ void _getdns_get_validation_chain(getdns_dns_req *dnsreq)
, netreq
);
}
if (chain)
if (chain) {
for (chain_p = chain; chain_p; chain_p = chain_p->next)
chain_p->lock--;
check_chain_complete(chain);
else
} else {
dnsreq->validating = 0;
_getdns_call_user_callback(dnsreq,
_getdns_create_getdns_response(dnsreq));
}
}

View File

@ -903,6 +903,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop,
result->finished_next = NULL;
result->freed = NULL;
result->validating = 0;
network_req_init(result->netreqs[0], result,
request_type, dnssec_extension_set, with_opt,

View File

@ -304,10 +304,15 @@ typedef struct getdns_dns_req {
int dnssec_ok_checking_disabled;
int is_sync_request;
/* Integer pointed to by pointer will be set to 1 (if set),
* before the request is freed.
* To be used by _getdns_submit_netreq only!
/* The validating and freed variables are used to make sure a single
* code path is followed while processing a DNS request, even when
* callbacks are already fired whilst the registering/scheduling call
* (i.e. ub_resolve_event) has not returned yet.
*
* validating is touched by _getdns_get_validation_chain only and
* freed is touched by _getdns_submit_netreq only
*/
int validating;
int *freed;
/* internally scheduled request */