Asterisk - The Open Source Telephony Project GIT-master-2de1a68
dns_query_set.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2015, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief DNS Query Set API
22 *
23 * \author Joshua Colp <jcolp@digium.com>
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include "asterisk/vector.h"
33#include "asterisk/astobj2.h"
34#include "asterisk/utils.h"
36#include "asterisk/dns_core.h"
40
41/*! \brief The default number of expected queries to be added to the query set */
42#define DNS_QUERY_SET_EXPECTED_QUERY_COUNT 5
43
44/*! \brief Destructor for DNS query set */
45static void dns_query_set_destroy(void *data)
46{
47 struct ast_dns_query_set *query_set = data;
48 int idx;
49
50 for (idx = 0; idx < AST_VECTOR_SIZE(&query_set->queries); ++idx) {
51 struct dns_query_set_query *query = AST_VECTOR_GET_ADDR(&query_set->queries, idx);
52
53 ao2_ref(query->query, -1);
54 }
55 AST_VECTOR_FREE(&query_set->queries);
56
57 ao2_cleanup(query_set->user_data);
58}
59
61{
62 struct ast_dns_query_set *query_set;
63
65 if (!query_set) {
66 return NULL;
67 }
68
70 ao2_ref(query_set, -1);
71 return NULL;
72 }
73
74 return query_set;
75}
76
77/*! \brief Callback invoked upon completion of a DNS query */
78static void dns_query_set_callback(const struct ast_dns_query *query)
79{
80 struct ast_dns_query_set *query_set = ast_dns_query_get_data(query);
81
82 /* The reference count of the query set is bumped here in case this query holds the last reference */
83 ao2_ref(query_set, +1);
84
85 /* Drop the query set from the query so the query set can be destroyed if this is the last one */
86 ao2_cleanup(((struct ast_dns_query *)query)->user_data);
87 ((struct ast_dns_query *)query)->user_data = NULL;
88
89 if (ast_atomic_fetchadd_int(&query_set->queries_completed, +1) != (AST_VECTOR_SIZE(&query_set->queries) - 1)) {
90 ao2_ref(query_set, -1);
91 return;
92 }
93
94 /* All queries have been completed, invoke final callback */
95 if (query_set->queries_cancelled != AST_VECTOR_SIZE(&query_set->queries)) {
96 query_set->callback(query_set);
97 }
98
99 ao2_cleanup(query_set->user_data);
100 query_set->user_data = NULL;
101
102 ao2_ref(query_set, -1);
103}
104
105int ast_dns_query_set_add(struct ast_dns_query_set *query_set, const char *name, int rr_type, int rr_class)
106{
107 struct dns_query_set_query query = {
108 .started = 0,
109 };
110
111 ast_assert(!query_set->in_progress);
112 if (query_set->in_progress) {
113 ast_log(LOG_ERROR, "Attempted to add additional query to query set '%p' after resolution has started\n",
114 query_set);
115 return -1;
116 }
117
118 /*
119 * We are intentionally passing NULL for the user data even
120 * though dns_query_set_callback() is not NULL tolerant. Doing
121 * this avoids a circular reference chain until the queries are
122 * started. ast_dns_query_set_resolve_async() will set the
123 * query user_data for us later when we actually kick off the
124 * queries.
125 */
126 query.query = dns_query_alloc(name, rr_type, rr_class, dns_query_set_callback, NULL);
127 if (!query.query) {
128 return -1;
129 }
130
131 if (AST_VECTOR_APPEND(&query_set->queries, query)) {
132 ao2_ref(query.query, -1);
133 return -1;
134 }
135
136 return 0;
137}
138
140{
141 return AST_VECTOR_SIZE(&query_set->queries);
142}
143
144struct ast_dns_query *ast_dns_query_set_get(const struct ast_dns_query_set *query_set, unsigned int index)
145{
146 /* Only once all queries have been completed can results be retrieved */
147 if (query_set->queries_completed != AST_VECTOR_SIZE(&query_set->queries)) {
148 return NULL;
149 }
150
151 /* If the index exceeds the number of queries... no query for you */
152 if (index >= AST_VECTOR_SIZE(&query_set->queries)) {
153 return NULL;
154 }
155
156 return AST_VECTOR_GET_ADDR(&query_set->queries, index)->query;
157}
158
159void *ast_dns_query_set_get_data(const struct ast_dns_query_set *query_set)
160{
161 return query_set->user_data;
162}
163
165{
166 int idx;
167
168 ast_assert(!query_set->in_progress);
169 if (query_set->in_progress) {
170 ast_log(LOG_ERROR, "Attempted to start asynchronous resolution of query set '%p' when it has already started\n",
171 query_set);
172 return;
173 }
174
175 query_set->in_progress = 1;
176 query_set->callback = callback;
177 query_set->user_data = ao2_bump(data);
178
179 /*
180 * Bump the query_set ref in case all queries complete
181 * before we are done kicking them off.
182 */
183 ao2_ref(query_set, +1);
184 for (idx = 0; idx < AST_VECTOR_SIZE(&query_set->queries); ++idx) {
185 struct dns_query_set_query *query = AST_VECTOR_GET_ADDR(&query_set->queries, idx);
186
187 query->query->user_data = ao2_bump(query_set);
188
189 if (!query->query->resolver->resolve(query->query)) {
190 query->started = 1;
191 continue;
192 }
193
195 }
196 if (!idx) {
197 /*
198 * There were no queries in the set;
199 * therefore all queries are "completed".
200 * Invoke the final callback.
201 */
202 query_set->callback(query_set);
203 ao2_cleanup(query_set->user_data);
204 query_set->user_data = NULL;
205 }
206 ao2_ref(query_set, -1);
207}
208
209/*! \brief Structure used for signaling back for synchronous resolution completion */
211 /*! \brief Lock used for signaling */
213 /*! \brief Condition used for signaling */
215 /*! \brief Whether the query has completed */
216 unsigned int completed;
217};
218
219/*! \brief Destructor for synchronous resolution structure */
220static void dns_synchronous_resolve_destroy(void *data)
221{
222 struct dns_synchronous_resolve *synchronous = data;
223
224 ast_mutex_destroy(&synchronous->lock);
225 ast_cond_destroy(&synchronous->cond);
226}
227
228/*! \brief Callback used to implement synchronous resolution */
229static void dns_synchronous_resolve_callback(const struct ast_dns_query_set *query_set)
230{
231 struct dns_synchronous_resolve *synchronous = ast_dns_query_set_get_data(query_set);
232
233 ast_mutex_lock(&synchronous->lock);
234 synchronous->completed = 1;
235 ast_cond_signal(&synchronous->cond);
236 ast_mutex_unlock(&synchronous->lock);
237}
238
240{
241 struct dns_synchronous_resolve *synchronous;
242
244 if (!synchronous) {
245 return -1;
246 }
247
248 ast_mutex_init(&synchronous->lock);
249 ast_cond_init(&synchronous->cond, NULL);
250
252
253 /* Wait for resolution to complete */
254 ast_mutex_lock(&synchronous->lock);
255 while (!synchronous->completed) {
256 ast_cond_wait(&synchronous->cond, &synchronous->lock);
257 }
258 ast_mutex_unlock(&synchronous->lock);
259
260 ao2_ref(synchronous, -1);
261
262 return 0;
263}
264
266{
267 int idx;
268 size_t query_count = AST_VECTOR_SIZE(&query_set->queries);
269
270 for (idx = 0; idx < AST_VECTOR_SIZE(&query_set->queries); ++idx) {
271 struct dns_query_set_query *query = AST_VECTOR_GET_ADDR(&query_set->queries, idx);
272
273 if (query->started) {
274 if (!query->query->resolver->cancel(query->query)) {
275 query_set->queries_cancelled++;
277 }
278 } else {
279 query_set->queries_cancelled++;
280 }
281 }
282
283 return (query_set->queries_cancelled == query_count) ? 0 : -1;
284}
Asterisk main include file. File version handling, generic pbx functions.
#define ast_log
Definition: astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Core DNS API.
void * ast_dns_query_get_data(const struct ast_dns_query *query)
Get the user specific data of a DNS query.
Definition: dns_core.c:72
Internal DNS structure definitions.
struct ast_dns_query * dns_query_alloc(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
Allocate a DNS query (but do not start resolution)
Definition: dns_core.c:193
struct ast_dns_query * ast_dns_query_set_get(const struct ast_dns_query_set *query_set, unsigned int index)
Retrieve a query from a query set.
static void dns_query_set_callback(const struct ast_dns_query *query)
Callback invoked upon completion of a DNS query.
Definition: dns_query_set.c:78
struct ast_dns_query_set * ast_dns_query_set_create(void)
Create a query set to hold queries.
Definition: dns_query_set.c:60
static void dns_synchronous_resolve_callback(const struct ast_dns_query_set *query_set)
Callback used to implement synchronous resolution.
size_t ast_dns_query_set_num_queries(const struct ast_dns_query_set *query_set)
Retrieve the number of queries in a query set.
static void dns_query_set_destroy(void *data)
Destructor for DNS query set.
Definition: dns_query_set.c:45
static void dns_synchronous_resolve_destroy(void *data)
Destructor for synchronous resolution structure.
int ast_dns_query_set_add(struct ast_dns_query_set *query_set, const char *name, int rr_type, int rr_class)
Add a query to a query set.
#define DNS_QUERY_SET_EXPECTED_QUERY_COUNT
The default number of expected queries to be added to the query set.
Definition: dns_query_set.c:42
int ast_query_set_resolve(struct ast_dns_query_set *query_set)
Synchronously resolve queries in a query set.
int ast_dns_query_set_resolve_cancel(struct ast_dns_query_set *query_set)
Cancel an asynchronous DNS query set resolution.
void ast_dns_query_set_resolve_async(struct ast_dns_query_set *query_set, ast_dns_query_set_callback callback, void *data)
Asynchronously resolve queries in a query set.
void * ast_dns_query_set_get_data(const struct ast_dns_query_set *query_set)
Retrieve user specific data from a query set.
DNS Query Set API.
void(* ast_dns_query_set_callback)(const struct ast_dns_query_set *query_set)
Callback invoked when a query set completes.
Definition: dns_query_set.h:39
DNS Resolver API.
static const char name[]
Definition: format_mp3.c:68
#define LOG_ERROR
A set of macros to manage forward-linked lists.
#define ast_cond_destroy(cond)
Definition: lock.h:202
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
pthread_cond_t ast_cond_t
Definition: lock.h:178
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:189
#define ast_cond_signal(cond)
Definition: lock.h:203
#define NULL
Definition: resample.c:96
A set of DNS queries.
Definition: dns_internal.h:185
void * user_data
User-specific data.
Definition: dns_internal.h:197
ast_dns_query_set_callback callback
Callback to invoke upon completion.
Definition: dns_internal.h:195
struct ast_dns_query_set::@216 queries
DNS queries.
int queries_cancelled
The total number of cancelled queries.
Definition: dns_internal.h:193
int queries_completed
The total number of completed queries.
Definition: dns_internal.h:191
int in_progress
Whether the query set is in progress or not.
Definition: dns_internal.h:189
A DNS query.
Definition: dns_internal.h:137
void * user_data
User-specific data.
Definition: dns_internal.h:141
ast_dns_resolve_callback callback
Callback to invoke upon completion.
Definition: dns_internal.h:139
struct ast_dns_resolver * resolver
The resolver in use for this query.
Definition: dns_internal.h:143
int rr_class
Resource record class.
Definition: dns_internal.h:151
int rr_type
Resource record type.
Definition: dns_internal.h:149
int(* cancel)(struct ast_dns_query *query)
Cancel resolution of a DNS query.
Definition: dns_resolver.h:48
int(* resolve)(struct ast_dns_query *query)
Perform resolution of a DNS query.
Definition: dns_resolver.h:45
Structure for mutex and tracking information.
Definition: lock.h:135
A DNS query set query, which includes its state.
Definition: dns_internal.h:177
struct ast_dns_query * query
The query itself.
Definition: dns_internal.h:181
Structure used for signaling back for synchronous resolution completion.
Definition: dns_core.c:278
ast_cond_t cond
Condition used for signaling.
Definition: dns_core.c:282
ast_mutex_t lock
Lock used for signaling.
Definition: dns_core.c:280
unsigned int completed
Whether the query has completed.
Definition: dns_core.c:284
Utility functions.
#define ast_assert(a)
Definition: utils.h:739
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:668