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 00000000..6cd91f31 Binary files /dev/null and b/src/libgetdns.so differ diff --git a/src/nameserver-internal.c b/src/nameserver-internal.c deleted file mode 100644 index b440633a..00000000 --- a/src/nameserver-internal.c +++ /dev/null @@ -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; -} - 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;