From 65762811bfe8eaacfc41034811f9555ce8ed8772 Mon Sep 17 00:00:00 2001 From: Neel Goyal Date: Fri, 18 Oct 2013 13:55:31 -0400 Subject: [PATCH] Adding timeout support --- .gitignore | 1 + src/context.c | 61 ++++++++++-------- src/context.h | 8 ++- src/convert.c | 8 ++- src/example/example_synchronous.c | 13 ++-- src/general.c | 45 ++++++++++--- src/general.h | 20 +++--- src/getdns/getdns_error.h | 20 +----- src/getdns_error.c | 23 ++++++- src/libgetdns.so | Bin 0 -> 71176 bytes src/nameserver-internal.c | 101 ------------------------------ src/request-internal.c | 8 +++ src/sync.c | 1 + src/test/tests_stub_async.c | 4 +- src/types-internal.h | 4 ++ 15 files changed, 145 insertions(+), 172 deletions(-) create mode 100755 src/libgetdns.so delete mode 100644 src/nameserver-internal.c diff --git a/.gitignore b/.gitignore index 0cf0fcb2..167faec1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ getdns*.tar.gz Makefile *.lo *.la +*.dSYM/ configure config.status config.log diff --git a/src/context.c b/src/context.c index 6021d54b..a1a04ba8 100644 --- a/src/context.c +++ b/src/context.c @@ -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) { diff --git a/src/context.h b/src/context.h index f9278896..8c283899 100644 --- a/src/context.h +++ b/src/context.h @@ -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 diff --git a/src/convert.c b/src/convert.c index 2e73e301..9f1d5d9c 100644 --- a/src/convert.c +++ b/src/convert.c @@ -29,6 +29,7 @@ */ #include +#include #include #include #include @@ -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 */ diff --git a/src/example/example_synchronous.c b/src/example/example_synchronous.c index 784709af..5d53ff10 100644 --- a/src/example/example_synchronous.c +++ b/src/example/example_synchronous.c @@ -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 */ diff --git a/src/general.c b/src/general.c index 2865e6b5..2e59af63 100644 --- a/src/general.c +++ b/src/general.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #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, diff --git a/src/general.h b/src/general.h index ee3bd84b..658131eb 100644 --- a/src/general.h +++ b/src/general.h @@ -32,18 +32,22 @@ #include +/* 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 diff --git a/src/getdns/getdns_error.h b/src/getdns/getdns_error.h index 68a0fd3e..311e3f69 100644 --- a/src/getdns/getdns_error.h +++ b/src/getdns/getdns_error.h @@ -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); diff --git a/src/getdns_error.c b/src/getdns_error.c index cb804da6..bc7832d7 100644 --- a/src/getdns_error.c +++ b/src/getdns_error.c @@ -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 #include +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 diff --git a/src/libgetdns.so b/src/libgetdns.so new file mode 100755 index 0000000000000000000000000000000000000000..6cd91f311a1fb207124c26595c1d8bea339f2937 GIT binary patch literal 71176 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 -#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; -} - diff --git a/src/request-internal.c b/src/request-internal.c index 604b6bac..167e5721 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -31,6 +31,7 @@ #include "types-internal.h" #include "util-internal.h" #include +#include /* 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); diff --git a/src/sync.c b/src/sync.c index e0937ce4..bdd2b62b 100644 --- a/src/sync.c +++ b/src/sync.c @@ -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, diff --git a/src/test/tests_stub_async.c b/src/test/tests_stub_async.c index 8c6139ad..091e8be0 100644 --- a/src/test/tests_stub_async.c +++ b/src/test/tests_stub_async.c @@ -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) diff --git a/src/types-internal.h b/src/types-internal.h index 15475a5d..822e206b 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -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;