[asterisk-commits] file: branch group/dns r432689 - /team/group/dns/res/res_resolver_unbound.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Mar 10 12:42:20 CDT 2015
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 <jcolp at 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
More information about the asterisk-commits
mailing list