Adding timeout support

This commit is contained in:
Neel Goyal 2013-10-18 13:55:31 -04:00
parent 840939aac8
commit 65762811bf
15 changed files with 145 additions and 172 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ getdns*.tar.gz
Makefile
*.lo
*.la
*.dSYM/
configure
config.status
config.log

View File

@ -214,8 +214,8 @@ getdns_return_t getdns_context_create(
result->unbound_sync = ub_ctx_create_event(result->event_base_sync);
/* create the async one also so options are kept up to date */
result->unbound_async = ub_ctx_create_event(result->event_base_sync);
result->event_base_async = NULL;
result->async_set = 0;
result->resolution_type_set = 0;
result->outbound_requests = ldns_rbtree_create(transaction_id_cmp);
@ -814,10 +814,10 @@ getdns_extension_set_libevent_base(
{
if (this_event_base) {
ub_ctx_set_event(context->unbound_async, this_event_base);
context->async_set = 1;
context->event_base_async = this_event_base;
} else {
ub_ctx_set_event(context->unbound_async, context->event_base_sync);
context->async_set = 0;
context->event_base_async = NULL;
}
return GETDNS_RETURN_GOOD;
} /* getdns_extension_set_libevent_base */
@ -839,19 +839,10 @@ static void cancel_dns_req(getdns_dns_req* req) {
req->canceled = 1;
}
/*
* getdns_cancel_callback
*
*/
getdns_return_t
getdns_cancel_callback(
getdns_context_t context,
getdns_transaction_t transaction_id
)
{
getdns_return_t getdns_context_cancel_request(getdns_context_t context,
getdns_transaction_t transaction_id,
int fire_callback) {
getdns_dns_req *req = NULL;
getdns_callback_t cb = NULL;
void* user_pointer = NULL;
/* delete the node from the tree */
ldns_rbnode_t* node = ldns_rbtree_delete(context->outbound_requests,
@ -864,21 +855,39 @@ getdns_cancel_callback(
/* do the cancel */
cancel_dns_req(req);
cb = req->user_callback;
user_pointer = req->user_pointer;
/* clean up */
context->memory_deallocator(node);
dns_req_free(req);
if (fire_callback) {
getdns_callback_t cb = NULL;
void* user_pointer = NULL;
/* fire callback */
cb(context,
GETDNS_CALLBACK_CANCEL,
NULL,
user_pointer,
transaction_id);
cb = req->user_callback;
user_pointer = req->user_pointer;
/* clean up */
context->memory_deallocator(node);
dns_req_free(req);
/* fire callback */
cb(context,
GETDNS_CALLBACK_CANCEL,
NULL,
user_pointer,
transaction_id);
}
return GETDNS_RETURN_GOOD;
}
/*
* getdns_cancel_callback
*
*/
getdns_return_t
getdns_cancel_callback(
getdns_context_t context,
getdns_transaction_t transaction_id
)
{
return getdns_context_cancel_request(context, transaction_id, 1);
} /* getdns_cancel_callback */
static void ub_setup_stub(struct ub_ctx* ctx, getdns_list* upstreams, size_t count) {

View File

@ -67,13 +67,13 @@ struct getdns_context_t {
/* Event loop for sync requests */
struct event_base* event_base_sync;
/* Event loop for async requests */
struct event_base* event_base_async;
/* The underlying unbound contexts that do
the real work */
struct ub_ctx *unbound_sync;
struct ub_ctx *unbound_async;
/* whether an async event base was set */
uint8_t async_set;
/* which resolution type the contexts are configured for
* 0 means nothing set
@ -97,6 +97,10 @@ getdns_return_t getdns_context_prepare_for_resolution(getdns_context_t context);
getdns_return_t getdns_context_track_outbound_request(struct getdns_dns_req* req);
/* clear the outbound request from being tracked - does not cancel it */
getdns_return_t getdns_context_clear_outbound_request(struct getdns_dns_req* req);
/* cancel callback internal - flag to indicate if req should be freed and callback fired */
getdns_return_t getdns_context_cancel_request(getdns_context_t context,
getdns_transaction_t transaction_id,
int fire_callback);
#endif

View File

@ -29,6 +29,7 @@
*/
#include <getdns/getdns.h>
#include <getdns/getdns_error.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <util-internal.h>
@ -96,9 +97,12 @@ getdns_strerror(getdns_return_t err, char *buf, size_t buflen)
{
getdns_return_t retval = GETDNS_RETURN_GOOD;
/* TODO: make this produce an actual string */
const char* err_str = getdns_get_errorstr_by_id(err);
if (!err_str) {
return GETDNS_RETURN_GENERIC_ERROR;
}
snprintf(buf, buflen, "%d", retval);
snprintf(buf, buflen, "%s", err_str);
return retval;
} /* getdns_strerror */

View File

@ -11,10 +11,10 @@
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -39,7 +39,6 @@ main()
struct getdns_list *just_the_addresses_ptr;
size_t num_addresses = 0;
size_t rec_count;
struct getdns_dict *this_address;
struct getdns_bindata *this_address_data;
struct getdns_context_t *this_context = NULL;
uint32_t this_error = 0;
@ -91,16 +90,20 @@ main()
if (num_addresses > 0) {
for (rec_count = 0; rec_count < num_addresses; ++rec_count )
{
char * display = getdns_display_ip_address(this_address_data);
this_ret = getdns_list_get_bindata(just_the_addresses_ptr, rec_count, &this_address_data); // Ignore any error
/* Just print the address */
printf("The address is %s\n", getdns_display_ip_address(this_address_data));
printf("The address is %s\n", display);
if (display) {
free(display);
}
}
}
}
/* Clean up */
getdns_context_destroy(this_context);
getdns_free_sync_request_memory(this_response);
getdns_free_sync_request_memory(this_response);
exit(EXIT_SUCCESS);
} /* main */

View File

@ -61,6 +61,7 @@
#include <string.h>
#include <unbound.h>
#include <unbound-event.h>
#include <event2/event.h>
#include <ldns/ldns.h>
#include "context.h"
#include "types-internal.h"
@ -70,13 +71,34 @@
#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 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);
static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec, char* bogus);
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);
/* 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;
getdns_context_t context = dns_req->context;
getdns_transaction_t trans_id = dns_req->trans_id;
getdns_callback_t cb = dns_req->user_callback;
void* user_arg = dns_req->user_pointer;
/* cancel the req - also clears it from outbound */
getdns_context_cancel_request(context, trans_id, 0);
/* cleanup */
dns_req_free(dns_req);
cb(context,
GETDNS_CALLBACK_TIMEOUT,
NULL,
user_arg,
trans_id);
}
/* 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_context_t context = dns_req->context;
getdns_transaction_t trans_id = dns_req->trans_id;
@ -166,6 +188,7 @@ static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec
getdns_return_t
getdns_general_ub(struct ub_ctx* unbound,
struct event_base* ev_base,
getdns_context_t context,
const char *name,
uint16_t request_type,
@ -173,7 +196,8 @@ getdns_general_ub(struct ub_ctx* unbound,
void *userarg,
getdns_transaction_t *transaction_id,
getdns_callback_t callbackfn) {
/* timeout */
struct timeval tv;
getdns_return_t gr;
int r;
@ -201,6 +225,12 @@ getdns_general_ub(struct ub_ctx* unbound,
getdns_context_track_outbound_request(req);
/* assign a timeout */
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);
@ -225,7 +255,7 @@ getdns_general_ub(struct ub_ctx* unbound,
getdns_transaction_t *transaction_id,
getdns_callback_t callback) {
if (!context || context->async_set == 0 ||
if (!context || !context->event_base_async ||
callback == NULL) {
/* Can't do async without an event loop
* or callback
@ -234,6 +264,7 @@ getdns_general_ub(struct ub_ctx* unbound,
}
return getdns_general_ub(context->unbound_async,
context->event_base_async,
context,
name,
request_type,

View File

@ -32,18 +32,22 @@
#include <getdns/getdns.h>
/* private inner helper used by sync and async */
struct ub_ctx;
struct event_base;
getdns_return_t
getdns_general_ub(
struct ub_ctx* unbound,
getdns_context_t context,
const char *name,
uint16_t request_type,
struct getdns_dict *extensions,
void *userarg,
getdns_transaction_t *transaction_id,
getdns_callback_t callbackfn
struct ub_ctx* unbound,
struct event_base* ev_base,
getdns_context_t context,
const char *name,
uint16_t request_type,
struct getdns_dict *extensions,
void *userarg,
getdns_transaction_t *transaction_id,
getdns_callback_t callbackfn
);
#endif

View File

@ -14,10 +14,10 @@
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -46,21 +46,7 @@ typedef struct getdns_struct_lookup_table getdns_lookup_table;
* @{
*/
getdns_lookup_table getdns_error_str[] = {
{ GETDNS_RETURN_GOOD, "Good" },
{ GETDNS_RETURN_GENERIC_ERROR, "Generic error" },
{ GETDNS_RETURN_BAD_DOMAIN_NAME, "Badly-formed domain name" },
{ GETDNS_RETURN_BAD_CONTEXT, "Bad value for a context type" },
{ GETDNS_RETURN_CONTEXT_UPDATE_FAIL, "Did not update the context" },
{ GETDNS_RETURN_UNKNOWN_TRANSACTION, "An attempt was made to cancel a callback with a transaction_id that is not recognized" },
{ GETDNS_RETURN_NO_SUCH_LIST_ITEM, "A helper function for lists had an index argument that was too high" },
{ GETDNS_RETURN_NO_SUCH_DICT_NAME, "A helper function for dicts had a name argument that for a name that is not in the dict" },
{ GETDNS_RETURN_WRONG_TYPE_REQUESTED, "A helper function was supposed to return a certain type for an item, but the wrong type was given" },
{ GETDNS_RETURN_NO_SUCH_EXTENSION, "A name in the extensions dict is not a valid extension" },
{ GETDNS_RETURN_EXTENSION_MISFORMAT, "One or more of the extensions is has a bad format" },
{ GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED, "A query was made with a context that is using stub resolution and a DNSSEC extension specified" },
{ 0, "" }
};
extern getdns_lookup_table getdns_error_str[];
typedef enum getdns_enum_status getdns_status;
const char *getdns_get_errorstr_by_id(uint16_t err);

View File

@ -1,7 +1,7 @@
/**
* \file getdns_error.c
* @brief getdns error code to string function
*
*
*/
/* The MIT License (MIT)
@ -13,10 +13,10 @@
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -30,6 +30,23 @@
#include <getdns/getdns.h>
#include <getdns/getdns_error.h>
getdns_lookup_table getdns_error_str[] = {
{ GETDNS_RETURN_GOOD, "Good" },
{ GETDNS_RETURN_GENERIC_ERROR, "Generic error" },
{ GETDNS_RETURN_BAD_DOMAIN_NAME, "Badly-formed domain name" },
{ GETDNS_RETURN_BAD_CONTEXT, "Bad value for a context type" },
{ GETDNS_RETURN_CONTEXT_UPDATE_FAIL, "Did not update the context" },
{ GETDNS_RETURN_UNKNOWN_TRANSACTION, "An attempt was made to cancel a callback with a transaction_id that is not recognized" },
{ GETDNS_RETURN_NO_SUCH_LIST_ITEM, "A helper function for lists had an index argument that was too high" },
{ GETDNS_RETURN_NO_SUCH_DICT_NAME, "A helper function for dicts had a name argument that for a name that is not in the dict" },
{ GETDNS_RETURN_WRONG_TYPE_REQUESTED, "A helper function was supposed to return a certain type for an item, but the wrong type was given" },
{ GETDNS_RETURN_NO_SUCH_EXTENSION, "A name in the extensions dict is not a valid extension" },
{ GETDNS_RETURN_EXTENSION_MISFORMAT, "One or more of the extensions is has a bad format" },
{ GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED, "A query was made with a context that is using stub resolution and a DNSSEC extension specified" },
{ 0, "" }
};
/*---------------------------------------- getdns_get_errorstr_by_id() */
/**
* return error string from getdns return

BIN
src/libgetdns.so Executable file

Binary file not shown.

View File

@ -1,101 +0,0 @@
/**
*
* /brief getdns contect management functions
*
* This is the meat of the API
* Originally taken from the getdns API description pseudo implementation.
*
*/
/* The MIT License (MIT)
* Copyright (c) 2013 Verisign, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "types-internal.h"
#include "util-internal.h"
/* useful macros */
#define gd_malloc(sz) context->memory_allocator(sz)
#define gd_free(ptr) context->memory_deallocator(ptr)
getdns_nameserver* nameserver_new_from_ip_dict(getdns_context_t context,
getdns_dict* ip_dict) {
if (!context || !ip_dict) {
return NULL;
}
struct sockaddr_storage sockdata;
/* setup socket */
if (dict_to_sockaddr(ip_dict, &sockdata) != GETDNS_RETURN_GOOD) {
return NULL;
}
getdns_nameserver *result = gd_malloc(sizeof(getdns_nameserver));
if (!result) {
return NULL;
}
memset(result, 0, sizeof(getdns_nameserver));
result->context = context;
/* create socket */
evutil_socket_t sock = socket(sockdata.ss_family, SOCK_DGRAM, 0);
evutil_make_socket_closeonexec(sock);
evutil_make_socket_nonblocking(sock);
result->address = sockdata;
result->socket = sock;
int connected = -1;
if (sockdata.ss_family == AF_INET) {
connected = connect(sock, (struct sockaddr *) &sockdata, sizeof(struct sockaddr_in));
} else if (sockdata.ss_family == AF_INET6) {
connected = connect(sock, (struct sockaddr *) &sockdata, sizeof(struct sockaddr_in6));
}
if (connected != 0) {
// sad
nameserver_free(result);
result= NULL;
}
return result;
}
void nameserver_free(getdns_nameserver* nameserver) {
if (!nameserver) {
return;
}
if (nameserver->event) {
event_del(nameserver->event);
event_free(nameserver->event);
}
getdns_context_t context = nameserver->context;
evutil_closesocket(nameserver->socket);
gd_free(nameserver);
}
getdns_dict* nameserver_to_dict(getdns_nameserver* nameserver) {
if (!nameserver) {
return NULL;
}
getdns_dict* result = NULL;
sockaddr_to_dict(&nameserver->address, &result);
return result;
}

View File

@ -31,6 +31,7 @@
#include "types-internal.h"
#include "util-internal.h"
#include <unbound.h>
#include <event2/event.h>
/* useful macros */
#define gd_malloc(sz) context->memory_allocator(sz)
@ -86,6 +87,12 @@ void dns_req_free(getdns_dns_req* req) {
net_req = next;
}
/* cleanup timeout */
if (req->timeout) {
event_del(req->timeout);
event_free(req->timeout);
}
/* free strduped name */
free(req->name);
@ -116,6 +123,7 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
result->current_req = NULL;
result->first_req = NULL;
result->trans_id = ldns_get_random();
result->timeout = NULL;
getdns_dict_copy(extensions, &result->extensions);

View File

@ -61,6 +61,7 @@ static void * request_thread_start(void *arg) {
struct sync_request_data *req_data = arg;
req_data->response_status = getdns_general_ub(req_data->context->unbound_sync,
req_data->context->event_base_sync,
req_data->context,
req_data->name,
req_data->request_type,

View File

@ -65,7 +65,9 @@ main()
return(GETDNS_RETURN_GENERIC_ERROR);
}
getdns_context_set_resolution_type(this_context, GETDNS_CONTEXT_STUB);
/* Create an event base and put it in the context using the unknown function name */
getdns_context_set_timeout(this_context, 5000);
/* Create an event base and put it in the context using the unknown function name */
struct event_base *this_event_base;
this_event_base = event_base_new();
if (this_event_base == NULL)

View File

@ -38,6 +38,7 @@
struct getdns_dns_req;
struct getdns_network_req;
struct ub_ctx;
struct event;
typedef enum network_req_state_enum {
NET_REQ_NOT_SENT,
@ -87,6 +88,9 @@ typedef struct getdns_dns_req {
/* first request in list */
struct getdns_network_req *first_req;
/* request timeout event */
struct event* timeout;
/* context that owns the request */
getdns_context_t context;