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; +} -- _____________________________________________________________________ -- 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