Asterisk - The Open Source Telephony Project GIT-master-a358458
test_dns_recurring.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2015, Mark Michelson
5 *
6 * Mark Michelson <mmichelson@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/*** MODULEINFO
20 <depend>TEST_FRAMEWORK</depend>
21 <support_level>core</support_level>
22 ***/
23
24#include "asterisk.h"
25
26#include <arpa/nameser.h>
27#include <arpa/inet.h>
28
29#include "asterisk/test.h"
30#include "asterisk/module.h"
31#include "asterisk/dns_core.h"
35
37 /*! TTL to place in first returned result */
38 int ttl1;
39 /*! TTL to place in second returned result */
40 int ttl2;
41 /*! Boolean indicator if query has completed */
43 /*! Number of times recurring resolution has completed */
45 /*! Number of times resolve() method has been called */
47 /*! Indicates that the query is expected to be canceled */
49 /*! Indicates that the query is ready to be canceled */
51 /*! Indicates that the query has been canceled */
55};
56
57static void recurring_data_destructor(void *obj)
58{
59 struct recurring_data *rdata = obj;
60
61 ast_mutex_destroy(&rdata->lock);
62 ast_cond_destroy(&rdata->cond);
63}
64
66{
67 struct recurring_data *rdata;
68
69 rdata = ao2_alloc(sizeof(*rdata), recurring_data_destructor);
70 if (!rdata) {
71 return NULL;
72 }
73
74 ast_mutex_init(&rdata->lock);
75 ast_cond_init(&rdata->cond, NULL);
76
77 return rdata;
78}
79
80#define DNS_ANSWER "Yes sirree"
81#define DNS_ANSWER_SIZE strlen(DNS_ANSWER)
82
83/*!
84 * \brief Thread that performs asynchronous resolution.
85 *
86 * This thread uses the query's user data to determine how to
87 * perform the resolution. The query may either be canceled or
88 * it may be completed with records.
89 *
90 * \param dns_query The ast_dns_query that is being performed
91 * \return NULL
92 */
93static void *resolution_thread(void *dns_query)
94{
95 struct ast_dns_query *query = dns_query;
96
97 static const char *ADDR1 = "127.0.0.1";
98 static const size_t ADDR1_BUFSIZE = sizeof(struct in_addr);
99 char addr1_buf[ADDR1_BUFSIZE];
100
101 static const char *ADDR2 = "192.168.0.1";
102 static const size_t ADDR2_BUFSIZE = sizeof(struct in_addr);
103 char addr2_buf[ADDR2_BUFSIZE];
104
105 struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query);
106 struct recurring_data *rdata = recurring->user_data;
107
108 ast_assert(rdata != NULL);
109
110 /* Canceling is an interesting dance. This thread needs to signal that it is
111 * ready to be canceled. Then it needs to wait until the query is actually canceled.
112 */
113 if (rdata->cancel_expected) {
114 ast_mutex_lock(&rdata->lock);
115 rdata->cancel_ready = 1;
116 ast_cond_signal(&rdata->cond);
117
118 while (!rdata->canceled) {
119 ast_cond_wait(&rdata->cond, &rdata->lock);
120 }
121 ast_mutex_unlock(&rdata->lock);
122
124 ao2_ref(query, -1);
125
126 return NULL;
127 }
128
129 /* When the query isn't canceled, we set the TTL of the results based on what
130 * we've been told to set it to
131 */
132 ast_dns_resolver_set_result(query, 0, 0, NOERROR, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE);
133
134 inet_pton(AF_INET, ADDR1, addr1_buf);
135 ast_dns_resolver_add_record(query, T_A, C_IN, rdata->ttl1, addr1_buf, ADDR1_BUFSIZE);
136
137 inet_pton(AF_INET, ADDR2, addr2_buf);
138 ast_dns_resolver_add_record(query, T_A, C_IN, rdata->ttl2, addr2_buf, ADDR2_BUFSIZE);
139
140 ++rdata->complete_resolutions;
141
143
144 ao2_ref(query, -1);
145 return NULL;
146}
147
148/*!
149 * \brief Resolver's resolve() method
150 *
151 * \param query The query that is to be resolved
152 * \retval 0 Successfully created thread to perform the resolution
153 * \retval non-zero Failed to create resolution thread
154 */
155static int recurring_resolve(struct ast_dns_query *query)
156{
157 struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query);
158 struct recurring_data *rdata = recurring->user_data;
159 pthread_t resolver_thread;
160
161 ast_assert(rdata != NULL);
162 ++rdata->resolves;
163 return ast_pthread_create_detached(&resolver_thread, NULL, resolution_thread, ao2_bump(query));
164}
165
166/*!
167 * \brief Resolver's cancel() method
168 *
169 * \param query The query to cancel
170 * \return 0
171 */
172static int recurring_cancel(struct ast_dns_query *query)
173{
174 struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query);
175 struct recurring_data *rdata = recurring->user_data;
176
177 ast_mutex_lock(&rdata->lock);
178 rdata->canceled = 1;
179 ast_cond_signal(&rdata->cond);
180 ast_mutex_unlock(&rdata->lock);
181
182 return 0;
183}
184
186 .name = "test_recurring",
187 .priority = 0,
188 .resolve = recurring_resolve,
189 .cancel = recurring_cancel,
190};
191
192/*!
193 * \brief Wait for a successful resolution to complete
194 *
195 * This is called whenever a successful DNS resolution occurs. This function
196 * serves to ensure that parameters are as we expect them to be.
197 *
198 * \param test The test being executed
199 * \param rdata DNS query user data
200 * \param expected_lapse The amount of time we expect to wait for the query to complete
201 * \param num_resolves The number of DNS resolutions that have been executed
202 * \param num_completed The number of DNS resolutions we expect to have completed successfully
203 * \param canceled Whether the query is expected to have been canceled
204 */
205static int wait_for_resolution(struct ast_test *test, struct recurring_data *rdata,
206 int expected_lapse, int num_resolves, int num_completed, int canceled)
207{
208 struct timespec begin;
209 struct timespec end;
210 struct timespec timeout;
211 int secdiff;
212
213 begin = ast_tsnow();
214
215 timeout.tv_sec = begin.tv_sec + 20;
216 timeout.tv_nsec = begin.tv_nsec;
217
218 ast_mutex_lock(&rdata->lock);
219 while (!rdata->query_complete) {
220 if (ast_cond_timedwait(&rdata->cond, &rdata->lock, &timeout) == ETIMEDOUT) {
221 break;
222 }
223 }
224 ast_mutex_unlock(&rdata->lock);
225
226 if (!rdata->query_complete) {
227 ast_test_status_update(test, "Query timed out\n");
228 return -1;
229 }
230
231 rdata->query_complete = 0;
232 end = ast_tsnow();
233
234 secdiff = end.tv_sec - begin.tv_sec;
235
236 /* Give ourselves some wiggle room */
237 if (secdiff < expected_lapse - 2 || secdiff > expected_lapse + 2) {
238 ast_test_status_update(test, "Query did not complete in expected time\n");
239 return -1;
240 }
241
242 if (rdata->resolves != num_resolves || rdata->complete_resolutions != num_completed) {
243 ast_test_status_update(test, "Query has not undergone expected number of resolutions\n");
244 return -1;
245 }
246
247 if (rdata->canceled != canceled) {
248 ast_test_status_update(test, "Query was canceled unexpectedly\n");
249 return -1;
250 }
251
252 ast_test_status_update(test, "Query completed in expected time frame\n");
253
254 return 0;
255}
256
257static void async_callback(const struct ast_dns_query *query)
258{
259 struct recurring_data *rdata = ast_dns_query_get_data(query);
260
261 ast_assert(rdata != NULL);
262
263 ast_mutex_lock(&rdata->lock);
264 rdata->query_complete = 1;
265 ast_cond_signal(&rdata->cond);
266 ast_mutex_unlock(&rdata->lock);
267}
268
269AST_TEST_DEFINE(recurring_query)
270{
271 RAII_VAR(struct ast_dns_query_recurring *, recurring_query, NULL, ao2_cleanup);
272 RAII_VAR(struct recurring_data *, rdata, NULL, ao2_cleanup);
273
275 int expected_lapse;
276
277 switch (cmd) {
278 case TEST_INIT:
279 info->name = "recurring_query";
280 info->category = "/main/dns/recurring/";
281 info->summary = "Test nominal asynchronous recurring DNS queries";
282 info->description =
283 "This tests nominal recurring queries in the following ways:\n"
284 "\t* An asynchronous query is sent to a mock resolver\n"
285 "\t* The mock resolver returns two records with different TTLs\n"
286 "\t* We ensure that the query re-occurs according to the lower of the TTLs\n"
287 "\t* The mock resolver returns two records, this time with different TTLs\n"
288 "\t from the first time the query was resolved\n"
289 "\t* We ensure that the query re-occurs according to the new lower TTL";
290 return AST_TEST_NOT_RUN;
291 case TEST_EXECUTE:
292 break;
293 }
294
296 ast_test_status_update(test, "Failed to register recurring DNS resolver\n");
297 return AST_TEST_FAIL;
298 }
299
300 rdata = recurring_data_alloc();
301 if (!rdata) {
302 ast_test_status_update(test, "Failed to allocate data necessary for recurring test\n");
303 res = AST_TEST_FAIL;
304 goto cleanup;
305 }
306
307 expected_lapse = 0;
308 rdata->ttl1 = 5;
309 rdata->ttl2 = 20;
310
311 recurring_query = ast_dns_resolve_recurring("asterisk.org", T_A, C_IN, async_callback, rdata);
312 if (!recurring_query) {
313 ast_test_status_update(test, "Failed to create recurring DNS query\n");
314 res = AST_TEST_FAIL;
315 goto cleanup;
316 }
317
318 /* This should be near instantaneous */
319 if (wait_for_resolution(test, rdata, expected_lapse, 1, 1, 0)) {
320 res = AST_TEST_FAIL;
321 goto cleanup;
322 }
323
324 expected_lapse = rdata->ttl1;
325 rdata->ttl1 = 45;
326 rdata->ttl2 = 10;
327
328 /* This should take approximately 5 seconds */
329 if (wait_for_resolution(test, rdata, expected_lapse, 2, 2, 0)) {
330 res = AST_TEST_FAIL;
331 goto cleanup;
332 }
333
334 expected_lapse = rdata->ttl2;
335
336 /* This should take approximately 10 seconds */
337 if (wait_for_resolution(test, rdata, expected_lapse, 3, 3, 0)) {
338 res = AST_TEST_FAIL;
339 goto cleanup;
340 }
341
342cleanup:
343 if (recurring_query) {
344 /* XXX I don't like calling this here since I'm not testing
345 * canceling recurring queries, but I'm forced into it here
346 */
347 ast_dns_resolve_recurring_cancel(recurring_query);
348 }
350 return res;
351}
352
353static int fail_resolve(struct ast_dns_query *query)
354{
355 return -1;
356}
357
358static int stub_cancel(struct ast_dns_query *query)
359{
360 return 0;
361}
362
363static void stub_callback(const struct ast_dns_query *query)
364{
365 return;
366}
367
368AST_TEST_DEFINE(recurring_query_off_nominal)
369{
370 struct ast_dns_resolver terrible_resolver = {
371 .name = "Harold P. Warren's Filmography",
372 .priority = 0,
373 .resolve = fail_resolve,
374 .cancel = stub_cancel,
375 };
376
377 struct ast_dns_query_recurring *recurring;
378
379 struct dns_resolve_data {
380 const char *name;
381 int rr_type;
382 int rr_class;
384 } resolves [] = {
385 { NULL, T_A, C_IN, stub_callback },
386 { "asterisk.org", -1, C_IN, stub_callback },
387 { "asterisk.org", 65536 + 1, C_IN, stub_callback },
388 { "asterisk.org", T_A, -1, stub_callback },
389 { "asterisk.org", T_A, 65536 + 1, stub_callback },
390 { "asterisk.org", T_A, C_IN, NULL },
391 };
392 int i;
394
395 switch (cmd) {
396 case TEST_INIT:
397 info->name = "recurring_query_off_nominal";
398 info->category = "/main/dns/recurring/";
399 info->summary = "Test off-nominal recurring DNS resolution";
400 info->description =
401 "This test performs several off-nominal recurring DNS resolutions:\n"
402 "\t* Attempt resolution with NULL name\n"
403 "\t* Attempt resolution with invalid RR type\n"
404 "\t* Attempt resolution with invalid RR class\n"
405 "\t* Attempt resolution with NULL callback pointer\n"
406 "\t* Attempt resolution with resolver that returns an error";
407 return AST_TEST_NOT_RUN;
408 case TEST_EXECUTE:
409 break;
410 }
411
413 ast_test_status_update(test, "Failed to register test resolver\n");
414 return AST_TEST_FAIL;
415 }
416
417 for (i = 0; i < ARRAY_LEN(resolves); ++i) {
418 recurring = ast_dns_resolve_recurring(resolves[i].name, resolves[i].rr_type, resolves[i].rr_class,
419 resolves[i].callback, NULL);
420 if (recurring) {
421 ast_test_status_update(test, "Successfully performed recurring resolution with invalid data\n");
423 ao2_ref(recurring, -1);
424 res = AST_TEST_FAIL;
425 }
426 }
427
429
430 if (ast_dns_resolver_register(&terrible_resolver)) {
431 ast_test_status_update(test, "Failed to register the DNS resolver\n");
432 return AST_TEST_FAIL;
433 }
434
435 recurring = ast_dns_resolve_recurring("asterisk.org", T_A, C_IN, stub_callback, NULL);
436
437 ast_dns_resolver_unregister(&terrible_resolver);
438
439 if (recurring) {
440 ast_test_status_update(test, "Successfully performed recurring resolution with invalid data\n");
442 ao2_ref(recurring, -1);
443 return AST_TEST_FAIL;
444 }
445
446 return res;
447}
448
449AST_TEST_DEFINE(recurring_query_cancel_between)
450{
451 RAII_VAR(struct ast_dns_query_recurring *, recurring_query, NULL, ao2_cleanup);
452 RAII_VAR(struct recurring_data *, rdata, NULL, ao2_cleanup);
453
455 struct timespec timeout;
456
457 switch (cmd) {
458 case TEST_INIT:
459 info->name = "recurring_query_cancel_between";
460 info->category = "/main/dns/recurring/";
461 info->summary = "Test canceling a recurring DNS query during the downtime between queries";
462 info->description = "This test does the following:\n"
463 "\t* Issue a recurring DNS query.\n"
464 "\t* Once results have been returned, cancel the recurring query.\n"
465 "\t* Wait a while to ensure that no more queries are occurring.";
466 return AST_TEST_NOT_RUN;
467 case TEST_EXECUTE:
468 break;
469 }
470
472 ast_test_status_update(test, "Failed to register recurring DNS resolver\n");
473 return AST_TEST_FAIL;
474 }
475
476 rdata = recurring_data_alloc();
477 if (!rdata) {
478 ast_test_status_update(test, "Failed to allocate data necessary for recurring test\n");
479 res = AST_TEST_FAIL;
480 goto cleanup;
481 }
482
483 rdata->ttl1 = 5;
484 rdata->ttl2 = 20;
485
486 recurring_query = ast_dns_resolve_recurring("asterisk.org", T_A, C_IN, async_callback, rdata);
487 if (!recurring_query) {
488 ast_test_status_update(test, "Unable to make recurring query\n");
489 res = AST_TEST_FAIL;
490 goto cleanup;
491 }
492
493 if (wait_for_resolution(test, rdata, 0, 1, 1, 0)) {
494 res = AST_TEST_FAIL;
495 goto cleanup;
496 }
497
498 if (ast_dns_resolve_recurring_cancel(recurring_query)) {
499 ast_test_status_update(test, "Failed to cancel recurring query\n");
500 res = AST_TEST_FAIL;
501 goto cleanup;
502 }
503
504 /* Query has been canceled, so let's wait to make sure that we don't get
505 * told another query has occurred.
506 */
507 timeout = ast_tsnow();
508 timeout.tv_sec += 10;
509
510 ast_mutex_lock(&rdata->lock);
511 while (!rdata->query_complete) {
512 if (ast_cond_timedwait(&rdata->cond, &rdata->lock, &timeout) == ETIMEDOUT) {
513 break;
514 }
515 }
516 ast_mutex_unlock(&rdata->lock);
517
518 if (rdata->query_complete) {
519 ast_test_status_update(test, "Recurring query occurred after cancellation\n");
520 res = AST_TEST_FAIL;
521 goto cleanup;
522 }
523
524cleanup:
526 return res;
527}
528
529AST_TEST_DEFINE(recurring_query_cancel_during)
530{
531
532 RAII_VAR(struct ast_dns_query_recurring *, recurring_query, NULL, ao2_cleanup);
533 RAII_VAR(struct recurring_data *, rdata, NULL, ao2_cleanup);
534
536 struct timespec timeout;
537
538 switch (cmd) {
539 case TEST_INIT:
540 info->name = "recurring_query_cancel_during";
541 info->category = "/main/dns/recurring/";
542 info->summary = "Cancel a recurring DNS query while a query is actually happening";
543 info->description = "This test does the following:\n"
544 "\t* Initiate a recurring DNS query.\n"
545 "\t* Allow the initial query to complete, and a second query to start\n"
546 "\t* Cancel the recurring query while the second query is executing\n"
547 "\t* Ensure that the resolver's cancel() method was called\n"
548 "\t* Wait a while to make sure that recurring queries are no longer occurring";
549 return AST_TEST_NOT_RUN;
550 case TEST_EXECUTE:
551 break;
552 }
553
555 ast_test_status_update(test, "Failed to register recurring DNS resolver\n");
556 return AST_TEST_FAIL;
557 }
558
559 rdata = recurring_data_alloc();
560 if (!rdata) {
561 ast_test_status_update(test, "Failed to allocate data necessary for recurring test\n");
562 res = AST_TEST_FAIL;
563 goto cleanup;
564 }
565
566 rdata->ttl1 = 5;
567 rdata->ttl2 = 20;
568
569 recurring_query = ast_dns_resolve_recurring("asterisk.org", T_A, C_IN, async_callback, rdata);
570 if (!recurring_query) {
571 ast_test_status_update(test, "Failed to make recurring DNS query\n");
572 res = AST_TEST_FAIL;
573 goto cleanup;
574 }
575
576 if (wait_for_resolution(test, rdata, 0, 1, 1, 0)) {
577 res = AST_TEST_FAIL;
578 goto cleanup;
579 }
580
581 /* Initial query has completed. Now let's make the next query expect a cancelation */
582 rdata->cancel_expected = 1;
583
584 /* Wait to be told that the query should be canceled */
585 ast_mutex_lock(&rdata->lock);
586 while (!rdata->cancel_ready) {
587 ast_cond_wait(&rdata->cond, &rdata->lock);
588 }
589 rdata->cancel_expected = 0;
590 ast_mutex_unlock(&rdata->lock);
591
592 if (ast_dns_resolve_recurring_cancel(recurring_query)) {
593 ast_test_status_update(test, "Failed to cancel recurring DNS query\n");
594 res = AST_TEST_FAIL;
595 goto cleanup;
596 }
597
598 /* Query has been canceled. We'll be told that the query in flight has completed. */
599 if (wait_for_resolution(test, rdata, 0, 2, 1, 1)) {
600 res = AST_TEST_FAIL;
601 goto cleanup;
602 }
603
604 /* Now ensure that no more queries get completed after cancellation. */
605 timeout = ast_tsnow();
606 timeout.tv_sec += 10;
607
608 ast_mutex_lock(&rdata->lock);
609 while (!rdata->query_complete) {
610 if (ast_cond_timedwait(&rdata->cond, &rdata->lock, &timeout) == ETIMEDOUT) {
611 break;
612 }
613 }
614 ast_mutex_unlock(&rdata->lock);
615
616 if (rdata->query_complete) {
617 ast_test_status_update(test, "Recurring query occurred after cancellation\n");
618 res = AST_TEST_FAIL;
619 goto cleanup;
620 }
621
622cleanup:
624 return res;
625}
626
627static int unload_module(void)
628{
629 AST_TEST_UNREGISTER(recurring_query);
630 AST_TEST_UNREGISTER(recurring_query_off_nominal);
631 AST_TEST_UNREGISTER(recurring_query_cancel_between);
632 AST_TEST_UNREGISTER(recurring_query_cancel_during);
633
634 return 0;
635}
636
637static int load_module(void)
638{
639 AST_TEST_REGISTER(recurring_query);
640 AST_TEST_REGISTER(recurring_query_off_nominal);
641 AST_TEST_REGISTER(recurring_query_cancel_between);
642 AST_TEST_REGISTER(recurring_query_cancel_during);
643
645}
646
647AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Recurring DNS query tests");
Asterisk main include file. File version handling, generic pbx functions.
#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_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
Core DNS API.
void(* ast_dns_resolve_callback)(const struct ast_dns_query *query)
Callback invoked when a query completes.
Definition: dns_core.h:171
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.
DNS Recurring Resolution API.
int ast_dns_resolve_recurring_cancel(struct ast_dns_query_recurring *recurring)
Cancel an asynchronous recurring DNS resolution.
struct ast_dns_query_recurring * ast_dns_resolve_recurring(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
Asynchronously resolve a DNS query, and continue resolving it according to the lowest TTL available.
DNS Resolver API.
int ast_dns_resolver_set_result(struct ast_dns_query *query, unsigned int secure, unsigned int bogus, unsigned int rcode, const char *canonical, const char *answer, size_t answer_size)
Set result information for a DNS query.
Definition: dns_core.c:456
void ast_dns_resolver_completed(struct ast_dns_query *query)
Mark a DNS query as having been completed.
Definition: dns_core.c:599
int ast_dns_resolver_register(struct ast_dns_resolver *resolver)
Register a DNS resolver.
Definition: dns_core.c:630
int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr_class, int ttl, const char *data, const size_t size)
Add a DNS record to the result of a DNS query.
Definition: dns_core.c:535
void ast_dns_resolver_unregister(struct ast_dns_resolver *resolver)
Unregister a DNS resolver.
Definition: dns_core.c:680
char * end
Definition: eagi_proxy.c:73
static const char name[]
Definition: format_mp3.c:68
#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_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
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
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
#define NULL
Definition: resample.c:96
A recurring DNS query.
Definition: dns_internal.h:157
void * user_data
User-specific data.
Definition: dns_internal.h:161
A DNS query.
Definition: dns_internal.h:137
DNS resolver implementation.
Definition: dns_resolver.h:32
const char * name
The name of the resolver implementation.
Definition: dns_resolver.h:34
Structure for mutex and tracking information.
Definition: lock.h:135
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
ast_test_result_state
Definition: test.h:193
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
static struct ast_dns_resolver recurring_resolver
static int wait_for_resolution(struct ast_test *test, struct recurring_data *rdata, int expected_lapse, int num_resolves, int num_completed, int canceled)
Wait for a successful resolution to complete.
#define DNS_ANSWER_SIZE
static int stub_cancel(struct ast_dns_query *query)
static void stub_callback(const struct ast_dns_query *query)
AST_TEST_DEFINE(recurring_query)
static void * resolution_thread(void *dns_query)
Thread that performs asynchronous resolution.
static void recurring_data_destructor(void *obj)
static struct recurring_data * recurring_data_alloc(void)
static int recurring_cancel(struct ast_dns_query *query)
Resolver's cancel() method.
static int load_module(void)
static int unload_module(void)
static int recurring_resolve(struct ast_dns_query *query)
Resolver's resolve() method.
static void async_callback(const struct ast_dns_query *query)
static int fail_resolve(struct ast_dns_query *query)
#define DNS_ANSWER
struct timespec ast_tsnow(void)
Returns current timespec. Meant to avoid calling ast_tvnow() just to create a timespec from the timev...
Definition: time.h:186
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:588
#define ARRAY_LEN(a)
Definition: utils.h:666