test_dns.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2015, Mark Michelson
00005  *
00006  * Mark Michelson <mmichelson@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*** MODULEINFO
00020    <depend>TEST_FRAMEWORK</depend>
00021    <support_level>core</support_level>
00022  ***/
00023 
00024 #include "asterisk.h"
00025 
00026 #include <arpa/nameser.h>
00027 #include <arpa/inet.h>
00028 
00029 #include "asterisk/test.h"
00030 #include "asterisk/module.h"
00031 #include "asterisk/dns_core.h"
00032 #include "asterisk/dns_resolver.h"
00033 #include "asterisk/dns_internal.h"
00034 
00035 /* Used when a stub is needed for certain tests */
00036 static int stub_resolve(struct ast_dns_query *query)
00037 {
00038    return 0;
00039 }
00040 
00041 /* Used when a stub is needed for certain tests */
00042 static int stub_cancel(struct ast_dns_query *query)
00043 {
00044    return 0;
00045 }
00046 
00047 AST_TEST_DEFINE(resolver_register_unregister)
00048 {
00049    struct ast_dns_resolver cool_guy_resolver = {
00050       .name = "A snake that swallowed a deer",
00051       .priority = 19890504,
00052       .resolve = stub_resolve,
00053       .cancel = stub_cancel,
00054    };
00055 
00056    switch (cmd) {
00057    case TEST_INIT:
00058       info->name = "resolver_register_unregister";
00059       info->category = "/main/dns/";
00060       info->summary = "Test nominal resolver registration and unregistration";
00061       info->description =
00062          "The test performs the following steps:\n"
00063          "\t* Register a valid resolver.\n"
00064          "\t* Unregister the resolver.\n"
00065          "If either step fails, the test fails\n";
00066       return AST_TEST_NOT_RUN;
00067    case TEST_EXECUTE:
00068       break;
00069    }
00070 
00071    if (ast_dns_resolver_register(&cool_guy_resolver)) {
00072       ast_test_status_update(test, "Unable to register a perfectly good resolver\n");
00073       return AST_TEST_FAIL;
00074    }
00075 
00076    ast_dns_resolver_unregister(&cool_guy_resolver);
00077 
00078    return AST_TEST_PASS;
00079 }
00080 
00081 AST_TEST_DEFINE(resolver_register_off_nominal)
00082 {
00083    struct ast_dns_resolver valid = {
00084       .name = "valid",
00085       .resolve = stub_resolve,
00086       .cancel = stub_cancel,
00087    };
00088 
00089    struct ast_dns_resolver incomplete1 = {
00090       .name = NULL,
00091       .resolve = stub_resolve,
00092       .cancel = stub_cancel,
00093    };
00094 
00095    struct ast_dns_resolver incomplete2 = {
00096       .name = "incomplete2",
00097       .resolve = NULL,
00098       .cancel = stub_cancel,
00099    };
00100 
00101    struct ast_dns_resolver incomplete3 = {
00102       .name = "incomplete3",
00103       .resolve = stub_resolve,
00104       .cancel = NULL,
00105    };
00106 
00107    switch (cmd) {
00108    case TEST_INIT:
00109       info->name = "resolver_register_off_nominal";
00110       info->category = "/main/dns/";
00111       info->summary = "Test off-nominal resolver registration";
00112       info->description =
00113          "Test off-nominal resolver registration:\n"
00114          "\t* Register a duplicate resolver\n"
00115          "\t* Register a resolver without a name\n"
00116          "\t* Register a resolver without a resolve() method\n"
00117          "\t* Register a resolver without a cancel() method\n";
00118       return AST_TEST_NOT_RUN;
00119    case TEST_EXECUTE:
00120       break;
00121    }
00122 
00123    if (ast_dns_resolver_register(&valid)) {
00124       ast_test_status_update(test, "Failed to register valid resolver\n");
00125       return AST_TEST_FAIL;
00126    }
00127 
00128    if (!ast_dns_resolver_register(&valid)) {
00129       ast_test_status_update(test, "Successfully registered the same resolver multiple times\n");
00130       return AST_TEST_FAIL;
00131    }
00132 
00133    ast_dns_resolver_unregister(&valid);
00134 
00135    if (!ast_dns_resolver_register(NULL)) {
00136       ast_test_status_update(test, "Successfully registered a NULL resolver\n");
00137       return AST_TEST_FAIL;
00138    }
00139 
00140    if (!ast_dns_resolver_register(&incomplete1)) {
00141       ast_test_status_update(test, "Successfully registered a DNS resolver with no name\n");
00142       return AST_TEST_FAIL;
00143    }
00144 
00145    if (!ast_dns_resolver_register(&incomplete2)) {
00146       ast_test_status_update(test, "Successfully registered a DNS resolver with no resolve() method\n");
00147       return AST_TEST_FAIL;
00148    }
00149 
00150    if (!ast_dns_resolver_register(&incomplete3)) {
00151       ast_test_status_update(test, "Successfully registered a DNS resolver with no cancel() method\n");
00152       return AST_TEST_FAIL;
00153    }
00154 
00155    return AST_TEST_PASS;
00156 }
00157 
00158 AST_TEST_DEFINE(resolver_unregister_off_nominal)
00159 {
00160    struct ast_dns_resolver non_existent = {
00161       .name = "I do not exist",
00162       .priority = 20141004,
00163       .resolve = stub_resolve,
00164       .cancel = stub_cancel,
00165    };
00166 
00167    switch (cmd) {
00168    case TEST_INIT:
00169       info->name = "resolver_unregister_off_nominal";
00170       info->category = "/main/dns/";
00171       info->summary = "Test off-nominal DNS resolver unregister";
00172       info->description =
00173          "The test attempts the following:\n"
00174          "\t* Unregister a resolver that is not registered.\n"
00175          "\t* Unregister a NULL pointer.\n"
00176          "Because unregistering a resolver does not return an indicator of success, the best\n"
00177          "this test can do is verify that nothing blows up when this is attempted.\n";
00178       return AST_TEST_NOT_RUN;
00179    case TEST_EXECUTE:
00180       break;
00181    }
00182 
00183    ast_dns_resolver_unregister(&non_existent);
00184    ast_dns_resolver_unregister(NULL);
00185 
00186    return AST_TEST_PASS;
00187 }
00188 
00189 AST_TEST_DEFINE(resolver_data)
00190 {
00191    struct ast_dns_query some_query;
00192 
00193    struct digits {
00194       int fingers;
00195       int toes;
00196    };
00197 
00198    RAII_VAR(struct digits *, average, NULL, ao2_cleanup);
00199    RAII_VAR(struct digits *, polydactyl, NULL, ao2_cleanup);
00200 
00201    struct digits *data_ptr;
00202 
00203    switch (cmd) {
00204    case TEST_INIT:
00205       info->name = "resolver_data";
00206       info->category = "/main/dns/";
00207       info->summary = "Test getting and setting data on a DNS resolver";
00208       info->description = "This test does the following:\n"
00209          "\t* Ensure that requesting resolver data results in a NULL return if no data has been set.\n"
00210          "\t* Ensure that setting resolver data does not result in an error.\n"
00211          "\t* Ensure that retrieving the set resolver data returns the data we expect\n"
00212          "\t* Ensure that setting new resolver data on the query does not result in an error\n"
00213          "\t* Ensure that retrieving the resolver data returns the new data that we set\n";
00214       return AST_TEST_NOT_RUN;
00215    case TEST_EXECUTE:
00216       break;
00217    }
00218 
00219    memset(&some_query, 0, sizeof(some_query));
00220 
00221    average = ao2_alloc(sizeof(*average), NULL);
00222    polydactyl = ao2_alloc(sizeof(*average), NULL);
00223 
00224    if (!average || !polydactyl) {
00225       ast_test_status_update(test, "Allocation failure during unit test\n");
00226       return AST_TEST_FAIL;
00227    }
00228 
00229    /* Ensure that NULL is retrieved if we haven't set anything on the query */
00230    data_ptr = ast_dns_resolver_get_data(&some_query);
00231    if (data_ptr) {
00232       ast_test_status_update(test, "Retrieved non-NULL resolver data from query unexpectedly\n");
00233       return AST_TEST_FAIL;
00234    }
00235 
00236    if (ast_dns_resolver_set_data(&some_query, average)) {
00237       ast_test_status_update(test, "Failed to set resolver data on query\n");
00238       return AST_TEST_FAIL;
00239    }
00240 
00241    /* Go ahead now and remove the query's reference to the resolver data to prevent memory leaks */
00242    ao2_ref(average, -1);
00243 
00244    /* Ensure that data can be set and retrieved */
00245    data_ptr = ast_dns_resolver_get_data(&some_query);
00246    if (!data_ptr) {
00247       ast_test_status_update(test, "Unable to retrieve resolver data from DNS query\n");
00248       return AST_TEST_FAIL;
00249    }
00250 
00251    if (data_ptr != average) {
00252       ast_test_status_update(test, "Unexpected resolver data retrieved from DNS query\n");
00253       return AST_TEST_FAIL;
00254    }
00255 
00256    /* Ensure that attempting to set new resolver data on the query fails */
00257    if (!ast_dns_resolver_set_data(&some_query, polydactyl)) {
00258       ast_test_status_update(test, "Successfully overwrote resolver data on a query. We shouldn't be able to do that\n");
00259       return AST_TEST_FAIL;
00260    }
00261 
00262    return AST_TEST_PASS;
00263 }
00264 
00265 static int test_results(struct ast_test *test, const struct ast_dns_query *query,
00266       unsigned int expected_secure, unsigned int expected_bogus,
00267       unsigned int expected_rcode, const char *expected_canonical,
00268       const char *expected_answer, size_t answer_size)
00269 {
00270    struct ast_dns_result *result;
00271 
00272    result = ast_dns_query_get_result(query);
00273    if (!result) {
00274       ast_test_status_update(test, "Unable to retrieve result from query\n");
00275       return -1;
00276    }
00277 
00278    if (ast_dns_result_get_secure(result) != expected_secure ||
00279          ast_dns_result_get_bogus(result) != expected_bogus ||
00280          ast_dns_result_get_rcode(result) != expected_rcode ||
00281          strcmp(ast_dns_result_get_canonical(result), expected_canonical) ||
00282          memcmp(ast_dns_result_get_answer(result), expected_answer, answer_size)) {
00283       ast_test_status_update(test, "Unexpected values in result from query\n");
00284       return -1;
00285    }
00286 
00287    return 0;
00288 }
00289 
00290 /* When setting a DNS result, we have to provide the raw DNS answer. This
00291  * is not happening. Sorry. Instead, we provide a dummy string and call it
00292  * a day
00293  */
00294 #define DNS_ANSWER "Grumble Grumble"
00295 #define DNS_ANSWER_SIZE strlen(DNS_ANSWER)
00296 
00297 AST_TEST_DEFINE(resolver_set_result)
00298 {
00299    struct ast_dns_query some_query;
00300    struct ast_dns_result *result;
00301 
00302    struct dns_result {
00303       unsigned int secure;
00304       unsigned int bogus;
00305       unsigned int rcode;
00306    } results[] = {
00307       { 0, 0, ns_r_noerror, },
00308       { 0, 1, ns_r_noerror, },
00309       { 1, 0, ns_r_noerror, },
00310       { 0, 0, ns_r_nxdomain, },
00311    };
00312    int i;
00313    enum ast_test_result_state res = AST_TEST_PASS;
00314 
00315    switch (cmd) {
00316    case TEST_INIT:
00317       info->name = "resolver_set_result";
00318       info->category = "/main/dns/";
00319       info->summary = "Test setting and getting results on DNS queries";
00320       info->description =
00321          "This test performs the following:\n"
00322          "\t* Sets a result that is not secure, bogus, and has rcode 0\n"
00323          "\t* Sets a result that is not secure, has rcode 0, but is secure\n"
00324          "\t* Sets a result that is not bogus, has rcode 0, but is secure\n"
00325          "\t* Sets a result that is not secure or bogus, but has rcode NXDOMAIN\n"
00326          "After each result is set, we ensure that parameters retrieved from\n"
00327          "the result have the expected values.";
00328       return AST_TEST_NOT_RUN;
00329    case TEST_EXECUTE:
00330       break;
00331    }
00332 
00333    memset(&some_query, 0, sizeof(some_query));
00334 
00335    for (i = 0; i < ARRAY_LEN(results); ++i) {
00336       if (ast_dns_resolver_set_result(&some_query, results[i].secure, results[i].bogus,
00337             results[i].rcode, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) {
00338          ast_test_status_update(test, "Unable to add DNS result to query\n");
00339          res = AST_TEST_FAIL;
00340       }
00341 
00342       if (test_results(test, &some_query, results[i].secure, results[i].bogus,
00343             results[i].rcode, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE)) {
00344          res = AST_TEST_FAIL;
00345       }
00346    }
00347 
00348    /* The final result we set needs to be freed */
00349    result = ast_dns_query_get_result(&some_query);
00350    ast_dns_result_free(result);
00351 
00352    return res;
00353 }
00354 
00355 AST_TEST_DEFINE(resolver_set_result_off_nominal)
00356 {
00357    struct ast_dns_query some_query;
00358    struct ast_dns_result *result;
00359 
00360    switch (cmd) {
00361    case TEST_INIT:
00362       info->name = "resolver_set_result_off_nominal";
00363       info->category = "/main/dns/";
00364       info->summary = "Test setting off-nominal DNS results\n";
00365       info->description =
00366          "This test performs the following:\n"
00367          "\t* Attempt to add a DNS result that is both bogus and secure\n"
00368          "\t* Attempt to add a DNS result that has no canonical name\n"
00369          "\t* Attempt to add a DNS result that has no answer\n"
00370          "\t* Attempt to add a DNS result with a zero answer size\n";
00371       return AST_TEST_NOT_RUN;
00372    case TEST_EXECUTE:
00373       break;
00374    }
00375 
00376    memset(&some_query, 0, sizeof(some_query));
00377 
00378    if (!ast_dns_resolver_set_result(&some_query, 1, 1, ns_r_noerror, "asterisk.org",
00379             DNS_ANSWER, DNS_ANSWER_SIZE)) {
00380       ast_test_status_update(test, "Successfully added a result that was both secure and bogus\n");
00381       result = ast_dns_query_get_result(&some_query);
00382       ast_dns_result_free(result);
00383       return AST_TEST_FAIL;
00384    }
00385 
00386    if (!ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, NULL,
00387             DNS_ANSWER, DNS_ANSWER_SIZE)) {
00388       ast_test_status_update(test, "Successfully added result with no canonical name\n");
00389       result = ast_dns_query_get_result(&some_query);
00390       ast_dns_result_free(result);
00391       return AST_TEST_FAIL;
00392    }
00393 
00394    if (!ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, NULL,
00395             NULL, DNS_ANSWER_SIZE)) {
00396       ast_test_status_update(test, "Successfully added result with no answer\n");
00397       result = ast_dns_query_get_result(&some_query);
00398       ast_dns_result_free(result);
00399       return AST_TEST_FAIL;
00400    }
00401 
00402    if (!ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, NULL,
00403             DNS_ANSWER, 0)) {
00404       ast_test_status_update(test, "Successfully added result with answer size of zero\n");
00405       result = ast_dns_query_get_result(&some_query);
00406       ast_dns_result_free(result);
00407       return AST_TEST_FAIL;
00408    }
00409 
00410    return AST_TEST_PASS;
00411 }
00412 
00413 static int test_record(struct ast_test *test, const struct ast_dns_record *record,
00414       int rr_type, int rr_class, int ttl, const char *data, const size_t size)
00415 {
00416    if (ast_dns_record_get_rr_type(record) != rr_type) {
00417       ast_test_status_update(test, "Unexpected rr_type from DNS record\n");
00418       return -1;
00419    }
00420 
00421    if (ast_dns_record_get_rr_class(record) != rr_class) {
00422       ast_test_status_update(test, "Unexpected rr_class from DNS record\n");
00423       return -1;
00424    }
00425 
00426    if (ast_dns_record_get_ttl(record) != ttl) {
00427       ast_test_status_update(test, "Unexpected ttl from DNS record\n");
00428       return -1;
00429    }
00430 
00431    if (memcmp(ast_dns_record_get_data(record), data, size)) {
00432       ast_test_status_update(test, "Unexpected data in DNS record\n");
00433       return -1;
00434    }
00435 
00436    return 0;
00437 }
00438 
00439 AST_TEST_DEFINE(resolver_add_record)
00440 {
00441    RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free);
00442    struct ast_dns_query some_query;
00443    const struct ast_dns_record *record;
00444 
00445    static const char *V4 = "127.0.0.1";
00446    static const size_t V4_BUFSIZE = sizeof(struct in_addr);
00447    char v4_buf[V4_BUFSIZE];
00448 
00449    static const char *V6 = "::1";
00450    static const size_t V6_BUFSIZE = sizeof(struct in6_addr);
00451    char v6_buf[V6_BUFSIZE];
00452 
00453    struct dns_record_details {
00454       int type;
00455       int class;
00456       int ttl;
00457       const char *data;
00458       const size_t size;
00459       int visited;
00460    } records[] = {
00461       { ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE, 0, },
00462       { ns_t_aaaa, ns_c_in, 12345, v6_buf, V6_BUFSIZE, 0, },
00463    };
00464 
00465    int num_records_visited = 0;
00466 
00467    switch (cmd) {
00468    case TEST_INIT:
00469       info->name = "resolver_add_record";
00470       info->category = "/main/dns/";
00471       info->summary = "Test adding DNS records to a query";
00472       info->description =
00473          "This test performs the following:\n"
00474          "\t* Ensure a nominal A record can be added to a query result\n"
00475          "\t* Ensures that the record can be retrieved\n"
00476          "\t* Ensure that a second record can be added to the query result\n"
00477          "\t* Ensures that both records can be retrieved\n";
00478       return AST_TEST_NOT_RUN;
00479    case TEST_EXECUTE:
00480       break;
00481    }
00482 
00483    memset(&some_query, 0, sizeof(some_query));
00484 
00485    if (ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, "asterisk.org",
00486             DNS_ANSWER, DNS_ANSWER_SIZE)) {
00487       ast_test_status_update(test, "Unable to set result for DNS query\n");
00488       return AST_TEST_FAIL;
00489    }
00490 
00491    result = ast_dns_query_get_result(&some_query);
00492    if (!result) {
00493       ast_test_status_update(test, "Unable to retrieve result from query\n");
00494       return AST_TEST_FAIL;
00495    }
00496 
00497    inet_pton(AF_INET, V4, v4_buf);
00498 
00499    /* Nominal Record */
00500    if (ast_dns_resolver_add_record(&some_query, records[0].type, records[0].class,
00501             records[0].ttl, records[0].data, records[0].size)) {
00502       ast_test_status_update(test, "Unable to add nominal record to query result\n");
00503       return AST_TEST_FAIL;
00504    }
00505 
00506    /* I should only be able to retrieve one record */
00507    record = ast_dns_result_get_records(result);
00508    if (!record) {
00509       ast_test_status_update(test, "Unable to retrieve record from result\n");
00510       return AST_TEST_FAIL;
00511    }
00512 
00513    if (test_record(test, record, records[0].type, records[0].class, records[0].ttl,
00514             records[0].data, records[0].size)) {
00515       return AST_TEST_FAIL;
00516    }
00517 
00518    if (ast_dns_record_get_next(record)) {
00519       ast_test_status_update(test, "Multiple records returned when only one was expected\n");
00520       return AST_TEST_FAIL;
00521    }
00522 
00523    inet_pton(AF_INET6, V6, v6_buf);
00524 
00525    if (ast_dns_resolver_add_record(&some_query, records[1].type, records[1].class,
00526             records[1].ttl, records[1].data, records[1].size)) {
00527       ast_test_status_update(test, "Unable to add second record to query result\n");
00528       return AST_TEST_FAIL;
00529    }
00530 
00531    for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) {
00532       int res;
00533 
00534       /* The order of returned records is not specified by the API. We use the record type
00535        * as the discriminator to determine which record data to expect.
00536        */
00537       if (ast_dns_record_get_rr_type(record) == records[0].type) {
00538          res = test_record(test, record, records[0].type, records[0].class, records[0].ttl, records[0].data, records[0].size);
00539          records[0].visited = 1;
00540       } else if (ast_dns_record_get_rr_type(record) == records[1].type) {
00541          res = test_record(test, record, records[1].type, records[1].class, records[1].ttl, records[1].data, records[1].size);
00542          records[1].visited = 1;
00543       } else {
00544          ast_test_status_update(test, "Unknown record type found in DNS results\n");
00545          return AST_TEST_FAIL;
00546       }
00547 
00548       if (res) {
00549          return AST_TEST_FAIL;
00550       }
00551 
00552       ++num_records_visited;
00553    }
00554 
00555    if (!records[0].visited || !records[1].visited) {
00556       ast_test_status_update(test, "Did not visit all added DNS records\n");
00557       return AST_TEST_FAIL;
00558    }
00559 
00560    if (num_records_visited != ARRAY_LEN(records)) {
00561       ast_test_status_update(test, "Did not visit the expected number of DNS records\n");
00562       return AST_TEST_FAIL;
00563    }
00564 
00565    return AST_TEST_PASS;
00566 }
00567 
00568 AST_TEST_DEFINE(resolver_add_record_off_nominal)
00569 {
00570    RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free);
00571    struct ast_dns_query some_query;
00572    static const char *V4 = "127.0.0.1";
00573    static const size_t V4_BUFSIZE = sizeof(struct in_addr);
00574    char v4_buf[V4_BUFSIZE];
00575 
00576    switch (cmd) {
00577    case TEST_INIT:
00578       info->name = "resolver_add_record_off_nominal";
00579       info->category = "/main/dns/";
00580       info->summary = "Test adding off-nominal DNS records to a query";
00581       info->description =
00582          "This test performs the following:\n"
00583          "\t* Ensure a nominal A record cannot be added if no result has been set.\n"
00584          "\t* Ensure that an A record with invalid RR types cannot be added to a query\n"
00585          "\t* Ensure that an A record with invalid RR classes cannot be added to a query\n"
00586          "\t* Ensure that an A record with invalid TTL cannot be added to a query\n"
00587          "\t* Ensure that an A record with NULL data cannot be added to a query\n"
00588          "\t* Ensure that an A record with invalid length cannot be added to a query\n";
00589       return AST_TEST_NOT_RUN;
00590    case TEST_EXECUTE:
00591       break;
00592    }
00593 
00594    memset(&some_query, 0, sizeof(some_query));
00595 
00596    inet_ntop(AF_INET, V4, v4_buf, V4_BUFSIZE);
00597 
00598    /* Add record before setting result */
00599    if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) {
00600       ast_test_status_update(test, "Successfully added DNS record to query before setting a result\n");
00601       return AST_TEST_FAIL;
00602    }
00603 
00604    if (ast_dns_resolver_set_result(&some_query, 0, 0, ns_r_noerror, "asterisk.org",
00605             DNS_ANSWER, DNS_ANSWER_SIZE)) {
00606       ast_test_status_update(test, "Unable to set result for DNS query\n");
00607       return AST_TEST_FAIL;
00608    }
00609 
00610    /* We get the result so it will be cleaned up when the function exits */
00611    result = ast_dns_query_get_result(&some_query);
00612 
00613    /* Invalid RR types */
00614    if (!ast_dns_resolver_add_record(&some_query, -1, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) {
00615       ast_test_status_update(test, "Successfully added DNS record with negative RR type\n");
00616       return AST_TEST_FAIL;
00617    }
00618 
00619    if (!ast_dns_resolver_add_record(&some_query, ns_t_max + 1, ns_c_in, 12345, v4_buf, V4_BUFSIZE)) {
00620       ast_test_status_update(test, "Successfully added DNS record with too large RR type\n");
00621       return AST_TEST_FAIL;
00622    }
00623 
00624    /* Invalid RR classes */
00625    if (!ast_dns_resolver_add_record(&some_query, ns_t_a, -1, 12345, v4_buf, V4_BUFSIZE)) {
00626       ast_test_status_update(test, "Successfully added DNS record with negative RR class\n");
00627       return AST_TEST_FAIL;
00628    }
00629 
00630    if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_max + 1, 12345, v4_buf, V4_BUFSIZE)) {
00631       ast_test_status_update(test, "Successfully added DNS record with too large RR class\n");
00632       return AST_TEST_FAIL;
00633    }
00634 
00635    /* Invalid TTL */
00636    if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, -1, v4_buf, V4_BUFSIZE)) {
00637       ast_test_status_update(test, "Successfully added DNS record with negative TTL\n");
00638       return AST_TEST_FAIL;
00639    }
00640 
00641    /* No data */
00642    if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, NULL, 0)) {
00643       ast_test_status_update(test, "Successfully added a DNS record with no data\n");
00644       return AST_TEST_FAIL;
00645    }
00646 
00647    /* Lie about the length */
00648    if (!ast_dns_resolver_add_record(&some_query, ns_t_a, ns_c_in, 12345, v4_buf, 0)) {
00649       ast_test_status_update(test, "Successfully added a DNS record with length zero\n");
00650       return AST_TEST_FAIL;
00651    }
00652 
00653    return AST_TEST_PASS;
00654 }
00655 
00656 /*!
00657  * \brief File-scoped data used during resolver tests
00658  *
00659  * This data has to live at file-scope since it needs to be
00660  * accessible by multiple threads.
00661  */
00662 static struct resolver_data {
00663    /*! True if the resolver's resolve() method has been called */
00664    int resolve_called;
00665    /*! True if the resolver's cancel() method has been called */
00666    int canceled;
00667    /*! True if resolution successfully completed. This is mutually exclusive with \ref canceled */
00668    int resolution_complete;
00669    /*! Lock used for protecting \ref cancel_cond */
00670    ast_mutex_t lock;
00671    /*! Condition variable used to coordinate canceling a query */
00672    ast_cond_t cancel_cond;
00673 } test_resolver_data;
00674 
00675 /*!
00676  * \brief Thread spawned by the mock resolver
00677  *
00678  * All DNS resolvers are required to be asynchronous. The mock resolver
00679  * spawns this thread for every DNS query that is executed.
00680  *
00681  * This thread waits for 5 seconds and then returns the same A record
00682  * every time. The 5 second wait is to allow for the query to be
00683  * canceled if desired
00684  *
00685  * \param dns_query The ast_dns_query that is being resolved
00686  * \return NULL
00687  */
00688 static void *resolution_thread(void *dns_query)
00689 {
00690    struct ast_dns_query *query = dns_query;
00691    struct timespec timeout;
00692 
00693    static const char *V4 = "127.0.0.1";
00694    static const size_t V4_BUFSIZE = sizeof(struct in_addr);
00695    char v4_buf[V4_BUFSIZE];
00696 
00697    clock_gettime(CLOCK_REALTIME, &timeout);
00698    timeout.tv_sec += 5;
00699 
00700    ast_mutex_lock(&test_resolver_data.lock);
00701    while (!test_resolver_data.canceled) {
00702       if (ast_cond_timedwait(&test_resolver_data.cancel_cond, &test_resolver_data.lock, &timeout) == ETIMEDOUT) {
00703          break;
00704       }
00705    }
00706    ast_mutex_unlock(&test_resolver_data.lock);
00707 
00708    if (test_resolver_data.canceled) {
00709       ast_dns_resolver_completed(query);
00710       ao2_ref(query, -1);
00711       return NULL;
00712    }
00713 
00714    ast_dns_resolver_set_result(query, 0, 0, ns_r_noerror, "asterisk.org", DNS_ANSWER, DNS_ANSWER_SIZE);
00715 
00716    inet_pton(AF_INET, V4, v4_buf);
00717    ast_dns_resolver_add_record(query, ns_t_a, ns_c_in, 12345, v4_buf, V4_BUFSIZE);
00718 
00719    test_resolver_data.resolution_complete = 1;
00720    ast_dns_resolver_completed(query);
00721 
00722    ao2_ref(query, -1);
00723    return NULL;
00724 }
00725 
00726 /*!
00727  * \brief Mock resolver's resolve method
00728  *
00729  * \param query The query to resolve
00730  * \retval 0 Successfully spawned resolution thread
00731  * \retval non-zero Failed to spawn the resolution thread
00732  */
00733 static int test_resolve(struct ast_dns_query *query)
00734 {
00735    pthread_t resolver_thread;
00736 
00737    test_resolver_data.resolve_called = 1;
00738    return ast_pthread_create_detached(&resolver_thread, NULL, resolution_thread, ao2_bump(query));
00739 }
00740 
00741 /*!
00742  * \brief Mock resolver's cancel method
00743  *
00744  * This signals the resolution thread not to return any DNS results.
00745  *
00746  * \param query DNS query to cancel
00747  * \return 0
00748  */
00749 static int test_cancel(struct ast_dns_query *query)
00750 {
00751    ast_mutex_lock(&test_resolver_data.lock);
00752    test_resolver_data.canceled = 1;
00753    ast_cond_signal(&test_resolver_data.cancel_cond);
00754    ast_mutex_unlock(&test_resolver_data.lock);
00755 
00756    return 0;
00757 }
00758 
00759 /*!
00760  * \brief Initialize global mock resolver data.
00761  *
00762  * This must be called at the beginning of tests that use the mock resolver
00763  */
00764 static void resolver_data_init(void)
00765 {
00766    test_resolver_data.resolve_called = 0;
00767    test_resolver_data.canceled = 0;
00768    test_resolver_data.resolution_complete = 0;
00769 
00770    ast_mutex_init(&test_resolver_data.lock);
00771    ast_cond_init(&test_resolver_data.cancel_cond, NULL);
00772 }
00773 
00774 /*!
00775  * \brief Cleanup global mock resolver data
00776  *
00777  * This must be called at the end of tests that use the mock resolver
00778  */
00779 static void resolver_data_cleanup(void)
00780 {
00781    ast_mutex_destroy(&test_resolver_data.lock);
00782    ast_cond_destroy(&test_resolver_data.cancel_cond);
00783 }
00784 
00785 /*!
00786  * \brief The mock resolver
00787  *
00788  * The mock resolver does not care about the DNS query that is
00789  * actually being made on it. It simply regurgitates the same
00790  * DNS record no matter what.
00791  */
00792 static struct ast_dns_resolver test_resolver = {
00793    .name = "test",
00794    .priority = 0,
00795    .resolve = test_resolve,
00796    .cancel = test_cancel,
00797 };
00798 
00799 AST_TEST_DEFINE(resolver_resolve_sync)
00800 {
00801    RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free);
00802    enum ast_test_result_state res = AST_TEST_PASS;
00803 
00804    switch (cmd) {
00805    case TEST_INIT:
00806       info->name = "resolver_resolve_sync";
00807       info->category = "/main/dns/";
00808       info->summary = "Test a nominal synchronous DNS resolution";
00809       info->description =
00810          "This test performs a synchronous DNS resolution of a domain. The goal of this\n"
00811          "test is not to check the records for accuracy. Rather, the goal is to ensure that\n"
00812          "the resolver is called into as expected, that the query completes entirely before\n"
00813          "returning from the synchronous resolution, that nothing tried to cancel the resolution\n,"
00814          "and that some records were returned.";
00815       return AST_TEST_NOT_RUN;
00816    case TEST_EXECUTE:
00817       break;
00818    }
00819 
00820    if (ast_dns_resolver_register(&test_resolver)) {
00821       ast_test_status_update(test, "Unable to register test resolver\n");
00822       return AST_TEST_FAIL;
00823    }
00824 
00825    resolver_data_init();
00826 
00827    if (ast_dns_resolve("asterisk.org", ns_t_a, ns_c_in, &result)) {
00828       ast_test_status_update(test, "Resolution of address failed\n");
00829       res = AST_TEST_FAIL;
00830       goto cleanup;
00831    }
00832 
00833    if (!result) {
00834       ast_test_status_update(test, "DNS resolution returned a NULL result\n");
00835       res = AST_TEST_FAIL;
00836       goto cleanup;
00837    }
00838 
00839    if (!test_resolver_data.resolve_called) {
00840       ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
00841       res = AST_TEST_FAIL;
00842       goto cleanup;
00843    }
00844 
00845    if (test_resolver_data.canceled) {
00846       ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
00847       res = AST_TEST_FAIL;
00848       goto cleanup;
00849    }
00850 
00851    if (!test_resolver_data.resolution_complete) {
00852       ast_test_status_update(test, "Synchronous resolution completed early?\n");
00853       res = AST_TEST_FAIL;
00854       goto cleanup;
00855    }
00856 
00857    if (!ast_dns_result_get_records(result)) {
00858       ast_test_status_update(test, "Synchronous resolution yielded no records.\n");
00859       res = AST_TEST_FAIL;
00860       goto cleanup;
00861    }
00862 
00863 cleanup:
00864    ast_dns_resolver_unregister(&test_resolver);
00865    resolver_data_cleanup();
00866    return res;
00867 }
00868 
00869 /*!
00870  * \brief A resolve() method that simply fails
00871  *
00872  * \param query The DNS query to resolve. This is ignored.
00873  * \return -1
00874  */
00875 static int fail_resolve(struct ast_dns_query *query)
00876 {
00877    return -1;
00878 }
00879 
00880 AST_TEST_DEFINE(resolver_resolve_sync_off_nominal)
00881 {
00882    struct ast_dns_resolver terrible_resolver = {
00883       .name = "Uwe Boll's Filmography",
00884       .priority = 0,
00885       .resolve = fail_resolve,
00886       .cancel = stub_cancel,
00887    };
00888 
00889    struct ast_dns_result *result = NULL;
00890 
00891    struct dns_resolve_data {
00892       const char *name;
00893       int rr_type;
00894       int rr_class;
00895       struct ast_dns_result **result;
00896    } resolves [] = {
00897       { NULL,           ns_t_a,       ns_c_in,      &result },
00898       { "asterisk.org", -1,           ns_c_in,      &result },
00899       { "asterisk.org", ns_t_max + 1, ns_c_in,      &result },
00900       { "asterisk.org", ns_t_a,       -1,           &result },
00901       { "asterisk.org", ns_t_a,       ns_c_max + 1, &result },
00902       { "asterisk.org", ns_t_a,       ns_c_in,      NULL },
00903    };
00904 
00905    int i;
00906 
00907    enum ast_test_result_state res = AST_TEST_PASS;
00908 
00909    switch (cmd) {
00910    case TEST_INIT:
00911       info->name = "resolver_resolve_sync_off_nominal";
00912       info->category = "/main/dns/";
00913       info->summary = "Test off-nominal synchronous DNS resolution";
00914       info->description =
00915          "This test performs several off-nominal synchronous DNS resolutions:\n"
00916          "\t* Attempt resolution with NULL name\n",
00917          "\t* Attempt resolution with invalid RR type\n",
00918          "\t* Attempt resolution with invalid RR class\n",
00919          "\t* Attempt resolution with NULL result pointer\n",
00920          "\t* Attempt resolution with resolver that returns an error\n";
00921       return AST_TEST_NOT_RUN;
00922    case TEST_EXECUTE:
00923       break;
00924    }
00925 
00926    if (ast_dns_resolver_register(&test_resolver)) {
00927       ast_test_status_update(test, "Failed to register test resolver\n");
00928       return AST_TEST_FAIL;
00929    }
00930 
00931    for (i = 0; i < ARRAY_LEN(resolves); ++i) {
00932       if (!ast_dns_resolve(resolves[i].name, resolves[i].rr_type, resolves[i].rr_class, resolves[i].result)) {
00933          ast_test_status_update(test, "Successfully resolved DNS query with invalid parameters\n");
00934          res = AST_TEST_FAIL;
00935       } else if (result) {
00936          ast_test_status_update(test, "Failed resolution set a non-NULL result\n");
00937          ast_dns_result_free(result);
00938          res = AST_TEST_FAIL;
00939       }
00940    }
00941 
00942    ast_dns_resolver_unregister(&test_resolver);
00943 
00944    /* As a final test, try a legitimate query with a bad resolver */
00945    if (ast_dns_resolver_register(&terrible_resolver)) {
00946       ast_test_status_update(test, "Failed to register the terrible resolver\n");
00947       return AST_TEST_FAIL;
00948    }
00949 
00950    if (!ast_dns_resolve("asterisk.org", ns_t_a, ns_c_in, &result)) {
00951       ast_test_status_update(test, "DNS resolution succeeded when we expected it not to\n");
00952       ast_dns_resolver_unregister(&terrible_resolver);
00953       return AST_TEST_FAIL;
00954    }
00955 
00956    ast_dns_resolver_unregister(&terrible_resolver);
00957 
00958    if (result) {
00959       ast_test_status_update(test, "Failed DNS resolution set the result to something non-NULL\n");
00960       ast_dns_result_free(result);
00961       return AST_TEST_FAIL;
00962    }
00963 
00964    return res;
00965 }
00966 
00967 /*!
00968  * \brief Data used by async result callback
00969  *
00970  * This is the typical combination of boolean, lock, and condition
00971  * used to synchronize the activities of two threads. In this case,
00972  * the testing thread waits on the condition, and the async callback
00973  * signals the condition when the asynchronous callback is complete.
00974  */
00975 struct async_resolution_data {
00976    int complete;
00977    ast_mutex_t lock;
00978    ast_cond_t cond;
00979 };
00980 
00981 /*!
00982  * \brief Destructor for async_resolution_data
00983  */
00984 static void async_data_destructor(void *obj)
00985 {
00986    struct async_resolution_data *async_data = obj;
00987 
00988    ast_mutex_destroy(&async_data->lock);
00989    ast_cond_destroy(&async_data->cond);
00990 }
00991 
00992 /*!
00993  * \brief Allocation/initialization for async_resolution_data
00994  *
00995  * The DNS core mandates that a query's user data has to be ao2 allocated,
00996  * so this is a helper method for doing that.
00997  *
00998  * \retval NULL Failed allocation
00999  * \retval non-NULL Newly allocated async_resolution_data
01000  */
01001 static struct async_resolution_data *async_data_alloc(void)
01002 {
01003    struct async_resolution_data *async_data;
01004 
01005    async_data = ao2_alloc(sizeof(*async_data), async_data_destructor);
01006    if (!async_data) {
01007       return NULL;
01008    }
01009 
01010    async_data->complete = 0;
01011    ast_mutex_init(&async_data->lock);
01012    ast_cond_init(&async_data->cond, NULL);
01013 
01014    return async_data;
01015 }
01016 
01017 /*!
01018  * \brief Async DNS callback
01019  *
01020  * This is called when an async query completes, either because it resolved or
01021  * because it was canceled. In our case, this callback is used to signal to the
01022  * test that it can continue
01023  *
01024  * \param query The DNS query that has completed
01025  */
01026 static void async_callback(const struct ast_dns_query *query)
01027 {
01028    struct async_resolution_data *async_data = ast_dns_query_get_data(query);
01029 
01030    ast_mutex_lock(&async_data->lock);
01031    async_data->complete = 1;
01032    ast_cond_signal(&async_data->cond);
01033    ast_mutex_unlock(&async_data->lock);
01034 }
01035 
01036 AST_TEST_DEFINE(resolver_resolve_async)
01037 {
01038    RAII_VAR(struct async_resolution_data *, async_data, NULL, ao2_cleanup);
01039    RAII_VAR(struct ast_dns_query_active *, active, NULL, ao2_cleanup);
01040    struct ast_dns_result *result;
01041    enum ast_test_result_state res = AST_TEST_PASS;
01042    struct timespec timeout;
01043 
01044    switch (cmd) {
01045    case TEST_INIT:
01046       info->name = "resolver_resolve_async";
01047       info->category = "/main/dns/";
01048       info->summary = "Test a nominal asynchronous DNS resolution";
01049       info->description =
01050          "This test performs an asynchronous DNS resolution of a domain. The goal of this\n"
01051          "test is not to check the records for accuracy. Rather, the goal is to ensure that\n"
01052          "the resolver is called into as expected, that we regain control before the query\n"
01053          "is completed, and to ensure that nothing tried to cancel the resolution.";
01054       return AST_TEST_NOT_RUN;
01055    case TEST_EXECUTE:
01056       break;
01057    }
01058 
01059    if (ast_dns_resolver_register(&test_resolver)) {
01060       ast_test_status_update(test, "Unable to register test resolver\n");
01061       return AST_TEST_FAIL;
01062    }
01063 
01064    resolver_data_init();
01065 
01066    async_data = async_data_alloc();
01067    if (!async_data) {
01068       ast_test_status_update(test, "Failed to allocate asynchronous data\n");
01069       res = AST_TEST_FAIL;
01070       goto cleanup;
01071    }
01072 
01073    active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, async_callback, async_data);
01074    if (!active) {
01075       ast_test_status_update(test, "Asynchronous resolution of address failed\n");
01076       res = AST_TEST_FAIL;
01077       goto cleanup;
01078    }
01079 
01080    if (!test_resolver_data.resolve_called) {
01081       ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
01082       res = AST_TEST_FAIL;
01083       goto cleanup;
01084    }
01085 
01086    if (test_resolver_data.canceled) {
01087       ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
01088       res = AST_TEST_FAIL;
01089       goto cleanup;
01090    }
01091 
01092    clock_gettime(CLOCK_REALTIME, &timeout);
01093    timeout.tv_sec += 10;
01094    ast_mutex_lock(&async_data->lock);
01095    while (!async_data->complete) {
01096       if (ast_cond_timedwait(&async_data->cond, &async_data->lock, &timeout) == ETIMEDOUT) {
01097          break;
01098       }
01099    }
01100    ast_mutex_unlock(&async_data->lock);
01101 
01102    if (!async_data->complete) {
01103       ast_test_status_update(test, "Asynchronous resolution timed out\n");
01104       res = AST_TEST_FAIL;
01105       goto cleanup;
01106    }
01107 
01108    if (!test_resolver_data.resolution_complete) {
01109       ast_test_status_update(test, "Asynchronous resolution completed early?\n");
01110       res = AST_TEST_FAIL;
01111       goto cleanup;
01112    }
01113 
01114    result = ast_dns_query_get_result(active->query);
01115    if (!result) {
01116       ast_test_status_update(test, "Asynchronous resolution yielded no result\n");
01117       res = AST_TEST_FAIL;
01118       goto cleanup;
01119    }
01120 
01121    if (!ast_dns_result_get_records(result)) {
01122       ast_test_status_update(test, "Asynchronous result had no records\n");
01123       res = AST_TEST_FAIL;
01124       goto cleanup;
01125    }
01126 
01127 cleanup:
01128    ast_dns_resolver_unregister(&test_resolver);
01129    resolver_data_cleanup();
01130    return res;
01131 }
01132 
01133 /*! Stub async resolution callback */
01134 static void stub_callback(const struct ast_dns_query *query)
01135 {
01136    return;
01137 }
01138 
01139 AST_TEST_DEFINE(resolver_resolve_async_off_nominal)
01140 {
01141    struct ast_dns_resolver terrible_resolver = {
01142       .name = "Ed Wood's Filmography",
01143       .priority = 0,
01144       .resolve = fail_resolve,
01145       .cancel = stub_cancel,
01146    };
01147 
01148    struct dns_resolve_data {
01149       const char *name;
01150       int rr_type;
01151       int rr_class;
01152       ast_dns_resolve_callback callback;
01153    } resolves [] = {
01154       { NULL,           ns_t_a,       ns_c_in,      stub_callback },
01155       { "asterisk.org", -1,           ns_c_in,      stub_callback },
01156       { "asterisk.org", ns_t_max + 1, ns_c_in,      stub_callback },
01157       { "asterisk.org", ns_t_a,       -1,           stub_callback },
01158       { "asterisk.org", ns_t_a,       ns_c_max + 1, stub_callback },
01159       { "asterisk.org", ns_t_a,       ns_c_in,      NULL },
01160    };
01161 
01162    struct ast_dns_query_active *active;
01163    enum ast_test_result_state res = AST_TEST_PASS;
01164    int i;
01165 
01166    switch (cmd) {
01167    case TEST_INIT:
01168       info->name = "resolver_resolve_async_off_nominal";
01169       info->category = "/main/dns/";
01170       info->summary = "Test off-nominal asynchronous DNS resolution";
01171       info->description =
01172          "This test performs several off-nominal asynchronous DNS resolutions:\n"
01173          "\t* Attempt resolution with NULL name\n",
01174          "\t* Attempt resolution with invalid RR type\n",
01175          "\t* Attempt resolution with invalid RR class\n",
01176          "\t* Attempt resolution with NULL callback pointer\n",
01177          "\t* Attempt resolution with resolver that returns an error\n";
01178       return AST_TEST_NOT_RUN;
01179    case TEST_EXECUTE:
01180       break;
01181    }
01182 
01183    if (ast_dns_resolver_register(&test_resolver)) {
01184       ast_test_status_update(test, "Failed to register test resolver\n");
01185       return AST_TEST_FAIL;
01186    }
01187 
01188    for (i = 0; i < ARRAY_LEN(resolves); ++i) {
01189       active = ast_dns_resolve_async(resolves[i].name, resolves[i].rr_type, resolves[i].rr_class,
01190             resolves[i].callback, NULL);
01191       if (active) {
01192          ast_test_status_update(test, "Successfully performed asynchronous resolution with invalid data\n");
01193          ao2_ref(active, -1);
01194          res = AST_TEST_FAIL;
01195       }
01196    }
01197 
01198    ast_dns_resolver_unregister(&test_resolver);
01199 
01200    if (ast_dns_resolver_register(&terrible_resolver)) {
01201       ast_test_status_update(test, "Failed to register the DNS resolver\n");
01202       return AST_TEST_FAIL;
01203    }
01204 
01205    active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, stub_callback, NULL);
01206 
01207    ast_dns_resolver_unregister(&terrible_resolver);
01208 
01209    if (active) {
01210       ast_test_status_update(test, "Successfully performed asynchronous resolution with invalid data\n");
01211       ao2_ref(active, -1);
01212       return AST_TEST_FAIL;
01213    }
01214 
01215    return res;
01216 }
01217 
01218 AST_TEST_DEFINE(resolver_resolve_async_cancel)
01219 {
01220    RAII_VAR(struct async_resolution_data *, async_data, NULL, ao2_cleanup);
01221    RAII_VAR(struct ast_dns_query_active *, active, NULL, ao2_cleanup);
01222    struct ast_dns_result *result;
01223    enum ast_test_result_state res = AST_TEST_PASS;
01224    struct timespec timeout;
01225 
01226    switch (cmd) {
01227    case TEST_INIT:
01228       info->name = "resolver_resolve_async_cancel";
01229       info->category = "/main/dns/";
01230       info->summary = "Test canceling an asynchronous DNS resolution";
01231       info->description =
01232          "This test performs an asynchronous DNS resolution of a domain and then cancels\n"
01233          "the resolution. The goal of this test is to ensure that the cancel() callback of\n"
01234          "the resolver is called and that it properly interrupts the resolution such that no\n"
01235          "records are returned.\n";
01236       return AST_TEST_NOT_RUN;
01237    case TEST_EXECUTE:
01238       break;
01239    }
01240 
01241    if (ast_dns_resolver_register(&test_resolver)) {
01242       ast_test_status_update(test, "Unable to register test resolver\n");
01243       return AST_TEST_FAIL;
01244    }
01245 
01246    resolver_data_init();
01247 
01248    async_data = async_data_alloc();
01249    if (!async_data) {
01250       ast_test_status_update(test, "Failed to allocate asynchronous data\n");
01251       res = AST_TEST_FAIL;
01252       goto cleanup;
01253    }
01254 
01255    active = ast_dns_resolve_async("asterisk.org", ns_t_a, ns_c_in, async_callback, async_data);
01256    if (!active) {
01257       ast_test_status_update(test, "Asynchronous resolution of address failed\n");
01258       res = AST_TEST_FAIL;
01259       goto cleanup;
01260    }
01261 
01262    if (!test_resolver_data.resolve_called) {
01263       ast_test_status_update(test, "DNS resolution did not call resolver's resolve() method\n");
01264       res = AST_TEST_FAIL;
01265       goto cleanup;
01266    }
01267 
01268    if (test_resolver_data.canceled) {
01269       ast_test_status_update(test, "Resolver's cancel() method called for no reason\n");
01270       res = AST_TEST_FAIL;
01271       goto cleanup;
01272    }
01273 
01274    ast_dns_resolve_cancel(active);
01275 
01276    if (!test_resolver_data.canceled) {
01277       ast_test_status_update(test, "Resolver's cancel() method was not called\n");
01278       res = AST_TEST_FAIL;
01279       goto cleanup;
01280    }
01281 
01282    clock_gettime(CLOCK_REALTIME, &timeout);
01283    timeout.tv_sec += 10;
01284    ast_mutex_lock(&async_data->lock);
01285    while (!async_data->complete) {
01286       if (ast_cond_timedwait(&async_data->cond, &async_data->lock, &timeout) == ETIMEDOUT) {
01287          break;
01288       }
01289    }
01290    ast_mutex_unlock(&async_data->lock);
01291 
01292    if (!async_data->complete) {
01293       ast_test_status_update(test, "Asynchronous resolution timed out\n");
01294       res = AST_TEST_FAIL;
01295       goto cleanup;
01296    }
01297 
01298    if (test_resolver_data.resolution_complete) {
01299       ast_test_status_update(test, "Resolution completed without cancelation\n");
01300       res = AST_TEST_FAIL;
01301       goto cleanup;
01302    }
01303 
01304    result = ast_dns_query_get_result(active->query);
01305    if (result) {
01306       ast_test_status_update(test, "Canceled resolution had a result\n");
01307       res = AST_TEST_FAIL;
01308       goto cleanup;
01309    }
01310 
01311 cleanup:
01312    ast_dns_resolver_unregister(&test_resolver);
01313    resolver_data_cleanup();
01314    return res;
01315 }
01316 
01317 static int unload_module(void)
01318 {
01319    AST_TEST_UNREGISTER(resolver_register_unregister);
01320    AST_TEST_UNREGISTER(resolver_register_off_nominal);
01321    AST_TEST_UNREGISTER(resolver_unregister_off_nominal);
01322    AST_TEST_UNREGISTER(resolver_data);
01323    AST_TEST_UNREGISTER(resolver_set_result);
01324    AST_TEST_UNREGISTER(resolver_set_result_off_nominal);
01325    AST_TEST_UNREGISTER(resolver_add_record);
01326    AST_TEST_UNREGISTER(resolver_add_record_off_nominal);
01327    AST_TEST_UNREGISTER(resolver_resolve_sync);
01328    AST_TEST_UNREGISTER(resolver_resolve_sync_off_nominal);
01329    AST_TEST_UNREGISTER(resolver_resolve_async);
01330    AST_TEST_UNREGISTER(resolver_resolve_async_off_nominal);
01331    AST_TEST_UNREGISTER(resolver_resolve_async_cancel);
01332 
01333    return 0;
01334 }
01335 
01336 static int load_module(void)
01337 {
01338    AST_TEST_REGISTER(resolver_register_unregister);
01339    AST_TEST_REGISTER(resolver_register_off_nominal);
01340    AST_TEST_REGISTER(resolver_unregister_off_nominal);
01341    AST_TEST_REGISTER(resolver_data);
01342    AST_TEST_REGISTER(resolver_set_result);
01343    AST_TEST_REGISTER(resolver_set_result_off_nominal);
01344    AST_TEST_REGISTER(resolver_add_record);
01345    AST_TEST_REGISTER(resolver_add_record_off_nominal);
01346    AST_TEST_REGISTER(resolver_resolve_sync);
01347    AST_TEST_REGISTER(resolver_resolve_sync_off_nominal);
01348    AST_TEST_REGISTER(resolver_resolve_async);
01349    AST_TEST_REGISTER(resolver_resolve_async_off_nominal);
01350    AST_TEST_REGISTER(resolver_resolve_async_cancel);
01351 
01352    return AST_MODULE_LOAD_SUCCESS;
01353 }
01354 
01355 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DNS API Tests");

Generated on Thu Apr 16 06:27:59 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6