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 */
|
/* set upstreams */
|
||||||
ub_setup_stub(context->unbound_async, context->upstream_list, upstream_len);
|
ub_setup_stub(context->unbound_async, context->upstream_list, upstream_len);
|
||||||
ub_setup_stub(context->unbound_sync, 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) {
|
} else if (context->resolution_type == GETDNS_CONTEXT_RECURSING) {
|
||||||
/* set recursive */
|
/* 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
|
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"
|
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;
|
return;
|
||||||
}
|
}
|
||||||
struct getdns_list * just_the_addresses_ptr;
|
struct getdns_list * just_the_addresses_ptr;
|
||||||
this_ret = getdns_dict_get_list(this_response, "just_address_answers", &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"
|
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;
|
return;
|
||||||
}
|
}
|
||||||
size_t num_addresses = 0;
|
size_t num_addresses = 0;
|
||||||
this_ret = getdns_list_get_length(just_the_addresses_ptr, &num_addresses); // Ignore any error
|
this_ret = getdns_list_get_length(just_the_addresses_ptr, &num_addresses); // Ignore any error
|
||||||
/* Go through each record */
|
/* 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 )
|
for ( size_t rec_count = 0; rec_count < num_addresses; ++rec_count )
|
||||||
{
|
{
|
||||||
struct getdns_bindata * this_address_data;
|
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)
|
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
|
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 */
|
/* clean up */
|
||||||
getdns_dict_destroy(this_response);
|
getdns_dict_destroy(this_response);
|
||||||
|
@ -101,7 +108,7 @@ main()
|
||||||
this_event_base = event_base_new();
|
this_event_base = event_base_new();
|
||||||
if (this_event_base == NULL)
|
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);
|
return(GETDNS_RETURN_GENERIC_ERROR);
|
||||||
}
|
}
|
||||||
(void)getdns_extension_set_libevent_base(this_context, this_event_base);
|
(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
|
char* this_userarg = "somestring"; // Could add things here to help identify this call
|
||||||
getdns_transaction_t this_transaction_id = 0;
|
getdns_transaction_t this_transaction_id = 0;
|
||||||
|
|
||||||
|
// getdns_context_set_resolution_type(this_context, GETDNS_CONTEXT_STUB);
|
||||||
|
|
||||||
/* Make the call */
|
/* Make the call */
|
||||||
getdns_return_t dns_request_return = getdns_address(this_context, this_name,
|
getdns_return_t dns_request_return = getdns_address(this_context, this_name,
|
||||||
NULL, this_userarg, &this_transaction_id, this_callbackfn);
|
NULL, this_userarg, &this_transaction_id, this_callbackfn);
|
||||||
if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
|
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);
|
return(GETDNS_RETURN_GENERIC_ERROR);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -28,36 +28,6 @@
|
||||||
* THE SOFTWARE.
|
* 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 <string.h>
|
||||||
#include <unbound.h>
|
#include <unbound.h>
|
||||||
#include <unbound-event.h>
|
#include <unbound-event.h>
|
||||||
|
@ -66,16 +36,28 @@
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "types-internal.h"
|
#include "types-internal.h"
|
||||||
#include "util-internal.h"
|
#include "util-internal.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
/* stuff to make it compile pedantically */
|
/* stuff to make it compile pedantically */
|
||||||
#define UNUSED_PARAM(x) ((void)(x))
|
#define UNUSED_PARAM(x) ((void)(x))
|
||||||
|
|
||||||
/* declarations */
|
/* declarations */
|
||||||
static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec, char* bogus);
|
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_network_request_error(getdns_network_req* netreq, int err);
|
||||||
static void handle_dns_request_complete(getdns_dns_req* dns_req);
|
static void handle_dns_request_complete(getdns_dns_req* dns_req);
|
||||||
static int submit_network_request(getdns_network_req* netreq);
|
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 */
|
/* cancel, cleanup and send timeout to callback */
|
||||||
static void ub_resolve_timeout(evutil_socket_t fd, short what, void *arg) {
|
static void ub_resolve_timeout(evutil_socket_t fd, short what, void *arg) {
|
||||||
getdns_dns_req *dns_req = (getdns_dns_req*) 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);
|
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 */
|
/* cleanup and send an error to the user callback */
|
||||||
static void handle_network_request_error(getdns_network_req* netreq, int err) {
|
static void handle_network_request_error(getdns_network_req* netreq, int err) {
|
||||||
getdns_dns_req *dns_req = netreq->owner;
|
getdns_dns_req *dns_req = netreq->owner;
|
||||||
|
@ -157,12 +160,45 @@ static int submit_network_request(getdns_network_req* netreq) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec, char* bogus) {
|
static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec, char* bogus) {
|
||||||
getdns_network_req* netreq = (getdns_network_req*) arg;
|
getdns_network_req* netreq = (getdns_network_req*) arg;
|
||||||
/* if netreq->state == NET_REQ_NOT_SENT here, that implies
|
/* if netreq->state == NET_REQ_NOT_SENT here, that implies
|
||||||
* that ub called us back immediately - probably from a local file.
|
* that ub called us back immediately - probably from a local file.
|
||||||
* This most likely means that getdns_general has not returned
|
* 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;
|
netreq->state = NET_REQ_FINISHED;
|
||||||
if (err) {
|
if (err) {
|
||||||
handle_network_request_error(netreq, err);
|
handle_network_request_error(netreq, err);
|
||||||
|
@ -230,12 +266,14 @@ getdns_general_ub(struct ub_ctx* unbound,
|
||||||
getdns_context_track_outbound_request(req);
|
getdns_context_track_outbound_request(req);
|
||||||
|
|
||||||
/* assign a timeout */
|
/* assign a timeout */
|
||||||
|
req->ev_base = ev_base;
|
||||||
req->timeout = evtimer_new(ev_base, ub_resolve_timeout, req);
|
req->timeout = evtimer_new(ev_base, ub_resolve_timeout, req);
|
||||||
tv.tv_sec = context->timeout / 1000;
|
tv.tv_sec = context->timeout / 1000;
|
||||||
tv.tv_usec = (context->timeout % 1000) * 1000;
|
tv.tv_usec = (context->timeout % 1000) * 1000;
|
||||||
evtimer_add(req->timeout, &tv);
|
evtimer_add(req->timeout, &tv);
|
||||||
|
|
||||||
/* issue the first network req */
|
/* issue the first network req */
|
||||||
|
|
||||||
r = submit_network_request(req->first_req);
|
r = submit_network_request(req->first_req);
|
||||||
|
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
|
|
|
@ -96,6 +96,11 @@ void dns_req_free(getdns_dns_req* req) {
|
||||||
event_free(req->timeout);
|
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 strduped name */
|
||||||
free(req->name);
|
free(req->name);
|
||||||
|
|
||||||
|
@ -127,6 +132,8 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
|
||||||
result->first_req = NULL;
|
result->first_req = NULL;
|
||||||
result->trans_id = ldns_get_random();
|
result->trans_id = ldns_get_random();
|
||||||
result->timeout = NULL;
|
result->timeout = NULL;
|
||||||
|
result->local_cb_timer = NULL;
|
||||||
|
result->ev_base = NULL;
|
||||||
|
|
||||||
getdns_dict_copy(extensions, &result->extensions);
|
getdns_dict_copy(extensions, &result->extensions);
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct getdns_dns_req;
|
||||||
struct getdns_network_req;
|
struct getdns_network_req;
|
||||||
struct ub_ctx;
|
struct ub_ctx;
|
||||||
struct event;
|
struct event;
|
||||||
|
struct event_base;
|
||||||
|
|
||||||
typedef enum network_req_state_enum {
|
typedef enum network_req_state_enum {
|
||||||
NET_REQ_NOT_SENT,
|
NET_REQ_NOT_SENT,
|
||||||
|
@ -91,6 +92,12 @@ typedef struct getdns_dns_req {
|
||||||
/* request timeout event */
|
/* request timeout event */
|
||||||
struct event* timeout;
|
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 */
|
/* context that owns the request */
|
||||||
getdns_context_t context;
|
getdns_context_t context;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue