mirror of https://github.com/getdnsapi/getdns.git
Handle immediate callback.
This commit is contained in:
parent
266cdb0063
commit
4fb66d8ea7
|
@ -919,6 +919,9 @@ getdns_return_t getdns_context_prepare_for_resolution(getdns_context_t context)
|
|||
/* set upstreams */
|
||||
ub_setup_stub(context->unbound_async, context->upstream_list, upstream_len);
|
||||
ub_setup_stub(context->unbound_sync, context->upstream_list, upstream_len);
|
||||
/* use /etc/hosts */
|
||||
ub_ctx_hosts(context->unbound_sync, NULL);
|
||||
ub_ctx_hosts(context->unbound_async, NULL);
|
||||
|
||||
} else if (context->resolution_type == GETDNS_CONTEXT_RECURSING) {
|
||||
/* set recursive */
|
||||
|
|
|
@ -53,19 +53,26 @@ void this_callbackfn(struct getdns_context_t *this_context,
|
|||
this_ret = getdns_dict_get_int(this_response, "status", &this_error); // Ignore any error
|
||||
if (this_error != GETDNS_RESPSTATUS_GOOD) // If the search didn't return "good"
|
||||
{
|
||||
fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", this_error);
|
||||
fprintf(stderr, "The search had no results, and a return value of %d. Exiting.\n", this_error);
|
||||
getdns_dict_destroy(this_response);
|
||||
return;
|
||||
}
|
||||
struct getdns_list * just_the_addresses_ptr;
|
||||
this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr);
|
||||
if (this_ret != GETDNS_RETURN_GOOD) // This check is really not needed, but prevents a compiler error under "pedantic"
|
||||
{
|
||||
fprintf(stderr, "Trying to get the answers failed: %d", this_ret);
|
||||
fprintf(stderr, "Trying to get the answers failed: %d\n", this_ret);
|
||||
getdns_dict_destroy(this_response);
|
||||
return;
|
||||
}
|
||||
size_t num_addresses = 0;
|
||||
this_ret = getdns_list_get_length(just_the_addresses_ptr, &num_addresses); // Ignore any error
|
||||
/* Go through each record */
|
||||
if (num_addresses == 0) {
|
||||
fprintf(stderr, "There are no addresses.\n");
|
||||
getdns_dict_destroy(this_response);
|
||||
return;
|
||||
}
|
||||
for ( size_t rec_count = 0; rec_count < num_addresses; ++rec_count )
|
||||
{
|
||||
struct getdns_bindata * this_address_data;
|
||||
|
@ -77,9 +84,9 @@ void this_callbackfn(struct getdns_context_t *this_context,
|
|||
}
|
||||
}
|
||||
else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
|
||||
fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id);
|
||||
fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.\n", this_transaction_id);
|
||||
else
|
||||
fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type);
|
||||
fprintf(stderr, "The callback got a callback_type of %d. Exiting.\n", this_callback_type);
|
||||
|
||||
/* clean up */
|
||||
getdns_dict_destroy(this_response);
|
||||
|
@ -101,7 +108,7 @@ main()
|
|||
this_event_base = event_base_new();
|
||||
if (this_event_base == NULL)
|
||||
{
|
||||
fprintf(stderr, "Trying to create the event base failed.");
|
||||
fprintf(stderr, "Trying to create the event base failed.\n");
|
||||
return(GETDNS_RETURN_GENERIC_ERROR);
|
||||
}
|
||||
(void)getdns_extension_set_libevent_base(this_context, this_event_base);
|
||||
|
@ -110,12 +117,17 @@ main()
|
|||
char* this_userarg = "somestring"; // Could add things here to help identify this call
|
||||
getdns_transaction_t this_transaction_id = 0;
|
||||
|
||||
// getdns_context_set_resolution_type(this_context, GETDNS_CONTEXT_STUB);
|
||||
|
||||
/* Make the call */
|
||||
getdns_return_t dns_request_return = getdns_address(this_context, this_name,
|
||||
NULL, this_userarg, &this_transaction_id, this_callbackfn);
|
||||
if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
|
||||
{
|
||||
fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name);
|
||||
fprintf(stderr, "A bad domain name was used: %s. Exiting.\n", this_name);
|
||||
return(GETDNS_RETURN_GENERIC_ERROR);
|
||||
} else if (dns_request_return != GETDNS_RETURN_GOOD) {
|
||||
fprintf(stderr, "The context is not setup properly.\n");
|
||||
return(GETDNS_RETURN_GENERIC_ERROR);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -28,36 +28,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Much of this is based on / duplicated code from libevent evdns. Credits to
|
||||
* Nick Mathewson and Niels Provos
|
||||
*
|
||||
* https://github.com/libevent/libevent/
|
||||
*
|
||||
* libevent dns is based on software by Adam Langly. Adam's original message:
|
||||
*
|
||||
* Async DNS Library
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
* http://www.imperialviolet.org/eventdns.html
|
||||
* Public Domain code
|
||||
*
|
||||
* This software is Public Domain. To view a copy of the public domain dedication,
|
||||
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
|
||||
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
|
||||
*
|
||||
* I ask and expect, but do not require, that all derivative works contain an
|
||||
* attribution similar to:
|
||||
* Parts developed by Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* You may wish to replace the word "Parts" with something else depending on
|
||||
* the amount of original code.
|
||||
*
|
||||
* (Derivative works does not include programs which link against, run or include
|
||||
* the source verbatim in their source distributions)
|
||||
*
|
||||
* Version: 0.1b
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <unbound.h>
|
||||
#include <unbound-event.h>
|
||||
|
@ -66,16 +36,28 @@
|
|||
#include "context.h"
|
||||
#include "types-internal.h"
|
||||
#include "util-internal.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* stuff to make it compile pedantically */
|
||||
#define UNUSED_PARAM(x) ((void)(x))
|
||||
|
||||
/* declarations */
|
||||
static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec, char* bogus);
|
||||
static void ub_resolve_timeout(evutil_socket_t fd, short what, void *arg);
|
||||
static void ub_local_resolve_timeout(evutil_socket_t fd, short what, void *arg);
|
||||
|
||||
static void handle_network_request_error(getdns_network_req* netreq, int err);
|
||||
static void handle_dns_request_complete(getdns_dns_req* dns_req);
|
||||
static int submit_network_request(getdns_network_req* netreq);
|
||||
|
||||
typedef struct netreq_cb_data {
|
||||
getdns_network_req *netreq;
|
||||
int err;
|
||||
ldns_buffer* result;
|
||||
int sec;
|
||||
char* bogus;
|
||||
} netreq_cb_data;
|
||||
|
||||
/* cancel, cleanup and send timeout to callback */
|
||||
static void ub_resolve_timeout(evutil_socket_t fd, short what, void *arg) {
|
||||
getdns_dns_req *dns_req = (getdns_dns_req*) arg;
|
||||
|
@ -97,6 +79,27 @@ static void ub_resolve_timeout(evutil_socket_t fd, short what, void *arg) {
|
|||
trans_id);
|
||||
}
|
||||
|
||||
static void ub_local_resolve_timeout(evutil_socket_t fd, short what, void *arg) {
|
||||
netreq_cb_data* cb_data = (netreq_cb_data*) arg;
|
||||
|
||||
/* cleanup the local timer here since the memory may be
|
||||
* invalid after calling ub_resolve_callback
|
||||
*/
|
||||
getdns_dns_req* dnsreq = cb_data->netreq->owner;
|
||||
event_free(dnsreq->local_cb_timer);
|
||||
dnsreq->local_cb_timer = NULL;
|
||||
|
||||
/* just call ub_resolve_callback */
|
||||
ub_resolve_callback(cb_data->netreq, cb_data->err, cb_data->result, cb_data->sec, cb_data->bogus);
|
||||
|
||||
/* cleanup the state */
|
||||
ldns_buffer_free(cb_data->result);
|
||||
if (cb_data->bogus) {
|
||||
free(cb_data->bogus);
|
||||
}
|
||||
free(cb_data);
|
||||
}
|
||||
|
||||
/* cleanup and send an error to the user callback */
|
||||
static void handle_network_request_error(getdns_network_req* netreq, int err) {
|
||||
getdns_dns_req *dns_req = netreq->owner;
|
||||
|
@ -157,12 +160,45 @@ static int submit_network_request(getdns_network_req* netreq) {
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec, char* bogus) {
|
||||
getdns_network_req* netreq = (getdns_network_req*) arg;
|
||||
/* if netreq->state == NET_REQ_NOT_SENT here, that implies
|
||||
* that ub called us back immediately - probably from a local file.
|
||||
* This most likely means that getdns_general has not returned
|
||||
*/
|
||||
if (netreq->state == NET_REQ_NOT_SENT) {
|
||||
/* just do a very short timer since this was called immediately.
|
||||
* we can make this less hacky, but it gets interesting when multiple
|
||||
* netreqs need to be issued and some resolve immediately vs. not.
|
||||
*/
|
||||
struct timeval tv;
|
||||
getdns_dns_req* dnsreq = netreq->owner;
|
||||
netreq_cb_data* cb_data = (netreq_cb_data*) malloc(sizeof(netreq_cb_data));
|
||||
|
||||
cb_data->netreq = netreq;
|
||||
cb_data->err = err;
|
||||
cb_data->sec = sec;
|
||||
cb_data->result = NULL;
|
||||
cb_data->bogus = NULL; /* unused but here in case we need it */
|
||||
if (result) {
|
||||
cb_data->result = ldns_buffer_new(ldns_buffer_limit(result));
|
||||
if (!cb_data->result) {
|
||||
cb_data->err = GETDNS_RETURN_GENERIC_ERROR;
|
||||
} else {
|
||||
/* copy */
|
||||
ldns_buffer_copy(cb_data->result, result);
|
||||
}
|
||||
}
|
||||
/* schedule the timeout */
|
||||
dnsreq->local_cb_timer = evtimer_new(dnsreq->ev_base, ub_local_resolve_timeout, cb_data);
|
||||
tv.tv_sec = 0;
|
||||
/* half ms */
|
||||
tv.tv_usec = 500;
|
||||
evtimer_add(dnsreq->local_cb_timer, &tv);
|
||||
return;
|
||||
}
|
||||
netreq->state = NET_REQ_FINISHED;
|
||||
if (err) {
|
||||
handle_network_request_error(netreq, err);
|
||||
|
@ -230,12 +266,14 @@ getdns_general_ub(struct ub_ctx* unbound,
|
|||
getdns_context_track_outbound_request(req);
|
||||
|
||||
/* assign a timeout */
|
||||
req->ev_base = ev_base;
|
||||
req->timeout = evtimer_new(ev_base, ub_resolve_timeout, req);
|
||||
tv.tv_sec = context->timeout / 1000;
|
||||
tv.tv_usec = (context->timeout % 1000) * 1000;
|
||||
evtimer_add(req->timeout, &tv);
|
||||
|
||||
/* issue the first network req */
|
||||
|
||||
r = submit_network_request(req->first_req);
|
||||
|
||||
if (r != 0) {
|
||||
|
|
|
@ -96,6 +96,11 @@ void dns_req_free(getdns_dns_req* req) {
|
|||
event_free(req->timeout);
|
||||
}
|
||||
|
||||
if (req->local_cb_timer) {
|
||||
event_del(req->local_cb_timer);
|
||||
event_free(req->local_cb_timer);
|
||||
}
|
||||
|
||||
/* free strduped name */
|
||||
free(req->name);
|
||||
|
||||
|
@ -127,6 +132,8 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
|
|||
result->first_req = NULL;
|
||||
result->trans_id = ldns_get_random();
|
||||
result->timeout = NULL;
|
||||
result->local_cb_timer = NULL;
|
||||
result->ev_base = NULL;
|
||||
|
||||
getdns_dict_copy(extensions, &result->extensions);
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ struct getdns_dns_req;
|
|||
struct getdns_network_req;
|
||||
struct ub_ctx;
|
||||
struct event;
|
||||
struct event_base;
|
||||
|
||||
typedef enum network_req_state_enum {
|
||||
NET_REQ_NOT_SENT,
|
||||
|
@ -91,6 +92,12 @@ typedef struct getdns_dns_req {
|
|||
/* request timeout event */
|
||||
struct event* timeout;
|
||||
|
||||
/* local callback timer */
|
||||
struct event* local_cb_timer;
|
||||
|
||||
/* event base this req is scheduled on */
|
||||
struct event_base* ev_base;
|
||||
|
||||
/* context that owns the request */
|
||||
getdns_context_t context;
|
||||
|
||||
|
|
Loading…
Reference in New Issue