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