已合并
fix cares-6.1 #106
hhd227创建于 3月4日
fix cares-6.1 #106
已合并
共 4 个文件变更+136-42
| @@ -344,7 +344,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server /* Optional */, | |||
| 344 | ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, | 344 | ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, |
| 345 | ares_status_t status, | 345 | ares_status_t status, |
| 346 | ares_bool_t inc_try_count, | 346 | ares_bool_t inc_try_count, |
| 347 | - const ares_dns_record_t *dnsrec, | 347 | + ares_dns_record_t *dnsrec, |
| 348 | ares_array_t **requeue); | 348 | ares_array_t **requeue); |
| 349 | 349 | ||
| 350 | /*! Count the number of labels (dots+1) in a domain */ | 350 | /*! Count the number of labels (dots+1) in a domain */ |
| @@ -617,10 +617,10 @@ ares_status_t ares_qcache_create(ares_rand_state *rand_state, | |||
| 617 | unsigned int max_ttl, | 617 | unsigned int max_ttl, |
| 618 | ares_qcache_t **cache_out); | 618 | ares_qcache_t **cache_out); |
| 619 | void ares_qcache_flush(ares_qcache_t *cache); | 619 | void ares_qcache_flush(ares_qcache_t *cache); |
| 620 | -ares_status_t ares_qcache_insert(ares_channel_t *channel, | 620 | +ares_status_t ares_qcache_insert(ares_channel_t *channel, |
| 621 | - const ares_timeval_t *now, | 621 | + const ares_timeval_t *now, |
| 622 | - const ares_query_t *query, | 622 | + const ares_query_t *query, |
| 623 | - ares_dns_record_t *dnsrec); | 623 | + const ares_dns_record_t *dnsrec); |
| 624 | ares_status_t ares_qcache_fetch(ares_channel_t *channel, | 624 | ares_status_t ares_qcache_fetch(ares_channel_t *channel, |
| 625 | const ares_timeval_t *now, | 625 | const ares_timeval_t *now, |
| 626 | const ares_dns_record_t *dnsrec, | 626 | const ares_dns_record_t *dnsrec, |
| @@ -64,7 +64,8 @@ static ares_bool_t same_questions(const ares_query_t *query, | |||
| 64 | const ares_dns_record_t *arec); | 64 | const ares_dns_record_t *arec); |
| 65 | static void end_query(ares_channel_t *channel, ares_server_t *server, | 65 | static void end_query(ares_channel_t *channel, ares_server_t *server, |
| 66 | ares_query_t *query, ares_status_t status, | 66 | ares_query_t *query, ares_status_t status, |
| 67 | - const ares_dns_record_t *dnsrec); | 67 | + ares_dns_record_t *dnsrec, |
| 68 | + ares_array_t **requeue); | ||
| 68 | 69 | ||
| 69 | static void ares_query_remove_from_conn(ares_query_t *query) | 70 | static void ares_query_remove_from_conn(ares_query_t *query) |
| 70 | { | 71 | { |
| @@ -511,16 +512,27 @@ static ares_status_t read_conn_packets(ares_conn_t *conn) | |||
| 511 | return ARES_SUCCESS; | 512 | return ARES_SUCCESS; |
| 512 | } | 513 | } |
| 513 | 514 | ||
| 515 | +typedef enum { | ||
| 516 | + REQUEUE_REQUEUE = 1, | ||
| 517 | + REQUEUE_ENDQUERY = 2 | ||
| 518 | +} requeue_type_t; | ||
| 519 | + | ||
| 514 | /* Simple data structure to store a query that needs to be requeued with | 520 | /* Simple data structure to store a query that needs to be requeued with |
| 515 | * optional server */ | 521 | * optional server */ |
| 516 | typedef struct { | 522 | typedef struct { |
| 517 | - unsigned short qid; | 523 | + requeue_type_t type; /* type of entry, requeue or endquery */ |
| 518 | - ares_server_t *server; /* optional */ | 524 | + unsigned short qid; /* query id */ |
| 525 | + ares_server_t *server; /* requeue only: optional */ | ||
| 526 | + ares_status_t status; /* endquery only */ | ||
| 527 | + ares_dns_record_t *dnsrec; /* endquery only: optional */ | ||
| 519 | } ares_requeue_t; | 528 | } ares_requeue_t; |
| 520 | 529 | ||
| 521 | -static ares_status_t ares_append_requeue(ares_array_t **requeue, | 530 | +static ares_status_t ares_append_requeue_int(ares_array_t **requeue, |
| 522 | - ares_query_t *query, | 531 | + requeue_type_t type, |
| 523 | - ares_server_t *server) | 532 | + ares_query_t *query, |
| 533 | + ares_server_t *server, | ||
| 534 | + ares_status_t status, | ||
| 535 | + ares_dns_record_t *dnsrec) | ||
| 524 | { | 536 | { |
| 525 | ares_requeue_t entry; | 537 | ares_requeue_t entry; |
| 526 | 538 | ||
| @@ -533,16 +545,36 @@ static ares_status_t ares_append_requeue(ares_array_t **requeue, | |||
| 533 | 545 | ||
| 534 | ares_query_remove_from_conn(query); | 546 | ares_query_remove_from_conn(query); |
| 535 | 547 | ||
| 548 | + entry.type = type; | ||
| 536 | entry.qid = query->qid; | 549 | entry.qid = query->qid; |
| 537 | entry.server = server; | 550 | entry.server = server; |
| 551 | + entry.status = status; | ||
| 552 | + entry.dnsrec = dnsrec; | ||
| 538 | return ares_array_insertdata_last(*requeue, &entry); | 553 | return ares_array_insertdata_last(*requeue, &entry); |
| 539 | } | 554 | } |
| 540 | 555 | ||
| 556 | +static ares_status_t ares_append_requeue(ares_array_t **requeue, | ||
| 557 | + ares_query_t *query, | ||
| 558 | + ares_server_t *server) | ||
| 559 | +{ | ||
| 560 | + return ares_append_requeue_int(requeue, REQUEUE_REQUEUE, query, server, 0, | ||
| 561 | + NULL); | ||
| 562 | +} | ||
| 563 | + | ||
| 564 | +static ares_status_t ares_append_endqueue(ares_array_t **requeue, | ||
| 565 | + ares_query_t *query, | ||
| 566 | + ares_status_t status, | ||
| 567 | + ares_dns_record_t *dnsrec) | ||
| 568 | +{ | ||
| 569 | + return ares_append_requeue_int(requeue, REQUEUE_ENDQUERY, query, NULL, status, | ||
| 570 | + dnsrec); | ||
| 571 | +} | ||
| 572 | + | ||
| 541 | static ares_status_t read_answers(ares_conn_t *conn, const ares_timeval_t *now) | 573 | static ares_status_t read_answers(ares_conn_t *conn, const ares_timeval_t *now) |
| 542 | { | 574 | { |
| 543 | ares_status_t status; | 575 | ares_status_t status; |
| 544 | - ares_channel_t *channel = conn->server->channel; | 576 | + ares_channel_t *channel = conn->server->channel; |
| 545 | - ares_array_t *requeue = NULL; | 577 | + ares_array_t *requeue = NULL; |
| 546 | 578 | ||
| 547 | /* Process all queued answers */ | 579 | /* Process all queued answers */ |
| 548 | while (1) { | 580 | while (1) { |
| @@ -602,18 +634,30 @@ cleanup: | |||
| 602 | break; | 634 | break; |
| 603 | } | 635 | } |
| 604 | 636 | ||
| 605 | - /* Query disappeared */ | ||
| 606 | query = ares_htable_szvp_get_direct(channel->queries_by_qid, entry.qid); | 637 | query = ares_htable_szvp_get_direct(channel->queries_by_qid, entry.qid); |
| 607 | - if (query == NULL) { | ||
| 608 | - continue; | ||
| 609 | - } | ||
| 610 | 638 | ||
| 611 | - internal_status = ares_send_query(entry.server, query, now); | 639 | + if (entry.type == REQUEUE_REQUEUE) { |
| 612 | - /* We only care about ARES_ENOMEM */ | 640 | + /* query disappeared */ |
| 613 | - if (internal_status == ARES_ENOMEM) { | 641 | + if (query == NULL) { |
| 614 | - status = ARES_ENOMEM; | 642 | + continue; |
| 643 | + } | ||
| 644 | + internal_status = ares_send_query(entry.server, query, now); | ||
| 645 | + /* We only care about ARES_ENOMEM */ | ||
| 646 | + if (internal_status == ARES_ENOMEM) { | ||
| 647 | + status = ARES_ENOMEM; | ||
| 648 | + } | ||
| 649 | + } else { /* REQUEUE_ENDQUERY */ | ||
| 650 | + if (query != NULL) { | ||
| 651 | + query->callback(query->arg, entry.status, query->timeouts, entry.dnsrec); | ||
| 652 | + ares_free_query(query); | ||
| 653 | + } | ||
| 654 | + ares_dns_record_destroy(entry.dnsrec); | ||
| 615 | } | 655 | } |
| 616 | } | 656 | } |
| 657 | + /* Don't forget to send notification if queue emptied */ | ||
| 658 | + if (requeue != NULL) { | ||
| 659 | + ares_queue_notify_empty(channel); | ||
| 660 | + } | ||
| 617 | ares_array_destroy(requeue); | 661 | ares_array_destroy(requeue); |
| 618 | 662 | ||
| 619 | return status; | 663 | return status; |
| @@ -669,7 +713,7 @@ static ares_status_t process_timeouts(ares_channel_t *channel, | |||
| 669 | conn = query->conn; | 713 | conn = query->conn; |
| 670 | server_increment_failures(conn->server, query->using_tcp); | 714 | server_increment_failures(conn->server, query->using_tcp); |
| 671 | status = ares_requeue_query(query, now, ARES_ETIMEOUT, ARES_TRUE, NULL, | 715 | status = ares_requeue_query(query, now, ARES_ETIMEOUT, ARES_TRUE, NULL, |
| 672 | - NULL); | 716 | + NULL); |
| 673 | if (status == ARES_ENOMEM) { | 717 | if (status == ARES_ENOMEM) { |
| 674 | goto done; | 718 | goto done; |
| 675 | } | 719 | } |
| @@ -824,7 +868,7 @@ static ares_status_t process_answer(ares_channel_t *channel, | |||
| 824 | if (issue_might_be_edns(query->query, rdnsrec)) { | 868 | if (issue_might_be_edns(query->query, rdnsrec)) { |
| 825 | status = rewrite_without_edns(query); | 869 | status = rewrite_without_edns(query); |
| 826 | if (status != ARES_SUCCESS) { | 870 | if (status != ARES_SUCCESS) { |
| 827 | - end_query(channel, server, query, status, NULL); | 871 | + end_query(channel, server, query, status, NULL, NULL); |
| 828 | goto cleanup; | 872 | goto cleanup; |
| 829 | } | 873 | } |
| 830 | 874 | ||
| @@ -869,7 +913,9 @@ static ares_status_t process_answer(ares_channel_t *channel, | |||
| 869 | } | 913 | } |
| 870 | 914 | ||
| 871 | server_increment_failures(server, query->using_tcp); | 915 | server_increment_failures(server, query->using_tcp); |
| 872 | - status = ares_requeue_query(query, now, status, ARES_TRUE, rdnsrec, requeue); | 916 | + status = ares_requeue_query(query, now, status, ARES_TRUE, rdnsrec, |
| 917 | + requeue); | ||
| 918 | + rdnsrec = NULL; /* Free'd by ares_requeue_query() */ | ||
| 873 | 919 | ||
| 874 | if (status != ARES_ENOMEM) { | 920 | if (status != ARES_ENOMEM) { |
| 875 | /* Should any of these cause a connection termination? | 921 | /* Should any of these cause a connection termination? |
| @@ -882,12 +928,11 @@ static ares_status_t process_answer(ares_channel_t *channel, | |||
| 882 | 928 | ||
| 883 | /* If cache insertion was successful, it took ownership. We ignore | 929 | /* If cache insertion was successful, it took ownership. We ignore |
| 884 | * other cache insertion failures. */ | 930 | * other cache insertion failures. */ |
| 885 | - if (ares_qcache_insert(channel, now, query, rdnsrec) == ARES_SUCCESS) { | 931 | + ares_qcache_insert(channel, now, query, rdnsrec); |
| 886 | - is_cached = ARES_TRUE; | ||
| 887 | - } | ||
| 888 | 932 | ||
| 889 | server_set_good(server, query->using_tcp); | 933 | server_set_good(server, query->using_tcp); |
| 890 | - end_query(channel, server, query, ARES_SUCCESS, rdnsrec); | 934 | + end_query(channel, server, query, ARES_SUCCESS, rdnsrec, requeue); |
| 935 | + rdnsrec = NULL; /* Free'd by the requeue */ | ||
| 891 | 936 | ||
| 892 | status = ARES_SUCCESS; | 937 | status = ARES_SUCCESS; |
| 893 | 938 | ||
| @@ -922,7 +967,7 @@ static void handle_conn_error(ares_conn_t *conn, ares_bool_t critical_failure, | |||
| 922 | ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, | 967 | ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, |
| 923 | ares_status_t status, | 968 | ares_status_t status, |
| 924 | ares_bool_t inc_try_count, | 969 | ares_bool_t inc_try_count, |
| 925 | - const ares_dns_record_t *dnsrec, | 970 | + ares_dns_record_t *dnsrec, |
| 926 | ares_array_t **requeue) | 971 | ares_array_t **requeue) |
| 927 | { | 972 | { |
| 928 | ares_channel_t *channel = query->channel; | 973 | ares_channel_t *channel = query->channel; |
| @@ -939,6 +984,7 @@ ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, | |||
| 939 | } | 984 | } |
| 940 | 985 | ||
| 941 | if (query->try_count < max_tries && !query->no_retries) { | 986 | if (query->try_count < max_tries && !query->no_retries) { |
| 987 | + ares_dns_record_destroy(dnsrec); | ||
| 942 | if (requeue != NULL) { | 988 | if (requeue != NULL) { |
| 943 | return ares_append_requeue(requeue, query, NULL); | 989 | return ares_append_requeue(requeue, query, NULL); |
| 944 | } | 990 | } |
| @@ -950,7 +996,7 @@ ares_status_t ares_requeue_query(ares_query_t *query, const ares_timeval_t *now, | |||
| 950 | query->error_status = ARES_ETIMEOUT; | 996 | query->error_status = ARES_ETIMEOUT; |
| 951 | } | 997 | } |
| 952 | 998 | ||
| 953 | - end_query(channel, NULL, query, query->error_status, dnsrec); | 999 | + end_query(channel, NULL, query, query->error_status, dnsrec, requeue); |
| 954 | return ARES_ETIMEOUT; | 1000 | return ARES_ETIMEOUT; |
| 955 | } | 1001 | } |
| 956 | 1002 | ||
| @@ -1232,7 +1278,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server, | |||
| 1232 | } | 1278 | } |
| 1233 | 1279 | ||
| 1234 | if (server == NULL) { | 1280 | if (server == NULL) { |
| 1235 | - end_query(channel, server, query, ARES_ENOSERVER /* ? */, NULL); | 1281 | + end_query(channel, server, query, ARES_ENOSERVER /* ? */, NULL, NULL); |
| 1236 | return ARES_ENOSERVER; | 1282 | return ARES_ENOSERVER; |
| 1237 | } | 1283 | } |
| 1238 | 1284 | ||
| @@ -1260,7 +1306,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server, | |||
| 1260 | 1306 | ||
| 1261 | /* Anything else is not retryable, likely ENOMEM */ | 1307 | /* Anything else is not retryable, likely ENOMEM */ |
| 1262 | default: | 1308 | default: |
| 1263 | - end_query(channel, server, query, status, NULL); | 1309 | + end_query(channel, server, query, status, NULL, NULL); |
| 1264 | return status; | 1310 | return status; |
| 1265 | } | 1311 | } |
| 1266 | } | 1312 | } |
| @@ -1274,7 +1320,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server, | |||
| 1274 | 1320 | ||
| 1275 | case ARES_ENOMEM: | 1321 | case ARES_ENOMEM: |
| 1276 | /* Not retryable */ | 1322 | /* Not retryable */ |
| 1277 | - end_query(channel, server, query, status, NULL); | 1323 | + end_query(channel, server, query, status, NULL, NULL); |
| 1278 | return status; | 1324 | return status; |
| 1279 | 1325 | ||
| 1280 | /* These conditions are retryable as they are server-specific | 1326 | /* These conditions are retryable as they are server-specific |
| @@ -1309,7 +1355,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server, | |||
| 1309 | ares_slist_insert(channel->queries_by_timeout, query); | 1355 | ares_slist_insert(channel->queries_by_timeout, query); |
| 1310 | if (!query->node_queries_by_timeout) { | 1356 | if (!query->node_queries_by_timeout) { |
| 1311 | /* LCOV_EXCL_START: OutOfMemory */ | 1357 | /* LCOV_EXCL_START: OutOfMemory */ |
| 1312 | - end_query(channel, server, query, ARES_ENOMEM, NULL); | 1358 | + end_query(channel, server, query, ARES_ENOMEM, NULL, NULL); |
| 1313 | return ARES_ENOMEM; | 1359 | return ARES_ENOMEM; |
| 1314 | /* LCOV_EXCL_STOP */ | 1360 | /* LCOV_EXCL_STOP */ |
| 1315 | } | 1361 | } |
| @@ -1322,7 +1368,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server, | |||
| 1322 | 1368 | ||
| 1323 | if (query->node_queries_to_conn == NULL) { | 1369 | if (query->node_queries_to_conn == NULL) { |
| 1324 | /* LCOV_EXCL_START: OutOfMemory */ | 1370 | /* LCOV_EXCL_START: OutOfMemory */ |
| 1325 | - end_query(channel, server, query, ARES_ENOMEM, NULL); | 1371 | + end_query(channel, server, query, ARES_ENOMEM, NULL, NULL); |
| 1326 | return ARES_ENOMEM; | 1372 | return ARES_ENOMEM; |
| 1327 | /* LCOV_EXCL_STOP */ | 1373 | /* LCOV_EXCL_STOP */ |
| 1328 | } | 1374 | } |
| @@ -1410,7 +1456,7 @@ static void ares_detach_query(ares_query_t *query) | |||
| 1410 | 1456 | ||
| 1411 | static void end_query(ares_channel_t *channel, ares_server_t *server, | 1457 | static void end_query(ares_channel_t *channel, ares_server_t *server, |
| 1412 | ares_query_t *query, ares_status_t status, | 1458 | ares_query_t *query, ares_status_t status, |
| 1413 | - const ares_dns_record_t *dnsrec) | 1459 | + ares_dns_record_t *dnsrec, ares_array_t **requeue) |
| 1414 | { | 1460 | { |
| 1415 | /* If we were probing for the server to come back online, lets mark it as | 1461 | /* If we were probing for the server to come back online, lets mark it as |
| 1416 | * no longer being probed */ | 1462 | * no longer being probed */ |
| @@ -1420,6 +1466,12 @@ static void end_query(ares_channel_t *channel, ares_server_t *server, | |||
| 1420 | 1466 | ||
| 1421 | ares_metrics_record(query, server, status, dnsrec); | 1467 | ares_metrics_record(query, server, status, dnsrec); |
| 1422 | 1468 | ||
| 1469 | + /* Delay calling the query callback */ | ||
| 1470 | + if (requeue != NULL) { | ||
| 1471 | + ares_append_endqueue(requeue, query, status, dnsrec); | ||
| 1472 | + return; | ||
| 1473 | + } | ||
| 1474 | + | ||
| 1423 | /* Invoke the callback. */ | 1475 | /* Invoke the callback. */ |
| 1424 | query->callback(query->arg, status, query->timeouts, dnsrec); | 1476 | query->callback(query->arg, status, query->timeouts, dnsrec); |
| 1425 | ares_free_query(query); | 1477 | ares_free_query(query); |
| @@ -421,10 +421,20 @@ done: | |||
| 421 | return status; | 421 | return status; |
| 422 | } | 422 | } |
| 423 | 423 | ||
| 424 | -ares_status_t ares_qcache_insert(ares_channel_t *channel, | 424 | + ares_status_t ares_qcache_insert(ares_channel_t *channel, |
| 425 | - const ares_timeval_t *now, | 425 | + const ares_timeval_t *now, |
| 426 | - const ares_query_t *query, | 426 | + const ares_query_t *query, |
| 427 | - ares_dns_record_t *dnsrec) | 427 | + const ares_dns_record_t *dnsrec) |
| 428 | { | 428 | { |
| 429 | - return ares_qcache_insert_int(channel->qcache, dnsrec, query->query, now); | 429 | + ares_dns_record_t *dupdns = ares_dns_record_duplicate(dnsrec); |
| 430 | + ares_status_t status; | ||
| 431 | + | ||
| 432 | + if (dupdns == NULL) { | ||
| 433 | + return ARES_ENOMEM; | ||
| 434 | + } | ||
| 435 | + status = ares_qcache_insert_int(channel->qcache, dupdns, query->query, now); | ||
| 436 | + if (status != ARES_SUCCESS) { | ||
| 437 | + ares_dns_record_destroy(dupdns); | ||
| 438 | + } | ||
| 439 | + return status; | ||
| 430 | } | 440 | } |
| @@ -805,7 +805,39 @@ TEST_P(MockUDPChannelTestAI, TriggerResendThenConnFailEDNS) { | |||
| 805 | EXPECT_THAT(result.ai_, IncludesV6Address("2121:0000:0000:0000:0000:0000:0000:0303")); | 805 | EXPECT_THAT(result.ai_, IncludesV6Address("2121:0000:0000:0000:0000:0000:0000:0303")); |
| 806 | } | 806 | } |
| 807 | 807 | ||
| 808 | - | 808 | +TEST_P(MockUDPChannelTestAI, ConnectionRefusedOnSearchDomainRetry) { |
| 809 | + DNSPacket badrsp4; | ||
| 810 | + badrsp4.set_response().set_aa() | ||
| 811 | + .add_question(new DNSQuestion("www.google.com", T_A)) | ||
| 812 | + .set_rcode(NXDOMAIN); | ||
| 813 | + | ||
| 814 | + EXPECT_CALL(server_, OnRequest("www.google.com", T_A)) | ||
| 815 | + .WillOnce(SetReplyAndFailSend(&server_, &badrsp4)); | ||
| 816 | + | ||
| 817 | + DNSPacket goodrsp4; | ||
| 818 | + goodrsp4.set_response().set_aa() | ||
| 819 | + .add_question(new DNSQuestion("www.google.com.first.com", T_A)) | ||
| 820 | + .add_answer(new DNSARR("www.google.com.first.com", 0x0100, {0x01, 0x02, 0x03, 0x04})); | ||
| 821 | + | ||
| 822 | + EXPECT_CALL(server_, OnRequest("www.google.com.first.com", T_A)) | ||
| 823 | + .WillOnce(SetReply(&server_, &goodrsp4)); | ||
| 824 | + | ||
| 825 | + ares_socket_functions sock_funcs; | ||
| 826 | + memset(&sock_funcs, 0, sizeof(sock_funcs)); | ||
| 827 | + | ||
| 828 | + sock_funcs.asendv = ares_sendv_fail; | ||
| 829 | + | ||
| 830 | + ares_set_socket_functions(channel_, &sock_funcs, NULL); | ||
| 831 | + | ||
| 832 | + AddrInfoResult result; | ||
| 833 | + struct ares_addrinfo_hints hints = {0, 0, 0, 0}; | ||
| 834 | + hints.ai_family = AF_INET; | ||
| 835 | + hints.ai_flags = ARES_AI_NOSORT; | ||
| 836 | + ares_getaddrinfo(channel_, "www.google.com", NULL, &hints, | ||
| 837 | + AddrInfoCallback, &result); | ||
| 838 | + | ||
| 839 | + Process(); | ||
| 840 | +} | ||
| 809 | 841 | ||
| 810 | class MockEDNSChannelTestAI : public MockFlagsChannelOptsTestAI { | 842 | class MockEDNSChannelTestAI : public MockFlagsChannelOptsTestAI { |
| 811 | public: | 843 | public: |