Asterisk - The Open Source Telephony Project  GIT-master-932eae6
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"
32 #include "asterisk/dns_resolver.h"
33 #include "asterisk/dns_internal.h"
34 
35 /* Used when a stub is needed for certain tests */
36 static int stub_resolve(struct ast_dns_query *query)
37 {
38  return 0;
39 }
40 
41 /* Used when a stub is needed for certain tests */
42 static int stub_cancel(struct ast_dns_query *query)
43 {
44  return 0;
45 }
46 
47 AST_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 
81 AST_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 
158 AST_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 
265 static 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 
272  result = ast_dns_query_get_result(query);
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 
297 AST_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);
350  ast_dns_result_free(result);
351 
352  return res;
353 }
354 
355 AST_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);
380  ast_dns_result_free(result);
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);
388  ast_dns_result_free(result);
389  return AST_TEST_FAIL;
390  }
391 
392  return AST_TEST_PASS;
393 }
394 
395 static 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 
421 AST_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 
550 AST_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  */
644 static 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 */
648  int canceled;
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  */
670 static 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 
683  while (!test_resolver_data.canceled) {
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  */
715 static 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  */
731 static 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  */
746 static 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  */
761 static 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 
781 AST_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 
802  if (ast_dns_resolver_register(&test_resolver)) {
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 
845 cleanup:
846  ast_dns_resolver_unregister(&test_resolver);
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  */
857 static int fail_resolve(struct ast_dns_query *query)
858 {
859  return -1;
860 }
861 
862 AST_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 
908  if (ast_dns_resolver_register(&test_resolver)) {
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");
919  ast_dns_result_free(result);
920  res = AST_TEST_FAIL;
921  }
922  }
923 
924  ast_dns_resolver_unregister(&test_resolver);
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");
942  ast_dns_result_free(result);
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  */
958  int complete;
961 };
962 
963 /*!
964  * \brief Destructor for async_resolution_data
965  */
966 static 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  */
1008 static 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 
1018 AST_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 
1041  if (ast_dns_resolver_register(&test_resolver)) {
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 
1103  if (!ast_dns_result_get_records(result)) {
1104  ast_test_status_update(test, "Asynchronous result had no records\n");
1105  res = AST_TEST_FAIL;
1106  goto cleanup;
1107  }
1108 
1109 cleanup:
1110  ast_dns_resolver_unregister(&test_resolver);
1112  return res;
1113 }
1114 
1115 /*! Stub async resolution callback */
1116 static void stub_callback(const struct ast_dns_query *query)
1117 {
1118  return;
1119 }
1120 
1121 AST_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 
1165  if (ast_dns_resolver_register(&test_resolver)) {
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 
1180  ast_dns_resolver_unregister(&test_resolver);
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 
1200 AST_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 
1223  if (ast_dns_resolver_register(&test_resolver)) {
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 
1293 cleanup:
1294  ast_dns_resolver_unregister(&test_resolver);
1296  return res;
1297 }
1298 
1299 static 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 
1318 static 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 
1334  return AST_MODULE_LOAD_SUCCESS;
1335 }
1336 
static void async_data_destructor(void *obj)
Destructor for async_resolution_data.
Definition: test_dns.c:966
static const char type[]
Definition: chan_ooh323.c:109
int ast_dns_record_get_ttl(const struct ast_dns_record *record)
Get the TTL of a DNS record.
Definition: dns_core.c:155
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
static int records
Definition: cdr_mysql.c:84
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
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
#define DNS_ANSWER
Definition: test_dns.c:294
Data used by async result callback.
Definition: test_dns.c:957
Asterisk main include file. File version handling, generic pbx functions.
const char * ast_dns_record_get_data(const struct ast_dns_record *record)
Retrieve the raw DNS record.
Definition: dns_core.c:160
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
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
void ast_dns_result_free(struct ast_dns_result *result)
Free the DNS result information.
Definition: dns_core.c:130
static void resolver_data_init(void)
Initialize global mock resolver data.
Definition: test_dns.c:746
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
#define DNS_ANSWER_SIZE
Definition: test_dns.c:295
static struct resolver_data test_resolver_data
int resolve_called
Definition: test_dns.c:646
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:503
void ast_dns_resolver_unregister(struct ast_dns_resolver *resolver)
Unregister a DNS resolver.
Definition: dns_core.c:680
void(* ast_dns_resolve_callback)(const struct ast_dns_query *query)
Callback invoked when a query completes.
Definition: dns_core.h:171
For AST_LIST.
Definition: dns_internal.h:39
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
static int test_cancel(struct ast_dns_query *query)
Mock resolver&#39;s cancel method.
Definition: test_dns.c:731
static void stub_callback(const struct ast_dns_query *query)
Definition: test_dns.c:1116
static struct ast_dns_resolver test_resolver
The mock resolver.
Definition: test_dns.c:774
Test Framework API.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
static int unload_module(void)
Definition: test_dns.c:1299
#define ast_cond_init(cond, attr)
Definition: lock.h:199
static int stub_cancel(struct ast_dns_query *query)
Definition: test_dns.c:42
#define ast_mutex_lock(a)
Definition: lock.h:187
static void * resolution_thread(void *dns_query)
Thread spawned by the mock resolver.
Definition: test_dns.c:670
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
#define NULL
Definition: resample.c:96
void * ast_dns_resolver_get_data(const struct ast_dns_query *query)
Retrieve resolver specific data.
Definition: dns_core.c:451
#define ast_cond_signal(cond)
Definition: lock.h:201
int resolution_complete
Definition: test_dns.c:650
const char * name
The name of the resolver implementation.
Definition: dns_resolver.h:34
pthread_cond_t ast_cond_t
Definition: lock.h:176
#define ao2_bump(obj)
Definition: astobj2.h:491
File-scoped data used during resolver tests.
Definition: test_dns.c:644
#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:851
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
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
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 int test_resolve(struct ast_dns_query *query)
Mock resolver&#39;s resolve method.
Definition: test_dns.c:715
int ast_dns_resolver_register(struct ast_dns_resolver *resolver)
Register a DNS resolver.
Definition: dns_core.c:630
ast_cond_t cancel_cond
Definition: test_dns.c:654
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static void async_callback(const struct ast_dns_query *query)
Async DNS callback.
Definition: test_dns.c:1008
static struct async_resolution_data * async_data_alloc(void)
Allocation/initialization for async_resolution_data.
Definition: test_dns.c:983
The result of a DNS query.
Definition: dns_internal.h:117
void ast_dns_resolver_completed(struct ast_dns_query *query)
Mark a DNS query as having been completed.
Definition: dns_core.c:599
AST_TEST_DEFINE(resolver_register_unregister)
Definition: test_dns.c:47
An active DNS query.
Definition: dns_internal.h:201
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
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_resolver_set_data(struct ast_dns_query *query, void *data)
Set resolver specific data on a query.
Definition: dns_core.c:440
def info(msg)
#define ast_cond_destroy(cond)
Definition: lock.h:200
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
DNS resolver implementation.
Definition: dns_resolver.h:32
Internal DNS structure definitions.
ast_mutex_t lock
Definition: test_dns.c:959
static const char name[]
Definition: cdr_mysql.c:74
A DNS query.
Definition: dns_internal.h:137
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
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_dns_resolve_cancel(struct ast_dns_query_active *active)
Cancel an asynchronous DNS resolution.
Definition: dns_core.c:272
ast_mutex_t lock
Definition: test_dns.c:652
static PGresult * result
Definition: cel_pgsql.c:88
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:177
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
#define ast_mutex_init(pmutex)
Definition: lock.h:184
#define ast_mutex_destroy(a)
Definition: lock.h:186
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
static void resolver_data_cleanup(void)
Cleanup global mock resolver data.
Definition: test_dns.c:761
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
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
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
Asterisk module definitions.
static int fail_resolve(struct ast_dns_query *query)
A resolve() method that simply fails.
Definition: test_dns.c:857
DNS Resolver API.
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
static int stub_resolve(struct ast_dns_query *query)
Definition: test_dns.c:36
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 int load_module(void)
Definition: test_dns.c:1318
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
Structure for mutex and tracking information.
Definition: lock.h:135
Core DNS API.
ast_test_result_state
Definition: test.h:200
#define ast_mutex_unlock(a)
Definition: lock.h:188