diff --git a/src/context.c b/src/context.c index dc8a8376..85e19b51 100755 --- a/src/context.c +++ b/src/context.c @@ -752,17 +752,14 @@ set_ub_number_opt(struct getdns_context *ctx, char *opt, uint16_t value) } static void -getdns_context_request_count_changed(getdns_context *context, uint32_t prev_rc) +getdns_context_request_count_changed(getdns_context *context) { - if ((!prev_rc && !context->outbound_requests->count) || - ( prev_rc && context->outbound_requests->count)) - return; - - if (context->outbound_requests->count) + if (context->outbound_requests->count && !context->ub_event.ev) context->extension->vmt->schedule( context->extension, ub_fd(context->unbound_ctx), TIMEOUT_FOREVER, &context->ub_event); - else + + else if (context->ub_event.ev) context->extension->vmt->clear( context->extension, &context->ub_event); } @@ -771,11 +768,10 @@ static void getdns_context_ub_read_cb(void *userarg) { getdns_context *context = (getdns_context *)userarg; - int32_t prev_rc = context->outbound_requests->count; if (getdns_context_process_async(context)) return; (void) getdns_context_get_num_pending_requests(context, NULL); - getdns_context_request_count_changed(context, prev_rc); + getdns_context_request_count_changed(context); } static getdns_return_t @@ -1694,14 +1690,11 @@ getdns_context_prepare_for_resolution(struct getdns_context *context, getdns_return_t getdns_context_track_outbound_request(getdns_dns_req * req) { - uint32_t prev_rc; ldns_rbnode_t *node; if (!req) return GETDNS_RETURN_INVALID_PARAMETER; - prev_rc = req->context->outbound_requests->count; - if (!(node = GETDNS_MALLOC(req->context->my_mf, ldns_rbnode_t))) return GETDNS_RETURN_MEMORY_ERROR; @@ -1711,37 +1704,33 @@ getdns_context_track_outbound_request(getdns_dns_req * req) GETDNS_FREE(req->context->my_mf, node); return GETDNS_RETURN_GENERIC_ERROR; } - getdns_context_request_count_changed(req->context, prev_rc); + getdns_context_request_count_changed(req->context); return GETDNS_RETURN_GOOD; } getdns_return_t getdns_context_clear_outbound_request(getdns_dns_req * req) { - uint32_t prev_rc; ldns_rbnode_t *node; if (!req) return GETDNS_RETURN_INVALID_PARAMETER; - prev_rc = req->context->outbound_requests->count; - node = ldns_rbtree_delete( req->context->outbound_requests, &req->trans_id); if (!node) return GETDNS_RETURN_GENERIC_ERROR; GETDNS_FREE(req->context->my_mf, node); - getdns_context_request_count_changed(req->context, prev_rc); + getdns_context_request_count_changed(req->context); return GETDNS_RETURN_GOOD; } getdns_return_t -getdns_context_request_timed_out(struct getdns_dns_req - *req) { +getdns_context_request_timed_out(struct getdns_dns_req *req) +{ /* Don't use req after callback */ getdns_context* context = req->context; - uint32_t prev_rc = context->outbound_requests->count; getdns_transaction_t trans_id = req->trans_id; getdns_callback_t cb = req->user_callback; void *user_arg = req->user_pointer; @@ -1752,7 +1741,7 @@ getdns_context_request_timed_out(struct getdns_dns_req context->processing = 1; cb(context, GETDNS_CALLBACK_TIMEOUT, response, user_arg, trans_id); context->processing = 0; - getdns_context_request_count_changed(context, prev_rc); + getdns_context_request_count_changed(context); return GETDNS_RETURN_GOOD; } @@ -1806,6 +1795,10 @@ int getdns_context_fd(struct getdns_context* context) { return ub_fd(context->unbound_ctx); } +/* TODO: Remove next_timeout argument from getdns_context_get_num_pending_requests + */ +void getdns_handle_timeouts(struct getdns_event_base* base, struct timeval* now, + struct timeval* wait); uint32_t getdns_context_get_num_pending_requests(struct getdns_context* context, struct timeval* next_timeout) @@ -1815,6 +1808,10 @@ getdns_context_get_num_pending_requests(struct getdns_context* context, if (context->outbound_requests->count) context->extension->vmt->run_once(context->extension, 0); + /* TODO: Remove this when next_timeout is gone */ + getdns_handle_timeouts(context->mini_event.base, + &context->mini_event.time_tv, next_timeout); + return context->outbound_requests->count; } @@ -1904,41 +1901,6 @@ getdns_context_set_eventloop(struct getdns_context* context, getdns_eventloop* l return GETDNS_RETURN_GOOD; } -getdns_return_t -getdns_context_schedule_timeout(getdns_context *context, uint64_t timeout, - getdns_eventloop_callback callback, void *userarg, - getdns_eventloop_event *el_ev) -{ - RETURN_IF_NULL(context , GETDNS_RETURN_INVALID_PARAMETER); - RETURN_IF_NULL(callback, GETDNS_RETURN_INVALID_PARAMETER); - RETURN_IF_NULL(el_ev , GETDNS_RETURN_INVALID_PARAMETER); - - /* Initialize eev_data struct */ - el_ev->userarg = userarg; - el_ev->read_cb = NULL; - el_ev->write_cb = NULL; - el_ev->timeout_cb = callback; - el_ev->ev = NULL; - - return context->extension->vmt->schedule( - context->extension, -1, timeout, el_ev); -} - -getdns_return_t -getdns_context_clear_timeout(getdns_context* context, - getdns_eventloop_event *el_ev) -{ - RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); - RETURN_IF_NULL(el_ev, GETDNS_RETURN_INVALID_PARAMETER); - RETURN_IF_NULL(el_ev->timeout_cb, GETDNS_RETURN_GOOD); - - if (el_ev->timeout_cb) { - context->extension->vmt->clear(context->extension, el_ev); - el_ev->timeout_cb = NULL; - } - return GETDNS_RETURN_GOOD; -} - static inline getdns_return_t priv_dict_set_list_if_not_null(getdns_dict* dict, const char* name, getdns_list* list) { diff --git a/src/context.h b/src/context.h index 6eb2ca1d..b7de400e 100755 --- a/src/context.h +++ b/src/context.h @@ -179,14 +179,6 @@ void getdns_bindata_destroy( struct mem_funcs *mfs, struct getdns_bindata *bindata); -/* timeout scheduling */ -getdns_return_t getdns_context_schedule_timeout(getdns_context* context, - uint64_t timeout, getdns_eventloop_callback callback, void* userarg, - getdns_eventloop_event *init_to_track); - -getdns_return_t getdns_context_clear_timeout(getdns_context* context, - getdns_eventloop_event *timeout_data); - /* perform name resolution in /etc/hosts */ getdns_return_t getdns_context_local_namespace_resolve(getdns_dns_req* req, struct getdns_dict **response, diff --git a/src/general.c b/src/general.c index 69669856..bfb837e3 100644 --- a/src/general.c +++ b/src/general.c @@ -152,104 +152,146 @@ ub_resolve_callback(void* arg, int err, struct ub_result* ub_res) } /* ub_resolve_callback */ getdns_return_t -getdns_general_ub(struct getdns_context *context, - const char *name, - uint16_t request_type, - struct getdns_dict *extensions, - void *userarg, - getdns_transaction_t * transaction_id, - getdns_callback_t callbackfn, - int usenamespaces) +getdns_general_ns(getdns_context *context, getdns_eventloop *loop, + const char *name, uint16_t request_type, getdns_dict *extensions, + void *userarg, getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn, int usenamespaces) { - getdns_return_t gr; - int r = GETDNS_RETURN_GOOD; + getdns_return_t r = GETDNS_RETURN_GOOD; getdns_network_req *netreq; + getdns_dns_req *req; + getdns_dict *localnames_response; + size_t i; - if (!name) { + if (!context || !name) return GETDNS_RETURN_INVALID_PARAMETER; - } + + if ((r = validate_dname(name))) + return r; - gr = getdns_context_prepare_for_resolution(context, usenamespaces); - if (gr != GETDNS_RETURN_GOOD) { - return gr; - } + if (extensions && (r = validate_extensions(extensions))) + return r; - /* request state */ - getdns_dns_req *req = dns_req_new(context, - name, - request_type, - extensions); - if (!req) { - return GETDNS_RETURN_GENERIC_ERROR; - } + /* Set up the context assuming we won't use the specified namespaces. + This is (currently) identical to setting up a pure DNS namespace */ + if ((r = getdns_context_prepare_for_resolution(context, 0))) + return r; + + /* create the request */ + if (!(req = dns_req_new(context, loop, name, request_type, extensions))) + return GETDNS_RETURN_MEMORY_ERROR; req->user_pointer = userarg; req->user_callback = callbackfn; - if (transaction_id) { + if (transaction_id) *transaction_id = req->trans_id; - } getdns_context_track_outbound_request(req); - /* assign a timeout */ - // req->ev_base = ev_base; - // req->timeout = evtimer_new(ev_base, ub_resolve_timeout, req); - /* schedule the timeout */ - getdns_context_schedule_timeout(context, context->timeout, - ub_resolve_timeout, req, &req->timeout); - - /* issue the first network req */ - netreq = req->first_req; - while (r == GETDNS_RETURN_GOOD && netreq) { - r = submit_network_request(netreq); - netreq = netreq->next; + if (1 || context->resolution_type == GETDNS_RESOLUTION_RECURSING) { + /* schedule the timeout */ + req->timeout.userarg = req; + req->timeout.read_cb = NULL; + req->timeout.write_cb = NULL; + req->timeout.timeout_cb = ub_resolve_timeout; + req->timeout.ev = NULL; + if ((r = loop->vmt->schedule( + loop, -1, context->timeout, &req->timeout))) + return r; } + + if (!usenamespaces) + /* issue all network requests */ + for (netreq = req->first_req; !r && netreq; netreq = netreq->next) + r = submit_network_request(netreq); + + else for (i = 0; i < context->namespace_count; i++) { + if (context->namespaces[i] == GETDNS_NAMESPACE_LOCALNAMES) { + + if (!(r = getdns_context_local_namespace_resolve( + req, &localnames_response, context))) + + priv_getdns_call_user_callback + ( req, localnames_response); + break; + } else if (context->namespaces[i] == GETDNS_NAMESPACE_DNS) { + + /* TODO: We will get a good return code here even if + the name is not found (NXDOMAIN). We should consider + if this means we go onto the next namespace instead + of returning */ + + netreq = req->first_req; + while (!r && netreq) { + r = submit_network_request(netreq); + netreq = netreq->next; + } + break; + } else + r = GETDNS_RETURN_BAD_CONTEXT; + } + if (r != 0) { /* clean up the request */ getdns_context_clear_outbound_request(req); dns_req_free(req); - return GETDNS_RETURN_GENERIC_ERROR; + return r; } return GETDNS_RETURN_GOOD; -} /* getdns_general_ub */ +} /* getdns_general_ns */ + +getdns_return_t +getdns_general_loop(getdns_context *context, getdns_eventloop *loop, + const char *name, uint16_t request_type, getdns_dict *extensions, + void *userarg, getdns_transaction_t *transaction_id, + getdns_callback_t callback) +{ + return getdns_general_ns(context, loop, + name, request_type, extensions, + userarg, transaction_id, callback, 0); + +} /* getdns_general_loop */ + +getdns_return_t +getdns_address_loop(getdns_context *context, getdns_eventloop *loop, + const char *name, getdns_dict *extensions, void *userarg, + getdns_transaction_t *transaction_id, getdns_callback_t callback) +{ + int cleanup_extensions = 0; + getdns_return_t r; + + if (!extensions) { + if (!(extensions = getdns_dict_create_with_context(context))) + return GETDNS_RETURN_MEMORY_ERROR; + cleanup_extensions = 1; + } + if ((r = getdns_dict_set_int(extensions, "return_both_v4_and_v6", + GETDNS_EXTENSION_TRUE))) + return r; + + r = getdns_general_ns(context, loop, + name, GETDNS_RRTYPE_A, extensions, + userarg, transaction_id, callback, 1); + + if (cleanup_extensions) + getdns_dict_destroy(extensions); + + return r; +} /* getdns_address_loop */ /** * getdns_general */ getdns_return_t -getdns_general(struct getdns_context *context, - const char *name, - uint16_t request_type, - struct getdns_dict * extensions, - void *userarg, - getdns_transaction_t * transaction_id, getdns_callback_t callback) +getdns_general(getdns_context *context, + const char *name, uint16_t request_type, getdns_dict *extensions, + void *userarg, getdns_transaction_t * transaction_id, + getdns_callback_t callback) { - int extcheck = GETDNS_RETURN_GOOD; - - if (!context) { - /* Can't do async without an event loop - * or callback - */ - return GETDNS_RETURN_INVALID_PARAMETER; - } - - /* ensure callback is not NULL */ - if (!callback || !name) { - return GETDNS_RETURN_INVALID_PARAMETER; - } - - extcheck = validate_dname(name); - if (extcheck != GETDNS_RETURN_GOOD) { - return extcheck; - } - - extcheck = validate_extensions(extensions); - if (extcheck != GETDNS_RETURN_GOOD) - return extcheck; - - return getdns_general_ub(context, - name, request_type, extensions, userarg, transaction_id, callback, 0); + return getdns_general_loop(context, context->extension, + name, request_type, extensions, + userarg, transaction_id, callback); } /* getdns_general */ @@ -258,44 +300,14 @@ getdns_general(struct getdns_context *context, * */ getdns_return_t -getdns_address(struct getdns_context *context, - const char *name, - struct getdns_dict * extensions, - void *userarg, - getdns_transaction_t * transaction_id, getdns_callback_t callback) +getdns_address(getdns_context *context, + const char *name, getdns_dict *extensions, void *userarg, + getdns_transaction_t *transaction_id, getdns_callback_t callback) { - int cleanup_extensions = 0; - int extcheck; - getdns_return_t result; - - if (!context) - return GETDNS_RETURN_INVALID_PARAMETER; - if (!callback || !name) - return GETDNS_RETURN_INVALID_PARAMETER; - - extcheck = validate_dname(name); - if (extcheck != GETDNS_RETURN_GOOD) - return extcheck; - - /* we set the extensions that make general behave like getdns_address */ - if (!extensions) - { - extensions = getdns_dict_create_with_context(context); - cleanup_extensions = 1; - } - getdns_dict_set_int(extensions, - GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6, GETDNS_EXTENSION_TRUE); - extcheck = validate_extensions(extensions); - if (extcheck != GETDNS_RETURN_GOOD) - return extcheck; - - result = getdns_general_ub(context, - name, GETDNS_RRTYPE_A, extensions, userarg, transaction_id, callback, 1); - - if (cleanup_extensions) - getdns_dict_destroy(extensions); - - return result; + return getdns_address_loop(context, context->extension, + name, extensions, userarg, + transaction_id, callback); } /* getdns_address */ + /* getdns_general.c */ diff --git a/src/general.h b/src/general.h index 91c00fc0..e58b467a 100644 --- a/src/general.h +++ b/src/general.h @@ -42,15 +42,35 @@ /* private inner helper used by sync and async */ getdns_return_t -getdns_general_ub(struct getdns_context *context, - const char *name, - uint16_t request_type, - struct getdns_dict *extensions, - void *userarg, - getdns_transaction_t * transaction_id, - getdns_callback_t callbackfn, - int usenamespaces); +getdns_general_ns(getdns_context *context, getdns_eventloop *loop, + const char *name, uint16_t request_type, getdns_dict *extensions, + void *userarg, getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn, int usenamespaces); void priv_getdns_call_user_callback(getdns_dns_req *, struct getdns_dict *); +getdns_return_t +getdns_general_loop(getdns_context *context, getdns_eventloop *loop, + const char *name, uint16_t request_type, getdns_dict *extensions, + void *userarg, getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn); + +getdns_return_t +getdns_address_loop(getdns_context *context, getdns_eventloop *loop, + const char *name, getdns_dict *extensions, + void *userarg, getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn); + +getdns_return_t +getdns_hostname_loop(getdns_context *context, getdns_eventloop *loop, + getdns_dict *address, getdns_dict *extensions, + void *userarg, getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn); + +getdns_return_t +getdns_service_loop(getdns_context *context, getdns_eventloop *loop, + const char *name, getdns_dict *extensions, + void *userarg, getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn); + #endif diff --git a/src/hostname.c b/src/hostname.c index 7faab768..b77493a1 100644 --- a/src/hostname.c +++ b/src/hostname.c @@ -50,11 +50,9 @@ * */ getdns_return_t -getdns_hostname(struct getdns_context *context, - struct getdns_dict * address, - struct getdns_dict * extensions, - void *userarg, - getdns_transaction_t * transaction_id, getdns_callback_t callback) +getdns_hostname_loop(getdns_context *context, getdns_eventloop *loop, + getdns_dict *address, getdns_dict *extensions, void *userarg, + getdns_transaction_t *transaction_id, getdns_callback_t callback) { struct getdns_bindata *address_data; struct getdns_bindata *address_type; @@ -83,10 +81,24 @@ getdns_hostname(struct getdns_context *context, return GETDNS_RETURN_INVALID_PARAMETER; if ((name = reverse_address(address_data)) == NULL) return GETDNS_RETURN_INVALID_PARAMETER; - retval = getdns_general(context, name, req_type, extensions, + retval = getdns_general_loop(context, loop, name, req_type, extensions, userarg, transaction_id, callback); free(name); return retval; +} /* getdns_hostname_loop */ + +/* + * getdns_hostname + * + */ +getdns_return_t +getdns_hostname(getdns_context *context, + getdns_dict *address, getdns_dict *extensions, void *userarg, + getdns_transaction_t *transaction_id, getdns_callback_t callback) +{ + return getdns_hostname_loop(context, context->extension, + address, extensions, userarg, transaction_id, callback); } /* getdns_hostname */ + /* hostname.c */ diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index a3e9d447..82df876a 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -91,10 +91,10 @@ getdns_root_trust_anchor getdns_context_set_return_dnssec_status getdns_dict_util_set_string getdns_dict_util_get_string -getdns_context_get_num_pending_requests getdns_context_fd -getdns_context_process_async getdns_context_set_use_threads -getdns_extension_set_eventloop -getdns_context_get_extension_data -getdns_extension_detach_eventloop +getdns_context_get_num_pending_requests +getdns_context_process_async +getdns_context_set_eventloop +getdns_context_detach_eventloop +getdns_context_run diff --git a/src/request-internal.c b/src/request-internal.c index 0b2156b5..7d001448 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -82,7 +82,6 @@ dns_req_free(getdns_dns_req * req) return; } getdns_network_req *net_req = NULL; - struct getdns_context *context = req->context; /* free extensions */ getdns_dict_destroy(req->extensions); @@ -95,7 +94,10 @@ dns_req_free(getdns_dns_req * req) net_req = next; } - getdns_context_clear_timeout(context, &req->timeout); + if (req->timeout.timeout_cb) { + req->loop->vmt->clear(req->loop, &req->timeout); + req->timeout.timeout_cb = NULL; + } /* free strduped name */ GETDNS_FREE(req->my_mf, req->name); @@ -104,7 +106,7 @@ 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, +dns_req_new(struct getdns_context *context, getdns_eventloop *loop, const char *name, uint16_t request_type, struct getdns_dict *extensions) { @@ -119,10 +121,12 @@ dns_req_new(struct getdns_context *context, 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 = ldns_get_random(); + result->trans_id = (((uint64_t) ldns_get_random()) << 32) + ^ ((intptr_t) result); getdns_dict_copy(extensions, &result->extensions); result->return_dnssec_status = context->return_dnssec_status; diff --git a/src/service.c b/src/service.c index 18c795ad..695dd3a0 100644 --- a/src/service.c +++ b/src/service.c @@ -43,35 +43,25 @@ * */ getdns_return_t -getdns_service(struct getdns_context *context, - const char *name, - struct getdns_dict * extensions, - void *userarg, +getdns_service_loop(struct getdns_context *context, getdns_eventloop *loop, + const char *name, getdns_dict *extensions, void *userarg, getdns_transaction_t * transaction_id, getdns_callback_t callback) { - int parmcheck; - getdns_return_t result; + return getdns_general_ns(context, loop, name, GETDNS_RRTYPE_SRV, + extensions, userarg, transaction_id, callback, 1); +} /* getdns_service_loop */ - if (!context) - return GETDNS_RETURN_INVALID_PARAMETER; - if (!callback || !name) - return GETDNS_RETURN_INVALID_PARAMETER; - - parmcheck = validate_dname(name); - if (parmcheck != GETDNS_RETURN_GOOD) - return parmcheck; - - if(extensions) - { - parmcheck = validate_extensions(extensions); - if (parmcheck != GETDNS_RETURN_GOOD) - return parmcheck; - } - - result = getdns_general_ub(context, - name, GETDNS_RRTYPE_SRV, extensions, userarg, transaction_id, callback, 1); - - return result; +/* + * getdns_service + * + */ +getdns_return_t +getdns_service(getdns_context *context, + const char *name, getdns_dict *extensions, void *userarg, + getdns_transaction_t *transaction_id, getdns_callback_t callback) +{ + return getdns_service_loop(context, context->extension, + name, extensions, userarg, transaction_id, callback); } /* getdns_service */ /* service.c */ diff --git a/src/sync.c b/src/sync.c index e55cb015..47bf4f7b 100755 --- a/src/sync.c +++ b/src/sync.c @@ -163,7 +163,7 @@ getdns_general_sync_ns(struct getdns_context *context, return response_status; /* create the request */ - req = dns_req_new(context, name, request_type, extensions); + req = dns_req_new(context, context->extension, name, request_type, extensions); if (!req) return GETDNS_RETURN_MEMORY_ERROR; diff --git a/src/types-internal.h b/src/types-internal.h index b3723ef8..9b0cea51 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -196,6 +196,9 @@ typedef struct getdns_dns_req /* request extensions */ struct getdns_dict *extensions; + /* event loop */ + getdns_eventloop *loop; + /* callback data */ getdns_callback_t user_callback; void *user_pointer; @@ -203,6 +206,7 @@ typedef struct getdns_dns_req /* the transaction id */ getdns_transaction_t trans_id; + /* for scheduling timeouts when using libunbound */ getdns_eventloop_event timeout; /* dnssec status */ @@ -246,8 +250,8 @@ getdns_network_req *network_req_new(getdns_dns_req * owner, uint16_t request_class, struct getdns_dict *extensions); /* dns request utils */ -getdns_dns_req *dns_req_new(struct getdns_context *context, - const char *name, uint16_t request_type, struct getdns_dict *extensions); +getdns_dns_req *dns_req_new(getdns_context *context, getdns_eventloop *loop, + const char *name, uint16_t request_type, getdns_dict *extensions); void dns_req_free(getdns_dns_req * req);