[asterisk-commits] file: branch group/dns_pjsip r433943 - in /team/group/dns_pjsip: include/aste...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Apr 2 08:45:02 CDT 2015
Author: file
Date: Thu Apr 2 08:44:55 2015
New Revision: 433943
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=433943
Log:
Add a theoretical query set implementation.
Still some rough areas (like cancel) but usable enough for some PJSIP work.
Modified:
team/group/dns_pjsip/include/asterisk/dns_internal.h
team/group/dns_pjsip/include/asterisk/dns_query_set.h
team/group/dns_pjsip/main/dns_core.c
team/group/dns_pjsip/main/dns_query_set.c
Modified: team/group/dns_pjsip/include/asterisk/dns_internal.h
URL: http://svnview.digium.com/svn/asterisk/team/group/dns_pjsip/include/asterisk/dns_internal.h?view=diff&rev=433943&r1=433942&r2=433943
==============================================================================
--- team/group/dns_pjsip/include/asterisk/dns_internal.h (original)
+++ team/group/dns_pjsip/include/asterisk/dns_internal.h Thu Apr 2 08:44:55 2015
@@ -170,4 +170,24 @@
*/
void ast_dns_srv_sort(struct ast_dns_result *result);
-
+/*!
+ * \brief Allocate a DNS query (but do not start resolution)
+ *
+ * \param name The name of what to resolve
+ * \param rr_type Resource record type
+ * \param rr_class Resource record class
+ * \param callback The callback to invoke upon completion
+ * \param data User data to make available on the query
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \note The result passed to the callback does not need to be freed
+ *
+ * \note The user data MUST be an ao2 object
+ *
+ * \note This function increments the reference count of the user data, it does NOT steal
+ *
+ * \note The query must be released upon completion or cancellation using ao2_ref
+ */
+struct ast_dns_query *dns_query_alloc(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data);
Modified: team/group/dns_pjsip/include/asterisk/dns_query_set.h
URL: http://svnview.digium.com/svn/asterisk/team/group/dns_pjsip/include/asterisk/dns_query_set.h?view=diff&rev=433943&r1=433942&r2=433943
==============================================================================
--- team/group/dns_pjsip/include/asterisk/dns_query_set.h (original)
+++ team/group/dns_pjsip/include/asterisk/dns_query_set.h Thu Apr 2 08:44:55 2015
@@ -43,6 +43,8 @@
*
* \retval non-NULL success
* \retval NULL failure
+ *
+ * \note The query set must be released upon cancellation or completion using ao2_ref
*/
struct ast_dns_query_set *ast_dns_query_set_create(void);
@@ -106,28 +108,24 @@
*
* \param query_set The query set
*
+ * \retval 0 success
+ * \retval -1 failure
+ *
* \note This function will return when all queries have been completed
*/
-void ast_query_set_resolve(struct ast_dns_query_set *query_set);
+int ast_query_set_resolve(struct ast_dns_query_set *query_set);
/*!
* \brief Cancel an asynchronous DNS query set resolution
*
* \param query_set The DNS query set
*
- * \retval 0 success
- * \retval -1 failure
+ * \retval 0 success (all queries have been cancelled)
+ * \retval -1 failure (some queries could not be cancelled)
*
* \note If successfully cancelled the callback will not be invoked
*/
int ast_dns_query_set_resolve_cancel(struct ast_dns_query_set *query_set);
-
-/*!
- * \brief Free a query set
- *
- * \param query_set A DNS query set
- */
-void ast_dns_query_set_free(struct ast_dns_query_set *query_set);
#if defined(__cplusplus) || defined(c_plusplus)
}
Modified: team/group/dns_pjsip/main/dns_core.c
URL: http://svnview.digium.com/svn/asterisk/team/group/dns_pjsip/main/dns_core.c?view=diff&rev=433943&r1=433942&r2=433943
==============================================================================
--- team/group/dns_pjsip/main/dns_core.c (original)
+++ team/group/dns_pjsip/main/dns_core.c Thu Apr 2 08:44:55 2015
@@ -186,9 +186,9 @@
ast_dns_result_free(query->result);
}
-struct ast_dns_query_active *ast_dns_resolve_async(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
-{
- struct ast_dns_query_active *active;
+struct ast_dns_query *dns_query_alloc(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
+{
+ struct ast_dns_query *query;
if (ast_strlen_zero(name)) {
ast_log(LOG_WARNING, "Could not perform asynchronous resolution, no name provided\n");
@@ -215,30 +215,42 @@
return NULL;
}
+ query = ao2_alloc_options(sizeof(*query) + strlen(name) + 1, dns_query_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!query) {
+ return NULL;
+ }
+
+ query->callback = callback;
+ query->user_data = ao2_bump(data);
+ query->rr_type = rr_type;
+ query->rr_class = rr_class;
+ strcpy(query->name, name); /* SAFE */
+
+ AST_RWLIST_RDLOCK(&resolvers);
+ query->resolver = AST_RWLIST_FIRST(&resolvers);
+ AST_RWLIST_UNLOCK(&resolvers);
+
+ if (!query->resolver) {
+ ast_log(LOG_ERROR, "Attempted to do a DNS query for '%s' of class '%d' and type '%d' but no resolver is available\n",
+ name, rr_class, rr_type);
+ ao2_ref(query, -1);
+ return NULL;
+ }
+
+ return query;
+}
+
+struct ast_dns_query_active *ast_dns_resolve_async(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
+{
+ struct ast_dns_query_active *active;
+
active = ao2_alloc_options(sizeof(*active), dns_query_active_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
if (!active) {
return NULL;
}
- active->query = ao2_alloc_options(sizeof(*active->query) + strlen(name) + 1, dns_query_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ active->query = dns_query_alloc(name, rr_type, rr_class, callback, data);
if (!active->query) {
- ao2_ref(active, -1);
- return NULL;
- }
-
- active->query->callback = callback;
- active->query->user_data = ao2_bump(data);
- active->query->rr_type = rr_type;
- active->query->rr_class = rr_class;
- strcpy(active->query->name, name); /* SAFE */
-
- AST_RWLIST_RDLOCK(&resolvers);
- active->query->resolver = AST_RWLIST_FIRST(&resolvers);
- AST_RWLIST_UNLOCK(&resolvers);
-
- if (!active->query->resolver) {
- ast_log(LOG_ERROR, "Attempted to do a DNS query for '%s' of class '%d' and type '%d' but no resolver is available\n",
- name, rr_class, rr_type);
ao2_ref(active, -1);
return NULL;
}
Modified: team/group/dns_pjsip/main/dns_query_set.c
URL: http://svnview.digium.com/svn/asterisk/team/group/dns_pjsip/main/dns_query_set.c?view=diff&rev=433943&r1=433942&r2=433943
==============================================================================
--- team/group/dns_pjsip/main/dns_query_set.c (original)
+++ team/group/dns_pjsip/main/dns_query_set.c Thu Apr 2 08:44:55 2015
@@ -33,39 +33,104 @@
#include "asterisk/vector.h"
#include "asterisk/astobj2.h"
+#include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
#include "asterisk/dns_core.h"
#include "asterisk/dns_query_set.h"
+#include "asterisk/dns_internal.h"
+#include "asterisk/dns_resolver.h"
/*! \brief A set of DNS queries */
struct ast_dns_query_set {
/*! \brief DNS queries */
AST_VECTOR(, struct ast_dns_query *) queries;
/*! \brief The total number of completed queries */
- unsigned int queries_completed;
+ int queries_completed;
/*! \brief Callback to invoke upon completion */
ast_dns_query_set_callback callback;
/*! \brief User-specific data */
void *user_data;
};
+/*! \brief Destructor for DNS query set */
+static void dns_query_set_destroy(void *data)
+{
+ struct ast_dns_query_set *query_set = data;
+ int idx;
+
+ for (idx = 0; idx < AST_VECTOR_SIZE(&query_set->queries); ++idx) {
+ struct ast_dns_query *query = AST_VECTOR_GET(&query_set->queries, idx);
+
+ ao2_ref(query, -1);
+ }
+ AST_VECTOR_FREE(&query_set->queries);
+
+ ao2_cleanup(query_set->user_data);
+}
+
struct ast_dns_query_set *ast_dns_query_set_create(void)
{
- return NULL;
+ struct ast_dns_query_set *query_set;
+
+ query_set = ao2_alloc_options(sizeof(*query_set), dns_query_set_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!query_set) {
+ return NULL;
+ }
+
+ /* It is likely that since they are creating a query set there will be at least 2 queries */
+ if (AST_VECTOR_INIT(&query_set->queries, 2)) {
+ ao2_ref(query_set, -1);
+ return NULL;
+ }
+
+ return query_set;
+}
+
+/*! \brief Callback invoked upon completion of a DNS query */
+static void dns_query_set_callback(const struct ast_dns_query *query)
+{
+ struct ast_dns_query_set *query_set = ast_dns_query_get_data(query);
+
+ if (ast_atomic_fetchadd_int(&query_set->queries_completed, +1) != (AST_VECTOR_SIZE(&query_set->queries) - 1)) {
+ return;
+ }
+
+ /* All queries have been completed, invoke final callback */
+ query_set->callback(query_set->user_data);
}
int ast_dns_query_set_add(struct ast_dns_query_set *query_set, const char *name, int rr_type, int rr_class)
{
- return -1;
+ struct ast_dns_query *query;
+
+ query = dns_query_alloc(name, rr_type, rr_class, dns_query_set_callback, query_set);
+ if (!query) {
+ return -1;
+ }
+
+ AST_VECTOR_APPEND(&query_set->queries, query);
+
+ return 0;
}
size_t ast_dns_query_set_num_queries(const struct ast_dns_query_set *query_set)
{
- return 0;
+ return AST_VECTOR_SIZE(&query_set->queries);
}
struct ast_dns_query *ast_dns_query_set_get(const struct ast_dns_query_set *query_set, unsigned int index)
{
- return NULL;
+ /* Only once all queries have been completed can results be retrieved */
+ if (query_set->queries_completed != AST_VECTOR_SIZE(&query_set->queries)) {
+ return NULL;
+ }
+
+ /* If the index exceeds the number of queries... no query for you */
+ if (index >= AST_VECTOR_SIZE(&query_set->queries)) {
+ return NULL;
+ }
+
+ return AST_VECTOR_GET(&query_set->queries, index);
}
void *ast_dns_query_set_get_data(const struct ast_dns_query_set *query_set)
@@ -75,19 +140,87 @@
void ast_dns_query_set_resolve_async(struct ast_dns_query_set *query_set, ast_dns_query_set_callback callback, void *data)
{
+ int idx;
+
query_set->callback = callback;
query_set->user_data = ao2_bump(data);
-}
-
-void ast_query_set_resolve(struct ast_dns_query_set *query_set)
-{
+
+ for (idx = 0; idx < AST_VECTOR_SIZE(&query_set->queries); ++idx) {
+ struct ast_dns_query *query = AST_VECTOR_GET(&query_set->queries, idx);
+
+ if (!query->resolver->resolve(query)) {
+ continue;
+ }
+
+ dns_query_set_callback(query);
+ }
+}
+
+/*! \brief Structure used for signaling back for synchronous resolution completion */
+struct dns_synchronous_resolve {
+ /*! \brief Lock used for signaling */
+ ast_mutex_t lock;
+ /*! \brief Condition used for signaling */
+ ast_cond_t cond;
+ /*! \brief Whether the query has completed */
+ unsigned int completed;
+};
+
+/*! \brief Destructor for synchronous resolution structure */
+static void dns_synchronous_resolve_destroy(void *data)
+{
+ struct dns_synchronous_resolve *synchronous = data;
+
+ ast_mutex_destroy(&synchronous->lock);
+ ast_cond_destroy(&synchronous->cond);
+}
+
+/*! \brief Callback used to implement synchronous resolution */
+static void dns_synchronous_resolve_callback(const struct ast_dns_query_set *query_set)
+{
+ struct dns_synchronous_resolve *synchronous = ast_dns_query_set_get_data(query_set);
+
+ ast_mutex_lock(&synchronous->lock);
+ synchronous->completed = 1;
+ ast_cond_signal(&synchronous->cond);
+ ast_mutex_unlock(&synchronous->lock);
+}
+
+int ast_query_set_resolve(struct ast_dns_query_set *query_set)
+{
+ struct dns_synchronous_resolve *synchronous;
+
+ synchronous = ao2_alloc_options(sizeof(*synchronous), dns_synchronous_resolve_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!synchronous) {
+ return -1;
+ }
+
+ ast_mutex_init(&synchronous->lock);
+ ast_cond_init(&synchronous->cond, NULL);
+
+ ast_dns_query_set_resolve_async(query_set, dns_synchronous_resolve_callback, synchronous);
+
+ /* Wait for resolution to complete */
+ ast_mutex_lock(&synchronous->lock);
+ while (!synchronous->completed) {
+ ast_cond_wait(&synchronous->cond, &synchronous->lock);
+ }
+ ast_mutex_unlock(&synchronous->lock);
+
+ ao2_ref(synchronous, -1);
+
+ return 0;
}
int ast_dns_query_set_resolve_cancel(struct ast_dns_query_set *query_set)
{
- return -1;
-}
-
-void ast_dns_query_set_free(struct ast_dns_query_set *query_set)
-{
-}
+ int res = 0, idx;
+
+ for (idx = 0; idx < AST_VECTOR_SIZE(&query_set->queries); ++idx) {
+ struct ast_dns_query *query = AST_VECTOR_GET(&query_set->queries, idx);
+
+ res |= query->resolver->cancel(query);
+ }
+
+ return res;
+}
More information about the asterisk-commits
mailing list