Asterisk - The Open Source Telephony Project GIT-master-d856a3e
test_dns.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"
34
35/* Used when a stub is needed for certain tests */
36static int stub_resolve(struct ast_dns_query *query)
37{
38 return 0;
39}
40
41/* Used when a stub is needed for certain tests */
42static int stub_cancel(struct ast_dns_query *query)
43{
44 return 0;
45}
46
47AST_TEST_DEFINE(resolver_register_unregister)
48{
49 struct ast_dns_resolver cool_guy_resolver = {
50 .name = "A snake that swallowed a deer",
51 .priority = 19890504,
52 .resolve = stub_resolve,
53 .cancel = stub_cancel,
54 };
55
56 switch (cmd) {
57 case TEST_INIT:
58 info->name = "resolver_register_unregister";
59 info->category = "/main/dns/";
60 info->summary = "Test nominal resolver registration and unregistration";
61 info->description =
62 "The test performs the following steps:\n"
63 "\t* Register a valid resolver.\n"
64 "\t* Unregister the resolver.\n"
65 "If either step fails, the test fails";
66 return AST_TEST_NOT_RUN;
67 case TEST_EXECUTE:
68 break;
69 }
70
71 if (ast_dns_resolver_register(&cool_guy_resolver)) {
72 ast_test_status_update(test, "Unable to register a perfectly good resolver\n");
73 return AST_TEST_FAIL;
74 }
75
76 ast_dns_resolver_unregister(&cool_guy_resolver);
77
78 return AST_TEST_PASS;
79}
80
81AST_TEST_DEFINE(resolver_register_off_nominal)
82{
83 struct ast_dns_resolver valid = {
84 .name = "valid",
85 .resolve = stub_resolve,
86 .cancel = stub_cancel,
87 };
88
89 struct ast_dns_resolver incomplete1 = {
90 .name = NULL,
91 .resolve = stub_resolve,
92 .cancel = stub_cancel,
93 };
94
95 struct ast_dns_resolver incomplete2 = {
96 .name = "incomplete2",
97 .resolve = NULL,
98 .cancel = stub_cancel,
99 };
100
101 struct ast_dns_resolver incomplete3 = {
102 .name = "incomplete3",
103 .resolve = stub_resolve,
104 .cancel = NULL,
105 };
106
107 switch (cmd) {
108 case TEST_INIT:
109 info->name = "resolver_register_off_nominal";
110 info->category = "/main/dns/";
111 info->summary = "Test off-nominal resolver registration";
112 info->description =
113 "Test off-nominal resolver registration:\n"
114 "\t* Register a duplicate resolver\n"
115 "\t* Register a resolver without a name\n"
116 "\t* Register a resolver without a resolve() method\n"
117 "\t* Register a resolver without a cancel() method";
118 return AST_TEST_NOT_RUN;
119 case TEST_EXECUTE:
120 break;
121 }
122
123 if (ast_dns_resolver_register(&valid)) {
124 ast_test_status_update(test, "Failed to register valid resolver\n");
125 return AST_TEST_FAIL;
126 }
127
128 if (!ast_dns_resolver_register(&valid)) {
129 ast_test_status_update(test, "Successfully registered the same resolver multiple times\n");
130 return AST_TEST_FAIL;
131 }
132
134
136 ast_test_status_update(test, "Successfully registered a NULL resolver\n");
137 return AST_TEST_FAIL;
138 }
139
140 if (!ast_dns_resolver_register(&incomplete1)) {
141 ast_test_status_update(test, "Successfully registered a DNS resolver with no name\n");
142 return AST_TEST_FAIL;
143 }
144
145 if (!ast_dns_resolver_register(&incomplete2)) {
146 ast_test_status_update(test, "Successfully registered a DNS resolver with no resolve() method\n");
147 return AST_TEST_FAIL;
148 }
149
150 if (!ast_dns_resolver_register(&incomplete3)) {
151 ast_test_status_update(test, "Successfully registered a DNS resolver with no cancel() method\n");
152 return AST_TEST_FAIL;
153 }
154
155 return AST_TEST_PASS;
156}
157
158AST_TEST_DEFINE(resolver_unregister_off_nominal)
159{
160 struct ast_dns_resolver non_existent = {
161 .name = "I do not exist",
162 .priority = 20141004,
163 .resolve = stub_resolve,
164 .cancel = stub_cancel,
165 };
166
167 switch (cmd) {
168 case TEST_INIT:
169 info->name = "resolver_unregister_off_nominal";
170 info->category = "/main/dns/";
171 info->summary = "Test off-nominal DNS resolver unregister";
172 info->description =
173 "The test attempts the following:\n"
174 "\t* Unregister a resolver that is not registered.\n"
175 "\t* Unregister a NULL pointer.\n"
176 "Because unregistering a resolver does not return an indicator of success, the best\n"
177 "this test can do is verify that nothing blows up when this is attempted.";
178 return AST_TEST_NOT_RUN;
179 case TEST_EXECUTE:
180 break;
181 }
182
183 ast_dns_resolver_unregister(&non_existent);
185
186 return AST_TEST_PASS;
187}
188
190{
191 struct ast_dns_query some_query;
192
193 struct digits {
194 int fingers;
195 int toes;
196 };
197
198 RAII_VAR(struct digits *, average, NULL, ao2_cleanup);
199 RAII_VAR(struct digits *, polydactyl, NULL, ao2_cleanup);
200
201 struct digits *data_ptr;
202
203 switch (cmd) {
204 case TEST_INIT:
205 info->name = "resolver_data";
206 info->category = "/main/dns/";
207 info->summary = "Test getting and setting data on a DNS resolver";
208 info->description = "This test does the following:\n"
209 "\t* Ensure that requesting resolver data results in a NULL return if no data has been set.\n"
210 "\t* Ensure that setting resolver data does not result in an error.\n"
211 "\t* Ensure that retrieving the set resolver data returns the data we expect\n"
212 "\t* Ensure that setting new resolver data on the query does not result in an error\n"
213 "\t* Ensure that retrieving the resolver data returns the new data that we set";
214 return AST_TEST_NOT_RUN;
215 case TEST_EXECUTE:
216 break;
217 }
218
219 memset(&some_query, 0, sizeof(some_query));
220
221 average = ao2_alloc(sizeof(*average), NULL);
222 polydactyl = ao2_alloc(sizeof(*average), NULL);
223
224 if (!average || !polydactyl) {
225 ast_test_status_update(test, "Allocation failure during unit test\n");
226 return AST_TEST_FAIL;
227 }
228
229 /* Ensure that NULL is retrieved if we haven't set anything on the query */
230 data_ptr = ast_dns_resolver_get_data(&some_query);
231 if (data_ptr) {
232 ast_test_status_update(test, "Retrieved non-NULL resolver data from query unexpectedly\n");
233 return AST_TEST_FAIL;
234 }
235
236 if (ast_dns_resolver_set_data(&some_query, average)) {
237 ast_test_status_update(test, "Failed to set resolver data on query\n");
238 return AST_TEST_FAIL;
239 }
240
241 /* Go ahead now and remove the query's reference to the resolver data to prevent memory leaks */
242 ao2_ref(average, -1);
243
244 /* Ensure that data can be set and retrieved */
245 data_ptr = ast_dns_resolver_get_data(&some_query);
246 if (!data_ptr) {
247 ast_test_status_update(test, "Unable to retrieve resolver data from DNS query\n");
248 return AST_TEST_FAIL;
249 }
250
251 if (data_ptr != average) {
252 ast_test_status_update(test, "Unexpected resolver data retrieved from DNS query\n");
253 return AST_TEST_FAIL;
254 }
255
256 /* Ensure that attempting to set new resolver data on the query fails */
257 if (!ast_dns_resolver_set_data(&some_query, polydactyl)) {
258 ast_test_status_update(test, "Successfully overwrote resolver data on a query. We shouldn't be able to do that\n");
259 return AST_TEST_FAIL;
260 }
261
262 return AST_TEST_PASS;
263}
264
265static int test_results(struct ast_test *test, const struct ast_dns_query *query,
266 unsigned int expected_secure, unsigned int expected_bogus,
267 unsigned int expected_rcode, const char *expected_canonical,
268 const char *expected_answer, size_t answer_size)
269{
270 struct ast_dns_result *result;
271
273 if (!result) {
274 ast_test_status_update(test, "Unable to retrieve result from query\n");
275 return -1;
276 }
277
278 if (ast_dns_result_get_secure(result) != expected_secure ||
279 ast_dns_result_get_bogus(result) != expected_bogus ||
280 ast_dns_result_get_rcode(result) != expected_rcode ||
281 strcmp(ast_dns_result_get_canonical(result), expected_canonical) ||
282 memcmp(ast_dns_result_get_answer(result), expected_answer, answer_size)) {
283 ast_test_status_update(test, "Unexpected values in result from query\n");
284 return -1;
285 }
286
287 return 0;
288}
289
290/* When setting a DNS result, we have to provide the raw DNS answer. This
291 * is not happening. Sorry. Instead, we provide a dummy string and call it
292 * a day
293 */
294#define DNS_ANSWER "Grumble Grumble"
295#define DNS_ANSWER_SIZE strlen(DNS_ANSWER)
296
297AST_TEST_DEFINE(resolver_set_result)
298{
299 struct ast_dns_query some_query;
300 struct ast_dns_result *result;
301
302 struct dns_result {
303 unsigned int secure;
304 unsigned int bogus;
305 unsigned int rcode;
306 } results[] = {
307 { 0, 0, NOERROR, },
308 { 0, 1, NOERROR, },
309 { 1, 0, NOERROR, },
310 { 0, 0, NXDOMAIN, },
311 };
312 int i;
314
315 switch (cmd) {
316 case TEST_INIT:
317 info->name = "resolver_set_result";
318 info->category = "/main/dns/";
319 info->summary = "Test setting and getting results on DNS queries";
320 info->description =
321 "This test performs the following:\n"
322 "\t* Sets a result that is not secure, bogus, and has rcode 0\n"
323 "\t* Sets a result that is not secure, has rcode 0, but is secure\n"
324 "\t* Sets a result that is not bogus, has rcode 0, but is secure\n"
325 "\t* Sets a result that is not secure or bogus, but has rcode NXDOMAIN\n"
326 "After each result is set, we ensure that parameters retrieved from\n"
327 "the result have the expected values.";
328 return AST_TEST_NOT_RUN;
329 case TEST_EXECUTE:
330 break;
331 }
332
333 memset(&some_query, 0, sizeof(some_query));
334
335 for (i = 0; i < ARRAY_LEN(results); ++i) {
336 if (ast_dns_resolver_set_result(&some_query, results[i].secure, results[i].bogus,
337 results[i].rcode, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) {
338 ast_test_status_update(test, "Unable to add DNS result to query\n");
339 res = AST_TEST_FAIL;
340 }
341
342 if (test_results(test, &some_query, results[i].secure, results[i].bogus,
343 results[i].rcode, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) {
344 res = AST_TEST_FAIL;
345 }
346 }
347
348 /* The final result we set needs to be freed */
349 result = ast_dns_query_get_result(&some_query);
351
352 return res;
353}
354
355AST_TEST_DEFINE(resolver_set_result_off_nominal)
356{
357 struct ast_dns_query some_query;
358 struct ast_dns_result *result;
359
360 switch (cmd) {
361 case TEST_INIT:
362 info->name = "resolver_set_result_off_nominal";
363 info->category = "/main/dns/";
364 info->summary = "Test setting off-nominal DNS results";
365 info->description =
366 "This test performs the following:\n"
367 "\t* Attempt to add a DNS result that is both bogus and secure\n"
368 "\t* Attempt to add a DNS result that has no canonical name";
369 return AST_TEST_NOT_RUN;
370 case TEST_EXECUTE:
371 break;
372 }
373
374 memset(&some_query, 0, sizeof(some_query));
375
376 if (!ast_dns_resolver_set_result(&some_query, 1, 1, NOERROR, "asterisk.org",
378 ast_test_status_update(test, "Successfully added a result that was both secure and bogus\n");
379 result = ast_dns_query_get_result(&some_query);
381 return AST_TEST_FAIL;
382 }
383
384 if (!ast_dns_resolver_set_result(&some_query, 0, 0, NOERROR, NULL,
386 ast_test_status_update(test, "Successfully added result with no canonical name\n");
387 result = ast_dns_query_get_result(&some_query);
389 return AST_TEST_FAIL;
390 }
391
392 return AST_TEST_PASS;
393}
394
395static int test_record(struct ast_test *test, const struct ast_dns_record *record,
396 int rr_type, int rr_class, int ttl, const char *data, const size_t size)
397{
398 if (ast_dns_record_get_rr_type(record) != rr_type) {
399 ast_test_status_update(test, "Unexpected rr_type from DNS record\n");
400 return -1;
401 }
402
403 if (ast_dns_record_get_rr_class(record) != rr_class) {
404 ast_test_status_update(test, "Unexpected rr_class from DNS record\n");
405 return -1;
406 }
407
408 if (ast_dns_record_get_ttl(record) != ttl) {
409 ast_test_status_update(test, "Unexpected ttl from DNS record\n");
410 return -1;
411 }
412
413 if (memcmp(ast_dns_record_get_data(record), data, size)) {
414 ast_test_status_update(test, "Unexpected data in DNS record\n");
415 return -1;
416 }
417
418 return 0;
419}
420
421AST_TEST_DEFINE(resolver_add_record)
422{
424 struct ast_dns_query some_query;
425 const struct ast_dns_record *record;
426
427 static const char *V4 = "127.0.0.1";
428 static const size_t V4_BUFSIZE = sizeof(struct in_addr);
429 char v4_buf[V4_BUFSIZE];
430
431 static const char *V6 = "::1";
432 static const size_t V6_BUFSIZE = sizeof(struct in6_addr);
433 char v6_buf[V6_BUFSIZE];
434
435 struct dns_record_details {
436 int type;
437 int class;
438 int ttl;
439 const char *data;
440 const size_t size;
441 int visited;
442 } records[] = {
443 { T_A, C_IN, 12345, v4_buf, V4_BUFSIZE, 0, },
444 { T_AAAA, C_IN, 12345, v6_buf, V6_BUFSIZE, 0, },
445 };
446
447 int num_records_visited = 0;
448
449 switch (cmd) {
450 case TEST_INIT:
451 info->name = "resolver_add_record";
452 info->category = "/main/dns/";
453 info->summary = "Test adding DNS records to a query";
454 info->description =
455 "This test performs the following:\n"
456 "\t* Ensure a nominal A record can be added to a query result\n"
457 "\t* Ensures that the record can be retrieved\n"
458 "\t* Ensure that a second record can be added to the query result\n"
459 "\t* Ensures that both records can be retrieved";
460 return AST_TEST_NOT_RUN;
461 case TEST_EXECUTE:
462 break;
463 }
464
465 memset(&some_query, 0, sizeof(some_query));
466
467 if (ast_dns_resolver_set_result(&some_query, 0, 0, NOERROR, "asterisk.org",
469 ast_test_status_update(test, "Unable to set result for DNS query\n");
470 return AST_TEST_FAIL;
471 }
472
473 result = ast_dns_query_get_result(&some_query);
474 if (!result) {
475 ast_test_status_update(test, "Unable to retrieve result from query\n");
476 return AST_TEST_FAIL;
477 }
478
479 inet_pton(AF_INET, V4, v4_buf);
480
481 /* Nominal Record */
482 if (ast_dns_resolver_add_record(&some_query, records[0].type, records[0].class,
483 records[0].ttl, records[0].data, records[0].size)) {
484 ast_test_status_update(test, "Unable to add nominal record to query result\n");
485 return AST_TEST_FAIL;
486 }
487
488 /* I should only be able to retrieve one record */
490 if (!record) {
491 ast_test_status_update(test, "Unable to retrieve record from result\n");
492 return AST_TEST_FAIL;
493 }
494
495 if (test_record(test, record, records[0].type, records[0].class, records[0].ttl,
496 records[0].data, records[0].size)) {
497 return AST_TEST_FAIL;
498 }
499
500 if (ast_dns_record_get_next(record)) {
501 ast_test_status_update(test, "Multiple records returned when only one was expected\n");
502 return AST_TEST_FAIL;
503 }
504
505 inet_pton(AF_INET6, V6, v6_buf);
506
507 if (ast_dns_resolver_add_record(&some_query, records[1].type, records[1].class,
508 records[1].ttl, records[1].data, records[1].size)) {
509 ast_test_status_update(test, "Unable to add second record to query result\n");
510 return AST_TEST_FAIL;
511 }
512
513 for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) {
514 int res;
515
516 /* The order of returned records is not specified by the API. We use the record type
517 * as the discriminator to determine which record data to expect.
518 */
519 if (ast_dns_record_get_rr_type(record) == records[0].type) {
520 res = test_record(test, record, records[0].type, records[0].class, records[0].ttl, records[0].data, records[0].size);
521 records[0].visited = 1;
522 } else if (ast_dns_record_get_rr_type(record) == records[1].type) {
523 res = test_record(test, record, records[1].type, records[1].class, records[1].ttl, records[1].data, records[1].size);
524 records[1].visited = 1;
525 } else {
526 ast_test_status_update(test, "Unknown record type found in DNS results\n");
527 return AST_TEST_FAIL;
528 }
529
530 if (res) {
531 return AST_TEST_FAIL;
532 }
533
534 ++num_records_visited;
535 }
536
537 if (!records[0].visited || !records[1].visited) {
538 ast_test_status_update(test, "Did not visit all added DNS records\n");
539 return AST_TEST_FAIL;
540 }
541
542 if (num_records_visited != ARRAY_LEN(records)) {
543 ast_test_status_update(test, "Did not visit the expected number of DNS records\n");
544 return AST_TEST_FAIL;
545 }
546
547 return AST_TEST_PASS;
548}
549
550AST_TEST_DEFINE(resolver_add_record_off_nominal)
551{
553 struct ast_dns_query some_query;
554 static const char *V4 = "127.0.0.1";
555 static const size_t V4_BUFSIZE = sizeof(struct in_addr);
556 char v4_buf[V4_BUFSIZE];
557
558 switch (cmd) {
559 case TEST_INIT:
560 info->name = "resolver_add_record_off_nominal";
561 info->category = "/main/dns/";
562 info->summary = "Test adding off-nominal DNS records to a query";
563 info->description =
564 "This test performs the following:\n"
565 "\t* Ensure a nominal A record cannot be added if no result has been set.\n"
566 "\t* Ensure that an A record with invalid RR types cannot be added to a query\n"
567 "\t* Ensure that an A record with invalid RR classes cannot be added to a query\n"
568 "\t* Ensure that an A record with invalid TTL cannot be added to a query\n"
569 "\t* Ensure that an A record with NULL data cannot be added to a query\n"
570 "\t* Ensure that an A record with invalid length cannot be added to a query";
571 return AST_TEST_NOT_RUN;
572 case TEST_EXECUTE:
573 break;
574 }
575
576 memset(&some_query, 0, sizeof(some_query));
577
578 inet_ntop(AF_INET, V4, v4_buf, V4_BUFSIZE);
579
580 /* Add record before setting result */
581 if (!ast_dns_resolver_add_record(&some_query, T_A, C_IN, 12345, v4_buf, V4_BUFSIZE)) {
582 ast_test_status_update(test, "Successfully added DNS record to query before setting a result\n");
583 return AST_TEST_FAIL;
584 }
585
586 if (ast_dns_resolver_set_result(&some_query, 0, 0, NOERROR, "asterisk.org",
588 ast_test_status_update(test, "Unable to set result for DNS query\n");
589 return AST_TEST_FAIL;
590 }
591
592 /* We get the result so it will be cleaned up when the function exits */
593 result = ast_dns_query_get_result(&some_query);
594
595 /* Invalid RR types */
596 if (!ast_dns_resolver_add_record(&some_query, -1, C_IN, 12345, v4_buf, V4_BUFSIZE)) {
597 ast_test_status_update(test, "Successfully added DNS record with negative RR type\n");
598 return AST_TEST_FAIL;
599 }
600
601 if (!ast_dns_resolver_add_record(&some_query, 65536 + 1, C_IN, 12345, v4_buf, V4_BUFSIZE)) {
602 ast_test_status_update(test, "Successfully added DNS record with too large RR type\n");
603 return AST_TEST_FAIL;
604 }
605
606 /* Invalid RR classes */
607 if (!ast_dns_resolver_add_record(&some_query, T_A, -1, 12345, v4_buf, V4_BUFSIZE)) {
608 ast_test_status_update(test, "Successfully added DNS record with negative RR class\n");
609 return AST_TEST_FAIL;
610 }
611
612 if (!ast_dns_resolver_add_record(&some_query, T_A, 65536 + 1, 12345, v4_buf, V4_BUFSIZE)) {
613 ast_test_status_update(test, "Successfully added DNS record with too large RR class\n");
614 return AST_TEST_FAIL;
615 }
616
617 /* Invalid TTL */
618 if (!ast_dns_resolver_add_record(&some_query, T_A, C_IN, -1, v4_buf, V4_BUFSIZE)) {
619 ast_test_status_update(test, "Successfully added DNS record with negative TTL\n");
620 return AST_TEST_FAIL;
621 }
622
623 /* No data */
624 if (!ast_dns_resolver_add_record(&some_query, T_A, C_IN, 12345, NULL, 0)) {
625 ast_test_status_update(test, "Successfully added a DNS record with no data\n");
626 return AST_TEST_FAIL;
627 }
628
629 /* Lie about the length */
630 if (!ast_dns_resolver_add_record(&some_query, T_A, C_IN, 12345, v4_buf, 0)) {
631 ast_test_status_update(test, "Successfully added a DNS record with length zero\n");
632 return AST_TEST_FAIL;
633 }
634
635 return AST_TEST_PASS;
636}
637
638/*!
639 * \brief File-scoped data used during resolver tests
640 *
641 * This data has to live at file-scope since it needs to be
642 * accessible by multiple threads.
643 */
644static struct resolver_data {
645 /*! True if the resolver's resolve() method has been called */
647 /*! True if the resolver's cancel() method has been called */
649 /*! True if resolution successfully completed. This is mutually exclusive with \ref canceled */
651 /*! Lock used for protecting \ref cancel_cond */
653 /*! Condition variable used to coordinate canceling a query */
656
657/*!
658 * \brief Thread spawned by the mock resolver
659 *
660 * All DNS resolvers are required to be asynchronous. The mock resolver
661 * spawns this thread for every DNS query that is executed.
662 *
663 * This thread waits for 5 seconds and then returns the same A record
664 * every time. The 5 second wait is to allow for the query to be
665 * canceled if desired
666 *
667 * \param dns_query The ast_dns_query that is being resolved
668 * \return NULL
669 */
670static void *resolution_thread(void *dns_query)
671{
672 struct ast_dns_query *query = dns_query;
673 struct timespec timeout;
674
675 static const char *V4 = "127.0.0.1";
676 static const size_t V4_BUFSIZE = sizeof(struct in_addr);
677 char v4_buf[V4_BUFSIZE];
678
679 timeout = ast_tsnow();
680 timeout.tv_sec += 5;
681
685 break;
686 }
687 }
689
692 ao2_ref(query, -1);
693 return NULL;
694 }
695
696 ast_dns_resolver_set_result(query, 0, 0, NOERROR, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE);
697
698 inet_pton(AF_INET, V4, v4_buf);
699 ast_dns_resolver_add_record(query, T_A, C_IN, 12345, v4_buf, V4_BUFSIZE);
700
703
704 ao2_ref(query, -1);
705 return NULL;
706}
707
708/*!
709 * \brief Mock resolver's resolve method
710 *
711 * \param query The query to resolve
712 * \retval 0 Successfully spawned resolution thread
713 * \retval non-zero Failed to spawn the resolution thread
714 */
715static int test_resolve(struct ast_dns_query *query)
716{
717 pthread_t resolver_thread;
718
720 return ast_pthread_create_detached(&resolver_thread, NULL, resolution_thread, ao2_bump(query));
721}
722
723/*!
724 * \brief Mock resolver's cancel method
725 *
726 * This signals the resolution thread not to return any DNS results.
727 *
728 * \param query DNS query to cancel
729 * \return 0
730 */
731static int test_cancel(struct ast_dns_query *query)
732{
737
738 return 0;
739}
740
741/*!
742 * \brief Initialize global mock resolver data.
743 *
744 * This must be called at the beginning of tests that use the mock resolver
745 */
746static void resolver_data_init(void)
747{
751
754}
755
756/*!
757 * \brief Cleanup global mock resolver data
758 *
759 * This must be called at the end of tests that use the mock resolver
760 */
761static void resolver_data_cleanup(void)
762{
765}
766
767/*!
768 * \brief The mock resolver
769 *
770 * The mock resolver does not care about the DNS query that is
771 * actually being made on it. It simply regurgitates the same
772 * DNS record no matter what.
773 */
775 .name = "test",
776 .priority = 0,
777 .resolve = test_resolve,
778 .cancel = test_cancel,
779};
780
781AST_TEST_DEFINE(resolver_resolve_sync)
782{
785
786 switch (cmd) {
787 case TEST_INIT:
788 info->name = "resolver_resolve_sync";
789 info->category = "/main/dns/";
790 info->summary = "Test a nominal synchronous DNS resolution";
791 info->description =
792 "This test performs a synchronous DNS resolution of a domain. The goal of this\n"
793 "test is not to check the records for accuracy. Rather, the goal is to ensure that\n"
794 "the resolver is called into as expected, that the query completes entirely before\n"
795 "returning from the synchronous resolution, that nothing tried to cancel the resolution\n,"
796 "and that some records were returned.";
797 return AST_TEST_NOT_RUN;
798 case TEST_EXECUTE:
799 break;
800 }
801
803 ast_test_status_update(test, "Unable to register test resolver\n");
804 return AST_TEST_FAIL;
805 }
806
808
809 if (ast_dns_resolve("asterisk.org", T_A, C_IN, &result)) {
810 ast_test_status_update(test, "Resolution of address failed\n");
811 res = AST_TEST_FAIL;
812 goto cleanup;
813 }
814
815 if (!result) {
816 ast_test_status_update(test, "DNS resolution returned a NULL result\n");
817 res = AST_TEST_FAIL;
818 goto cleanup;
819 }
820
822 ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
823 res = AST_TEST_FAIL;
824 goto cleanup;
825 }
826
828 ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
829 res = AST_TEST_FAIL;
830 goto cleanup;
831 }
832
834 ast_test_status_update(test, "Synchronous resolution completed early?\n");
835 res = AST_TEST_FAIL;
836 goto cleanup;
837 }
838
840 ast_test_status_update(test, "Synchronous resolution yielded no records.\n");
841 res = AST_TEST_FAIL;
842 goto cleanup;
843 }
844
845cleanup:
848 return res;
849}
850
851/*!
852 * \brief A resolve() method that simply fails
853 *
854 * \param query The DNS query to resolve. This is ignored.
855 * \return -1
856 */
857static int fail_resolve(struct ast_dns_query *query)
858{
859 return -1;
860}
861
862AST_TEST_DEFINE(resolver_resolve_sync_off_nominal)
863{
864 struct ast_dns_resolver terrible_resolver = {
865 .name = "Uwe Boll's Filmography",
866 .priority = 0,
867 .resolve = fail_resolve,
868 .cancel = stub_cancel,
869 };
870
871 struct ast_dns_result *result = NULL;
872
873 struct dns_resolve_data {
874 const char *name;
875 int rr_type;
876 int rr_class;
877 struct ast_dns_result **result;
878 } resolves [] = {
879 { NULL, T_A, C_IN, &result },
880 { "asterisk.org", -1, C_IN, &result },
881 { "asterisk.org", 65536 + 1, C_IN, &result },
882 { "asterisk.org", T_A, -1, &result },
883 { "asterisk.org", T_A, 65536 + 1, &result },
884 { "asterisk.org", T_A, C_IN, NULL },
885 };
886
887 int i;
888
890
891 switch (cmd) {
892 case TEST_INIT:
893 info->name = "resolver_resolve_sync_off_nominal";
894 info->category = "/main/dns/";
895 info->summary = "Test off-nominal synchronous DNS resolution";
896 info->description =
897 "This test performs several off-nominal synchronous DNS resolutions:\n"
898 "\t* Attempt resolution with NULL name\n"
899 "\t* Attempt resolution with invalid RR type\n"
900 "\t* Attempt resolution with invalid RR class\n"
901 "\t* Attempt resolution with NULL result pointer\n"
902 "\t* Attempt resolution with resolver that returns an error";
903 return AST_TEST_NOT_RUN;
904 case TEST_EXECUTE:
905 break;
906 }
907
909 ast_test_status_update(test, "Failed to register test resolver\n");
910 return AST_TEST_FAIL;
911 }
912
913 for (i = 0; i < ARRAY_LEN(resolves); ++i) {
914 if (!ast_dns_resolve(resolves[i].name, resolves[i].rr_type, resolves[i].rr_class, resolves[i].result)) {
915 ast_test_status_update(test, "Successfully resolved DNS query with invalid parameters\n");
916 res = AST_TEST_FAIL;
917 } else if (result) {
918 ast_test_status_update(test, "Failed resolution set a non-NULL result\n");
920 res = AST_TEST_FAIL;
921 }
922 }
923
925
926 /* As a final test, try a legitimate query with a bad resolver */
927 if (ast_dns_resolver_register(&terrible_resolver)) {
928 ast_test_status_update(test, "Failed to register the terrible resolver\n");
929 return AST_TEST_FAIL;
930 }
931
932 if (!ast_dns_resolve("asterisk.org", T_A, C_IN, &result)) {
933 ast_test_status_update(test, "DNS resolution succeeded when we expected it not to\n");
934 ast_dns_resolver_unregister(&terrible_resolver);
935 return AST_TEST_FAIL;
936 }
937
938 ast_dns_resolver_unregister(&terrible_resolver);
939
940 if (result) {
941 ast_test_status_update(test, "Failed DNS resolution set the result to something non-NULL\n");
943 return AST_TEST_FAIL;
944 }
945
946 return res;
947}
948
949/*!
950 * \brief Data used by async result callback
951 *
952 * This is the typical combination of boolean, lock, and condition
953 * used to synchronize the activities of two threads. In this case,
954 * the testing thread waits on the condition, and the async callback
955 * signals the condition when the asynchronous callback is complete.
956 */
961};
962
963/*!
964 * \brief Destructor for async_resolution_data
965 */
966static void async_data_destructor(void *obj)
967{
968 struct async_resolution_data *async_data = obj;
969
970 ast_mutex_destroy(&async_data->lock);
971 ast_cond_destroy(&async_data->cond);
972}
973
974/*!
975 * \brief Allocation/initialization for async_resolution_data
976 *
977 * The DNS core mandates that a query's user data has to be ao2 allocated,
978 * so this is a helper method for doing that.
979 *
980 * \retval NULL Failed allocation
981 * \retval non-NULL Newly allocated async_resolution_data
982 */
984{
985 struct async_resolution_data *async_data;
986
987 async_data = ao2_alloc(sizeof(*async_data), async_data_destructor);
988 if (!async_data) {
989 return NULL;
990 }
991
992 async_data->complete = 0;
993 ast_mutex_init(&async_data->lock);
994 ast_cond_init(&async_data->cond, NULL);
995
996 return async_data;
997}
998
999/*!
1000 * \brief Async DNS callback
1001 *
1002 * This is called when an async query completes, either because it resolved or
1003 * because it was canceled. In our case, this callback is used to signal to the
1004 * test that it can continue
1005 *
1006 * \param query The DNS query that has completed
1007 */
1008static void async_callback(const struct ast_dns_query *query)
1009{
1010 struct async_resolution_data *async_data = ast_dns_query_get_data(query);
1011
1012 ast_mutex_lock(&async_data->lock);
1013 async_data->complete = 1;
1014 ast_cond_signal(&async_data->cond);
1015 ast_mutex_unlock(&async_data->lock);
1016}
1017
1018AST_TEST_DEFINE(resolver_resolve_async)
1019{
1020 RAII_VAR(struct async_resolution_data *, async_data, NULL, ao2_cleanup);
1021 RAII_VAR(struct ast_dns_query_active *, active, NULL, ao2_cleanup);
1022 struct ast_dns_result *result;
1024 struct timespec timeout;
1025
1026 switch (cmd) {
1027 case TEST_INIT:
1028 info->name = "resolver_resolve_async";
1029 info->category = "/main/dns/";
1030 info->summary = "Test a nominal asynchronous DNS resolution";
1031 info->description =
1032 "This test performs an asynchronous DNS resolution of a domain. The goal of this\n"
1033 "test is not to check the records for accuracy. Rather, the goal is to ensure that\n"
1034 "the resolver is called into as expected, that we regain control before the query\n"
1035 "is completed, and to ensure that nothing tried to cancel the resolution.";
1036 return AST_TEST_NOT_RUN;
1037 case TEST_EXECUTE:
1038 break;
1039 }
1040
1042 ast_test_status_update(test, "Unable to register test resolver\n");
1043 return AST_TEST_FAIL;
1044 }
1045
1047
1048 async_data = async_data_alloc();
1049 if (!async_data) {
1050 ast_test_status_update(test, "Failed to allocate asynchronous data\n");
1051 res = AST_TEST_FAIL;
1052 goto cleanup;
1053 }
1054
1055 active = ast_dns_resolve_async("asterisk.org", T_A, C_IN, async_callback, async_data);
1056 if (!active) {
1057 ast_test_status_update(test, "Asynchronous resolution of address failed\n");
1058 res = AST_TEST_FAIL;
1059 goto cleanup;
1060 }
1061
1063 ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
1064 res = AST_TEST_FAIL;
1065 goto cleanup;
1066 }
1067
1069 ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
1070 res = AST_TEST_FAIL;
1071 goto cleanup;
1072 }
1073
1074 timeout = ast_tsnow();
1075 timeout.tv_sec += 10;
1076 ast_mutex_lock(&async_data->lock);
1077 while (!async_data->complete) {
1078 if (ast_cond_timedwait(&async_data->cond, &async_data->lock, &timeout) == ETIMEDOUT) {
1079 break;
1080 }
1081 }
1082 ast_mutex_unlock(&async_data->lock);
1083
1084 if (!async_data->complete) {
1085 ast_test_status_update(test, "Asynchronous resolution timed out\n");
1086 res = AST_TEST_FAIL;
1087 goto cleanup;
1088 }
1089
1091 ast_test_status_update(test, "Asynchronous resolution completed early?\n");
1092 res = AST_TEST_FAIL;
1093 goto cleanup;
1094 }
1095
1096 result = ast_dns_query_get_result(active->query);
1097 if (!result) {
1098 ast_test_status_update(test, "Asynchronous resolution yielded no result\n");
1099 res = AST_TEST_FAIL;
1100 goto cleanup;
1101 }
1102
1104 ast_test_status_update(test, "Asynchronous result had no records\n");
1105 res = AST_TEST_FAIL;
1106 goto cleanup;
1107 }
1108
1109cleanup:
1112 return res;
1113}
1114
1115/*! Stub async resolution callback */
1116static void stub_callback(const struct ast_dns_query *query)
1117{
1118 return;
1119}
1120
1121AST_TEST_DEFINE(resolver_resolve_async_off_nominal)
1122{
1123 struct ast_dns_resolver terrible_resolver = {
1124 .name = "Ed Wood's Filmography",
1125 .priority = 0,
1126 .resolve = fail_resolve,
1127 .cancel = stub_cancel,
1128 };
1129
1130 struct dns_resolve_data {
1131 const char *name;
1132 int rr_type;
1133 int rr_class;
1134 ast_dns_resolve_callback callback;
1135 } resolves [] = {
1136 { NULL, T_A, C_IN, stub_callback },
1137 { "asterisk.org", -1, C_IN, stub_callback },
1138 { "asterisk.org", 65536 + 1, C_IN, stub_callback },
1139 { "asterisk.org", T_A, -1, stub_callback },
1140 { "asterisk.org", T_A, 65536 + 1, stub_callback },
1141 { "asterisk.org", T_A, C_IN, NULL },
1142 };
1143
1144 struct ast_dns_query_active *active;
1146 int i;
1147
1148 switch (cmd) {
1149 case TEST_INIT:
1150 info->name = "resolver_resolve_async_off_nominal";
1151 info->category = "/main/dns/";
1152 info->summary = "Test off-nominal asynchronous DNS resolution";
1153 info->description =
1154 "This test performs several off-nominal asynchronous DNS resolutions:\n"
1155 "\t* Attempt resolution with NULL name\n"
1156 "\t* Attempt resolution with invalid RR type\n"
1157 "\t* Attempt resolution with invalid RR class\n"
1158 "\t* Attempt resolution with NULL callback pointer\n"
1159 "\t* Attempt resolution with resolver that returns an error";
1160 return AST_TEST_NOT_RUN;
1161 case TEST_EXECUTE:
1162 break;
1163 }
1164
1166 ast_test_status_update(test, "Failed to register test resolver\n");
1167 return AST_TEST_FAIL;
1168 }
1169
1170 for (i = 0; i < ARRAY_LEN(resolves); ++i) {
1171 active = ast_dns_resolve_async(resolves[i].name, resolves[i].rr_type, resolves[i].rr_class,
1172 resolves[i].callback, NULL);
1173 if (active) {
1174 ast_test_status_update(test, "Successfully performed asynchronous resolution with invalid data\n");
1175 ao2_ref(active, -1);
1176 res = AST_TEST_FAIL;
1177 }
1178 }
1179
1181
1182 if (ast_dns_resolver_register(&terrible_resolver)) {
1183 ast_test_status_update(test, "Failed to register the DNS resolver\n");
1184 return AST_TEST_FAIL;
1185 }
1186
1187 active = ast_dns_resolve_async("asterisk.org", T_A, C_IN, stub_callback, NULL);
1188
1189 ast_dns_resolver_unregister(&terrible_resolver);
1190
1191 if (active) {
1192 ast_test_status_update(test, "Successfully performed asynchronous resolution with invalid data\n");
1193 ao2_ref(active, -1);
1194 return AST_TEST_FAIL;
1195 }
1196
1197 return res;
1198}
1199
1200AST_TEST_DEFINE(resolver_resolve_async_cancel)
1201{
1202 RAII_VAR(struct async_resolution_data *, async_data, NULL, ao2_cleanup);
1203 RAII_VAR(struct ast_dns_query_active *, active, NULL, ao2_cleanup);
1204 struct ast_dns_result *result;
1206 struct timespec timeout;
1207
1208 switch (cmd) {
1209 case TEST_INIT:
1210 info->name = "resolver_resolve_async_cancel";
1211 info->category = "/main/dns/";
1212 info->summary = "Test canceling an asynchronous DNS resolution";
1213 info->description =
1214 "This test performs an asynchronous DNS resolution of a domain and then cancels\n"
1215 "the resolution. The goal of this test is to ensure that the cancel() callback of\n"
1216 "the resolver is called and that it properly interrupts the resolution such that no\n"
1217 "records are returned.";
1218 return AST_TEST_NOT_RUN;
1219 case TEST_EXECUTE:
1220 break;
1221 }
1222
1224 ast_test_status_update(test, "Unable to register test resolver\n");
1225 return AST_TEST_FAIL;
1226 }
1227
1229
1230 async_data = async_data_alloc();
1231 if (!async_data) {
1232 ast_test_status_update(test, "Failed to allocate asynchronous data\n");
1233 res = AST_TEST_FAIL;
1234 goto cleanup;
1235 }
1236
1237 active = ast_dns_resolve_async("asterisk.org", T_A, C_IN, async_callback, async_data);
1238 if (!active) {
1239 ast_test_status_update(test, "Asynchronous resolution of address failed\n");
1240 res = AST_TEST_FAIL;
1241 goto cleanup;
1242 }
1243
1245 ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
1246 res = AST_TEST_FAIL;
1247 goto cleanup;
1248 }
1249
1251 ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
1252 res = AST_TEST_FAIL;
1253 goto cleanup;
1254 }
1255
1256 ast_dns_resolve_cancel(active);
1257
1259 ast_test_status_update(test, "Resolver's cancel() method was not called\n");
1260 res = AST_TEST_FAIL;
1261 goto cleanup;
1262 }
1263
1264 timeout = ast_tsnow();
1265 timeout.tv_sec += 10;
1266 ast_mutex_lock(&async_data->lock);
1267 while (!async_data->complete) {
1268 if (ast_cond_timedwait(&async_data->cond, &async_data->lock, &timeout) == ETIMEDOUT) {
1269 break;
1270 }
1271 }
1272 ast_mutex_unlock(&async_data->lock);
1273
1274 if (!async_data->complete) {
1275 ast_test_status_update(test, "Asynchronous resolution timed out\n");
1276 res = AST_TEST_FAIL;
1277 goto cleanup;
1278 }
1279
1281 ast_test_status_update(test, "Resolution completed without cancelation\n");
1282 res = AST_TEST_FAIL;
1283 goto cleanup;
1284 }
1285
1286 result = ast_dns_query_get_result(active->query);
1287 if (result) {
1288 ast_test_status_update(test, "Canceled resolution had a result\n");
1289 res = AST_TEST_FAIL;
1290 goto cleanup;
1291 }
1292
1293cleanup:
1296 return res;
1297}
1298
1299static int unload_module(void)
1300{
1301 AST_TEST_UNREGISTER(resolver_register_unregister);
1302 AST_TEST_UNREGISTER(resolver_register_off_nominal);
1303 AST_TEST_UNREGISTER(resolver_unregister_off_nominal);
1305 AST_TEST_UNREGISTER(resolver_set_result);
1306 AST_TEST_UNREGISTER(resolver_set_result_off_nominal);
1307 AST_TEST_UNREGISTER(resolver_add_record);
1308 AST_TEST_UNREGISTER(resolver_add_record_off_nominal);
1309 AST_TEST_UNREGISTER(resolver_resolve_sync);
1310 AST_TEST_UNREGISTER(resolver_resolve_sync_off_nominal);
1311 AST_TEST_UNREGISTER(resolver_resolve_async);
1312 AST_TEST_UNREGISTER(resolver_resolve_async_off_nominal);
1313 AST_TEST_UNREGISTER(resolver_resolve_async_cancel);
1314
1315 return 0;
1316}
1317
1318static int load_module(void)
1319{
1320 AST_TEST_REGISTER(resolver_register_unregister);
1321 AST_TEST_REGISTER(resolver_register_off_nominal);
1322 AST_TEST_REGISTER(resolver_unregister_off_nominal);
1324 AST_TEST_REGISTER(resolver_set_result);
1325 AST_TEST_REGISTER(resolver_set_result_off_nominal);
1326 AST_TEST_REGISTER(resolver_add_record);
1327 AST_TEST_REGISTER(resolver_add_record_off_nominal);
1328 AST_TEST_REGISTER(resolver_resolve_sync);
1329 AST_TEST_REGISTER(resolver_resolve_sync_off_nominal);
1330 AST_TEST_REGISTER(resolver_resolve_async);
1331 AST_TEST_REGISTER(resolver_resolve_async_off_nominal);
1332 AST_TEST_REGISTER(resolver_resolve_async_cancel);
1333
1335}
1336
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
static int records
Definition: cdr_pgsql.c:78
static PGresult * result
Definition: cel_pgsql.c:84
static const char type[]
Definition: chan_ooh323.c:109
Core DNS API.
int ast_dns_record_get_rr_class(const struct ast_dns_record *record)
Get the resource record class of a DNS record.
Definition: dns_core.c:150
int ast_dns_record_get_ttl(const struct ast_dns_record *record)
Get the TTL of a DNS record.
Definition: dns_core.c:155
const struct ast_dns_record * ast_dns_record_get_next(const struct ast_dns_record *record)
Get the next DNS record.
Definition: dns_core.c:170
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)
Asynchronously resolve a DNS query.
Definition: dns_core.c:247
int ast_dns_resolve_cancel(struct ast_dns_query_active *active)
Cancel an asynchronous DNS resolution.
Definition: dns_core.c:272
const char * ast_dns_result_get_canonical(const struct ast_dns_result *result)
Get the canonical name of the result.
Definition: dns_core.c:97
void(* ast_dns_resolve_callback)(const struct ast_dns_query *query)
Callback invoked when a query completes.
Definition: dns_core.h:171
unsigned int ast_dns_result_get_rcode(const struct ast_dns_result *result)
Get the error rcode of a DN result.
Definition: dns_core.c:92
const char * ast_dns_record_get_data(const struct ast_dns_record *record)
Retrieve the raw DNS record.
Definition: dns_core.c:160
const struct ast_dns_record * ast_dns_result_get_records(const struct ast_dns_result *result)
Get the first record of a DNS Result.
Definition: dns_core.c:102
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
void ast_dns_result_free(struct ast_dns_result *result)
Free the DNS result information.
Definition: dns_core.c:130
struct ast_dns_result * ast_dns_query_get_result(const struct ast_dns_query *query)
Get the result information for a DNS query.
Definition: dns_core.c:77
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
Definition: dns_core.c:145
unsigned int ast_dns_result_get_bogus(const struct ast_dns_result *result)
Get whether the result is bogus or not.
Definition: dns_core.c:87
int ast_dns_resolve(const char *name, int rr_type, int rr_class, struct ast_dns_result **result)
Synchronously resolve a DNS query.
Definition: dns_core.c:314
unsigned int ast_dns_result_get_secure(const struct ast_dns_result *result)
Get whether the result is secure or not.
Definition: dns_core.c:82
const char * ast_dns_result_get_answer(const struct ast_dns_result *result)
Get the raw DNS answer from a DNS result.
Definition: dns_core.c:107
Internal DNS structure definitions.
DNS Resolver API.
int ast_dns_resolver_set_data(struct ast_dns_query *query, void *data)
Set resolver specific data on a query.
Definition: dns_core.c:440
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
void * ast_dns_resolver_get_data(const struct ast_dns_query *query)
Retrieve resolver specific data.
Definition: dns_core.c:451
int ast_dns_resolver_register(struct ast_dns_resolver *resolver)
Register a DNS resolver.
Definition: dns_core.c:632
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:682
static const char name[]
Definition: format_mp3.c:68
#define ast_cond_destroy(cond)
Definition: lock.h:202
#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:581
#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
An active DNS query.
Definition: dns_internal.h:201
A DNS query.
Definition: dns_internal.h:137
For AST_LIST.
Definition: dns_internal.h:39
DNS resolver implementation.
Definition: dns_resolver.h:32
const char * name
The name of the resolver implementation.
Definition: dns_resolver.h:34
The result of a DNS query.
Definition: dns_internal.h:117
size_t answer_size
The size of the raw DNS answer.
Definition: dns_internal.h:131
Structure for mutex and tracking information.
Definition: lock.h:135
Data used by async result callback.
Definition: test_dns.c:957
ast_mutex_t lock
Definition: test_dns.c:959
File-scoped data used during resolver tests.
Definition: test_dns.c:644
int resolution_complete
Definition: test_dns.c:650
int resolve_called
Definition: test_dns.c:646
ast_mutex_t lock
Definition: test_dns.c:652
ast_cond_t cancel_cond
Definition: test_dns.c:654
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 int stub_resolve(struct ast_dns_query *query)
Definition: test_dns.c:36
static struct async_resolution_data * async_data_alloc(void)
Allocation/initialization for async_resolution_data.
Definition: test_dns.c:983
#define DNS_ANSWER_SIZE
Definition: test_dns.c:295
static struct ast_dns_resolver test_resolver
The mock resolver.
Definition: test_dns.c:774
static int stub_cancel(struct ast_dns_query *query)
Definition: test_dns.c:42
static void resolver_data_cleanup(void)
Cleanup global mock resolver data.
Definition: test_dns.c:761
static int test_cancel(struct ast_dns_query *query)
Mock resolver's cancel method.
Definition: test_dns.c:731
static int test_resolve(struct ast_dns_query *query)
Mock resolver's resolve method.
Definition: test_dns.c:715
static struct resolver_data test_resolver_data
static void stub_callback(const struct ast_dns_query *query)
Definition: test_dns.c:1116
static void * resolution_thread(void *dns_query)
Thread spawned by the mock resolver.
Definition: test_dns.c:670
static int test_results(struct ast_test *test, const struct ast_dns_query *query, unsigned int expected_secure, unsigned int expected_bogus, unsigned int expected_rcode, const char *expected_canonical, const char *expected_answer, size_t answer_size)
Definition: test_dns.c:265
static void async_data_destructor(void *obj)
Destructor for async_resolution_data.
Definition: test_dns.c:966
static void resolver_data_init(void)
Initialize global mock resolver data.
Definition: test_dns.c:746
static int load_module(void)
Definition: test_dns.c:1318
static int unload_module(void)
Definition: test_dns.c:1299
static int test_record(struct ast_test *test, const struct ast_dns_record *record, int rr_type, int rr_class, int ttl, const char *data, const size_t size)
Definition: test_dns.c:395
static void async_callback(const struct ast_dns_query *query)
Async DNS callback.
Definition: test_dns.c:1008
AST_TEST_DEFINE(resolver_register_unregister)
Definition: test_dns.c:47
static int fail_resolve(struct ast_dns_query *query)
A resolve() method that simply fails.
Definition: test_dns.c:857
#define DNS_ANSWER
Definition: test_dns.c:294
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_pthread_create_detached(a, b, c, d)
Definition: utils.h:588
#define ARRAY_LEN(a)
Definition: utils.h:666