26 #include <arpa/nameser.h>
27 #include <arpa/inet.h>
57 static void recurring_data_destructor(
void *obj)
61 ast_mutex_destroy(&rdata->lock);
62 ast_cond_destroy(&rdata->cond);
69 rdata = ao2_alloc(
sizeof(*rdata), recurring_data_destructor);
74 ast_mutex_init(&rdata->lock);
75 ast_cond_init(&rdata->cond, NULL);
80 #define DNS_ANSWER "Yes sirree"
81 #define DNS_ANSWER_SIZE strlen(DNS_ANSWER)
93 static void *resolution_thread(
void *dns_query)
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];
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];
108 ast_assert(rdata != NULL);
114 ast_mutex_lock(&rdata->lock);
116 ast_cond_signal(&rdata->cond);
119 ast_cond_wait(&rdata->cond, &rdata->lock);
121 ast_mutex_unlock(&rdata->lock);
134 inet_pton(AF_INET, ADDR1, addr1_buf);
137 inet_pton(AF_INET, ADDR2, addr2_buf);
159 pthread_t resolver_thread;
161 ast_assert(rdata != NULL);
163 return ast_pthread_create_detached(&resolver_thread, NULL, resolution_thread,
ao2_bump(query));
177 ast_mutex_lock(&rdata->lock);
179 ast_cond_signal(&rdata->cond);
180 ast_mutex_unlock(&rdata->lock);
186 .
name =
"test_recurring",
188 .resolve = recurring_resolve,
189 .cancel = recurring_cancel,
206 int expected_lapse,
int num_resolves,
int num_completed,
int canceled)
208 struct timespec begin;
210 struct timespec timeout;
215 timeout.tv_sec = begin.tv_sec + 20;
216 timeout.tv_nsec = begin.tv_nsec;
218 ast_mutex_lock(&rdata->lock);
220 if (ast_cond_timedwait(&rdata->cond, &rdata->lock, &timeout) == ETIMEDOUT) {
224 ast_mutex_unlock(&rdata->lock);
227 ast_test_status_update(test,
"Query timed out\n");
234 secdiff = end.tv_sec - begin.tv_sec;
237 if (secdiff < expected_lapse - 2 || secdiff > expected_lapse + 2) {
238 ast_test_status_update(test,
"Query did not complete in expected time\n");
243 ast_test_status_update(test,
"Query has not undergone expected number of resolutions\n");
248 ast_test_status_update(test,
"Query was canceled unexpectedly\n");
252 ast_test_status_update(test,
"Query completed in expected time frame\n");
257 static void async_callback(
const struct ast_dns_query *query)
261 ast_assert(rdata != NULL);
263 ast_mutex_lock(&rdata->lock);
265 ast_cond_signal(&rdata->cond);
266 ast_mutex_unlock(&rdata->lock);
274 enum ast_test_result_state res = AST_TEST_PASS;
279 info->name =
"recurring_query";
280 info->category =
"/main/dns/recurring/";
281 info->summary =
"Test nominal asynchronous recurring DNS queries";
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;
296 ast_test_status_update(test,
"Failed to register recurring DNS resolver\n");
297 return AST_TEST_FAIL;
300 rdata = recurring_data_alloc();
302 ast_test_status_update(test,
"Failed to allocate data necessary for recurring test\n");
312 if (!recurring_query) {
313 ast_test_status_update(test,
"Failed to create recurring DNS query\n");
319 if (wait_for_resolution(test, rdata, expected_lapse, 1, 1, 0)) {
324 expected_lapse = rdata->
ttl1;
329 if (wait_for_resolution(test, rdata, expected_lapse, 2, 2, 0)) {
334 expected_lapse = rdata->
ttl2;
337 if (wait_for_resolution(test, rdata, expected_lapse, 3, 3, 0)) {
343 if (recurring_query) {
371 .
name =
"Harold P. Warren's Filmography",
373 .resolve = fail_resolve,
374 .cancel = stub_cancel,
379 struct dns_resolve_data {
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 },
393 enum ast_test_result_state res = AST_TEST_PASS;
397 info->name =
"recurring_query_off_nominal";
398 info->category =
"/main/dns/recurring/";
399 info->summary =
"Test off-nominal recurring DNS resolution";
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;
413 ast_test_status_update(test,
"Failed to register test resolver\n");
414 return AST_TEST_FAIL;
417 for (i = 0; i < ARRAY_LEN(resolves); ++i) {
419 resolves[i].callback, NULL);
421 ast_test_status_update(test,
"Successfully performed recurring resolution with invalid data\n");
431 ast_test_status_update(test,
"Failed to register the DNS resolver\n");
432 return AST_TEST_FAIL;
440 ast_test_status_update(test,
"Successfully performed recurring resolution with invalid data\n");
443 return AST_TEST_FAIL;
454 enum ast_test_result_state res = AST_TEST_PASS;
455 struct timespec timeout;
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;
472 ast_test_status_update(test,
"Failed to register recurring DNS resolver\n");
473 return AST_TEST_FAIL;
476 rdata = recurring_data_alloc();
478 ast_test_status_update(test,
"Failed to allocate data necessary for recurring test\n");
487 if (!recurring_query) {
488 ast_test_status_update(test,
"Unable to make recurring query\n");
493 if (wait_for_resolution(test, rdata, 0, 1, 1, 0)) {
499 ast_test_status_update(test,
"Failed to cancel recurring query\n");
508 timeout.tv_sec += 10;
510 ast_mutex_lock(&rdata->lock);
512 if (ast_cond_timedwait(&rdata->cond, &rdata->lock, &timeout) == ETIMEDOUT) {
516 ast_mutex_unlock(&rdata->lock);
519 ast_test_status_update(test,
"Recurring query occurred after cancellation\n");
535 enum ast_test_result_state res = AST_TEST_PASS;
536 struct timespec timeout;
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;
555 ast_test_status_update(test,
"Failed to register recurring DNS resolver\n");
556 return AST_TEST_FAIL;
559 rdata = recurring_data_alloc();
561 ast_test_status_update(test,
"Failed to allocate data necessary for recurring test\n");
570 if (!recurring_query) {
571 ast_test_status_update(test,
"Failed to make recurring DNS query\n");
576 if (wait_for_resolution(test, rdata, 0, 1, 1, 0)) {
585 ast_mutex_lock(&rdata->lock);
587 ast_cond_wait(&rdata->cond, &rdata->lock);
590 ast_mutex_unlock(&rdata->lock);
593 ast_test_status_update(test,
"Failed to cancel recurring DNS query\n");
599 if (wait_for_resolution(test, rdata, 0, 2, 1, 1)) {
606 timeout.tv_sec += 10;
608 ast_mutex_lock(&rdata->lock);
610 if (ast_cond_timedwait(&rdata->cond, &rdata->lock, &timeout) == ETIMEDOUT) {
614 ast_mutex_unlock(&rdata->lock);
617 ast_test_status_update(test,
"Recurring query occurred after cancellation\n");
627 static int unload_module(
void)
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);
637 static int load_module(
void)
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);
Asterisk main include file. File version handling, generic pbx functions.
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.
void ast_dns_resolver_unregister(struct ast_dns_resolver *resolver)
Unregister a DNS resolver.
void(* ast_dns_resolve_callback)(const struct ast_dns_query *query)
Callback invoked when a query completes.
const char * name
The name of the resolver implementation.
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...
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
int ast_dns_resolve_recurring_cancel(struct ast_dns_query_recurring *recurring)
Cancel an asynchronous recurring DNS resolution.
void * user_data
User-specific data.
static void cleanup(void)
Clean up any old apps that we don't need any more.
void * ast_dns_query_get_data(const struct ast_dns_query *query)
Get the user specific data of a DNS query.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
int ast_dns_resolver_register(struct ast_dns_resolver *resolver)
Register a DNS resolver.
void ast_dns_resolver_completed(struct ast_dns_query *query)
Mark a DNS query as having been completed.
DNS resolver implementation.
Internal DNS structure definitions.
struct timespec ast_tsnow(void)
Returns current timespec. Meant to avoid calling ast_tvnow() just to create a timespec from the timev...
#define AST_TEST_DEFINE(hdr)
#define ASTERISK_GPL_KEY
The text the key() function should return.
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.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Structure for mutex and tracking information.
DNS Recurring Resolution API.