Author: file Date: Tue Mar 10 12:42:18 2015 New Revision: 432689 URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=432689 Log: Add a resolver implementation which uses libunbound.
Added: team/group/dns/res/res_resolver_unbound.c (with props) Added: team/group/dns/res/res_resolver_unbound.c URL: http://svnview.digium.com/svn/asterisk/team/group/dns/res/res_resolver_unbound.c?view=auto&rev=432689 ============================================================================== --- team/group/dns/res/res_resolver_unbound.c (added) +++ team/group/dns/res/res_resolver_unbound.c Tue Mar 10 12:42:18 2015 @@ -1,0 +1,250 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2014, Digium, Inc. + * + * Joshua Colp <jc...@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*** MODULEINFO + <depend>unbound</depend> + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +#include <unbound.h> + +#include "asterisk/module.h" +#include "asterisk/linkedlists.h" +#include "asterisk/dns_core.h" +#include "asterisk/dns_resolver.h" + +/*! \brief Structure for an unbound resolver */ +struct unbound_resolver { + /*! \brief Resolver context itself */ + struct ub_ctx *context; + /*! \brief Thread handling the resolver */ + pthread_t thread; +}; + +/*! \brief Structure for query resolver data */ +struct unbound_resolver_data { + /*! \brief ID for the specific query */ + int id; +}; + +/*! \brief Unbound resolver */ +static struct unbound_resolver *resolver; + +/*! \brief Destructor for unbound resolver */ +static void unbound_resolver_destroy(void *obj) +{ + struct unbound_resolver *resolver = obj; + + if (resolver->context) { + ub_ctx_delete(resolver->context); + } +} + +/*! \brief Allocator for unbound resolver */ +static struct unbound_resolver *unbound_resolver_alloc(void) +{ + struct unbound_resolver *resolver; + + resolver = ao2_alloc_options(sizeof(*resolver), unbound_resolver_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!resolver) { + return NULL; + } + + resolver->thread = AST_PTHREADT_NULL; + + resolver->context = ub_ctx_create(); + if (!resolver->context) { + ao2_ref(resolver, -1); + return NULL; + } + + /* Each async result should be invoked in a separate thread so others are not blocked */ + ub_ctx_async(resolver->context, 1); + + ub_ctx_resolvconf(resolver->context, NULL); + ub_ctx_hosts(resolver->context, NULL); + + return resolver; +} + +/*! \brief Resolver thread which waits and handles results */ +static void *unbound_resolver_thread(void *data) +{ + struct unbound_resolver *resolver = data; + + ast_debug(1, "Starting processing for unbound resolver\n"); + + while (resolver->thread != AST_PTHREADT_STOP) { + /* Wait for any results to come in */ + ast_wait_for_input(ub_fd(resolver->context), -1); + + /* Finally process any results */ + ub_process(resolver->context); + } + + ast_debug(1, "Terminating processing for unbound resolver\n"); + + ao2_ref(resolver, -1); + + return NULL; +} + +/*! \brief Start function for the unbound resolver */ +static int unbound_resolver_start(struct unbound_resolver *resolver) +{ + int res; + + if (resolver->thread != AST_PTHREADT_NULL) { + return 0; + } + + ast_debug(1, "Starting thread for unbound resolver\n"); + + res = ast_pthread_create(&resolver->thread, NULL, unbound_resolver_thread, ao2_bump(resolver)); + if (res) { + ast_debug(1, "Could not start thread for unbound resolver\n"); + ao2_ref(resolver, -1); + } + + return res; +} + +/*! \brief Stop function for the unbound resolver */ +static void unbound_resolver_stop(struct unbound_resolver *resolver) +{ + pthread_t thread; + + if (resolver->thread == AST_PTHREADT_NULL) { + return; + } + + ast_debug(1, "Stopping processing thread for unbound resolver\n"); + + thread = resolver->thread; + resolver->thread = AST_PTHREADT_STOP; + pthread_kill(thread, SIGURG); + pthread_join(thread, NULL); + + ast_debug(1, "Stopped processing thread for unbound resolver\n"); +} + +/*! \brief Callback invoked when resolution completes on a query */ +static void unbound_resolver_callback(void *data, int err, struct ub_result *ub_result) +{ + RAII_VAR(struct ast_dns_query *, query, data, ao2_cleanup); + + if (!ast_dns_resolver_set_result(query, ub_result->secure, ub_result->bogus, ub_result->rcode, + ub_result->canonname)) { + int i; + char *data; + + for (i = 0; (data = ub_result->data[i]); i++) { + if (ast_dns_resolver_add_record(query, ub_result->qtype, ub_result->qclass, ub_result->ttl, + data, ub_result->len[i])) { + break; + } + } + } + + ast_dns_resolver_completed(query); + ub_resolve_free(ub_result); +} + +static int unbound_resolver_resolve(struct ast_dns_query *query) +{ + struct unbound_resolver_data *data; + int res; + + data = ao2_alloc_options(sizeof(*data), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!data) { + ast_log(LOG_ERROR, "Failed to allocate resolver data for resolution of '%s'\n", + ast_dns_query_get_name(query)); + return -1; + } + ast_dns_resolver_set_data(query, data); + + res = ub_resolve_async(resolver->context, ast_dns_query_get_name(query), + ast_dns_query_get_rr_type(query), ast_dns_query_get_rr_class(query), + ao2_bump(query), unbound_resolver_callback, &data->id); + + if (res) { + ast_log(LOG_ERROR, "Failed to perform async DNS resolution of '%s'\n", + ast_dns_query_get_name(query)); + ao2_ref(query, -1); + } + + ao2_ref(data, -1); + + return res; +} + +static int unbound_resolver_cancel(struct ast_dns_query *query) +{ + struct unbound_resolver_data *data = ast_dns_resolver_get_data(query); + int res; + + res = ub_cancel(resolver->context, data->id); + if (!res) { + /* When this query was started we bumped the ref, now that it has been cancelled we have ownership and + * need to drop it + */ + ao2_ref(query, -1); + } + + return res; +} + +struct ast_dns_resolver unbound_resolver = { + .name = "unbound", + .priority = 100, + .resolve = unbound_resolver_resolve, + .cancel = unbound_resolver_cancel, +}; + +static int unload_module(void) +{ + unbound_resolver_stop(resolver); + ao2_replace(resolver, NULL); + return 0; +} + +static int load_module(void) +{ + resolver = unbound_resolver_alloc(); + if (!resolver) { + return AST_MODULE_LOAD_DECLINE; + } + + if (unbound_resolver_start(resolver)) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + + ast_dns_resolver_register(&unbound_resolver); + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Unbound DNS Resolver Support", + .support_level = AST_MODULE_SUPPORT_CORE, + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4, + ); Propchange: team/group/dns/res/res_resolver_unbound.c ------------------------------------------------------------------------------ svn:eol-style = native Propchange: team/group/dns/res/res_resolver_unbound.c ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Propchange: team/group/dns/res/res_resolver_unbound.c ------------------------------------------------------------------------------ svn:mime-type = text/plain -- _____________________________________________________________________ -- Bandwidth and Colocation Provided by http://www.api-digital.com -- svn-commits mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/svn-commits