From 6a07664ef9e559f1121c31c47031b5eff1b6a2ee Mon Sep 17 00:00:00 2001 From: Neel Goyal Date: Mon, 3 Feb 2014 16:33:50 -0500 Subject: [PATCH] Fix an issue with timeouts in the async --- src/context.c | 13 +++++- src/test/check_getdns.c | 5 ++- src/test/check_getdns_common.c | 80 ++++++++++++++++++++++++---------- src/test/check_getdns_common.h | 20 ++++----- 4 files changed, 82 insertions(+), 36 deletions(-) diff --git a/src/context.c b/src/context.c index 2d92afca..7b9e164e 100644 --- a/src/context.c +++ b/src/context.c @@ -1330,6 +1330,8 @@ getdns_context_schedule_timeout(struct getdns_context* context, } node->key = &(timeout_data->transaction_id); node->data = timeout_data; + node->left = NULL; + node->right = NULL; if (!ldns_rbtree_insert(context->timeouts_by_id, node)) { /* free the node */ GETDNS_FREE(context->my_mf, timeout_data); @@ -1343,11 +1345,18 @@ getdns_context_schedule_timeout(struct getdns_context* context, } else { result = GETDNS_RETURN_GENERIC_ERROR; if (gettimeofday(&timeout_data->timeout_time, NULL) == 0) { + /* increment */ + uint16_t num_secs = timeout / 1000; + /* timeout is in millis */ + timeout_data->timeout_time.tv_sec += num_secs; + ldns_rbnode_t* id_node = GETDNS_MALLOC(context->my_mf, ldns_rbnode_t); if (id_node) { id_node->key = timeout_data; id_node->data = timeout_data; - if (!ldns_rbtree_insert(context->timeouts_by_time, node)) { + id_node->left = NULL; + id_node->right = NULL; + if (!ldns_rbtree_insert(context->timeouts_by_time, id_node)) { GETDNS_FREE(context->my_mf, id_node); } else { result = GETDNS_RETURN_GOOD; @@ -1359,7 +1368,7 @@ getdns_context_schedule_timeout(struct getdns_context* context, GETDNS_FREE(context->my_mf, timeout_data); GETDNS_FREE(context->my_mf, node); } - return GETDNS_RETURN_GOOD; + return result; } getdns_return_t diff --git a/src/test/check_getdns.c b/src/test/check_getdns.c index dcf0e0b4..6d8703d3 100644 --- a/src/test/check_getdns.c +++ b/src/test/check_getdns.c @@ -40,9 +40,12 @@ int -main (void) +main (int argc, char** argv) { int number_failed; + if (argc > 1) { + event_loop_type = atoi(argv[1]); + } SRunner *sr ; Suite *getdns_general_suite(void); diff --git a/src/test/check_getdns_common.c b/src/test/check_getdns_common.c index 4b5b9897..7d7249a6 100644 --- a/src/test/check_getdns_common.c +++ b/src/test/check_getdns_common.c @@ -5,12 +5,16 @@ #include #include #include +#include #include "check_getdns_common.h" +#include +#include int callback_called = 0; int callback_completed = 0; int callback_canceled = 0; uint16_t expected_changed_item = 0; +int event_loop_type = 0; /* * extract_response extracts all of the various information @@ -20,25 +24,25 @@ void extract_response(struct getdns_dict *response, struct extracted_response *e { ck_assert_msg(response != NULL, "Response should not be NULL"); - ASSERT_RC(getdns_dict_get_int(response, "answer_type", &ex_response->top_answer_type), + ASSERT_RC(getdns_dict_get_int(response, "answer_type", &ex_response->top_answer_type), GETDNS_RETURN_GOOD, "Failed to extract \"top answer_type\""); - ASSERT_RC(getdns_dict_get_bindata(response, "canonical_name", &ex_response->top_canonical_name), + ASSERT_RC(getdns_dict_get_bindata(response, "canonical_name", &ex_response->top_canonical_name), GETDNS_RETURN_GOOD, "Failed to extract \"top canonical_name\""); - ASSERT_RC(getdns_dict_get_list(response, "just_address_answers", &ex_response->just_address_answers), + ASSERT_RC(getdns_dict_get_list(response, "just_address_answers", &ex_response->just_address_answers), GETDNS_RETURN_GOOD, "Failed to extract \"just_address_answers\""); ck_assert_msg(ex_response->just_address_answers != NULL, "just_address_answers should not be NULL"); - ASSERT_RC(getdns_dict_get_list(response, "replies_full", &ex_response->replies_full), + ASSERT_RC(getdns_dict_get_list(response, "replies_full", &ex_response->replies_full), GETDNS_RETURN_GOOD, "Failed to extract \"replies_full\""); ck_assert_msg(ex_response->replies_full != NULL, "replies_full should not be NULL"); - ASSERT_RC(getdns_dict_get_list(response, "replies_tree", &ex_response->replies_tree), + ASSERT_RC(getdns_dict_get_list(response, "replies_tree", &ex_response->replies_tree), GETDNS_RETURN_GOOD, "Failed to extract \"replies_tree\""); ck_assert_msg(ex_response->replies_tree != NULL, "replies_tree should not be NULL"); - ASSERT_RC(getdns_list_get_dict(ex_response->replies_tree, 0, &ex_response->replies_tree_sub_dict), + ASSERT_RC(getdns_list_get_dict(ex_response->replies_tree, 0, &ex_response->replies_tree_sub_dict), GETDNS_RETURN_GOOD, "Failed to extract \"replies_tree[0]\""); ck_assert_msg(ex_response->replies_tree_sub_dict != NULL, "replies_tree[0] dict should not be NULL"); @@ -46,29 +50,29 @@ void extract_response(struct getdns_dict *response, struct extracted_response *e GETDNS_RETURN_GOOD, "Failed to extract \"additional\""); ck_assert_msg(ex_response->additional != NULL, "additional should not be NULL"); - ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "answer", &ex_response->answer), + ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "answer", &ex_response->answer), GETDNS_RETURN_GOOD, "Failed to extract \"answer\""); ck_assert_msg(ex_response->answer != NULL, "answer should not be NULL"); - ASSERT_RC(getdns_dict_get_int(ex_response->replies_tree_sub_dict, "answer_type", &ex_response->answer_type), + ASSERT_RC(getdns_dict_get_int(ex_response->replies_tree_sub_dict, "answer_type", &ex_response->answer_type), GETDNS_RETURN_GOOD, "Failed to extract \"answer_type\""); - ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "authority", &ex_response->authority), + ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "authority", &ex_response->authority), GETDNS_RETURN_GOOD, "Failed to extract \"authority\""); ck_assert_msg(ex_response->authority != NULL, "authority should not be NULL"); - ASSERT_RC(getdns_dict_get_bindata(ex_response->replies_tree_sub_dict, "canonical_name", &ex_response->canonical_name), + ASSERT_RC(getdns_dict_get_bindata(ex_response->replies_tree_sub_dict, "canonical_name", &ex_response->canonical_name), GETDNS_RETURN_GOOD, "Failed to extract \"canonical_name\""); - ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "header", &ex_response->header), + ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "header", &ex_response->header), GETDNS_RETURN_GOOD, "Failed to extract \"header\""); ck_assert_msg(ex_response->header != NULL, "header should not be NULL"); - ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "question", &ex_response->question), + ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "question", &ex_response->question), GETDNS_RETURN_GOOD, "Failed to extract \"question\""); ck_assert_msg(ex_response->question != NULL, "question should not be NULL"); - ASSERT_RC(getdns_dict_get_int(response, "status", &ex_response->status), + ASSERT_RC(getdns_dict_get_int(response, "status", &ex_response->status), GETDNS_RETURN_GOOD, "Failed to extract \"status\""); } @@ -87,17 +91,17 @@ void assert_noerror(struct extracted_response *ex_response) /* * assert_nodata asserts that ancount in the header and the * of the answer section (list) are both zero. - */ + */ void assert_nodata(struct extracted_response *ex_response) { uint32_t ancount; size_t length; - ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount), + ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount), GETDNS_RETURN_GOOD, "Failed to extract \"ancount\""); ck_assert_msg(ancount == 0, "Expected ancount == 0, got %d", ancount); - ASSERT_RC(getdns_list_get_length(ex_response->answer, &length), + ASSERT_RC(getdns_list_get_length(ex_response->answer, &length), GETDNS_RETURN_GOOD, "Failed to extract \"answer\" length"); ck_assert_msg(length == 0, "Expected \"answer\" length == 0, got %d", length); } @@ -110,7 +114,7 @@ void assert_nodata(struct extracted_response *ex_response) */ void assert_address_in_answer(struct extracted_response *ex_response, int a, int aaaa) { - uint32_t ancount; + uint32_t ancount; size_t length; struct getdns_dict *rr_dict; uint32_t type; @@ -127,9 +131,9 @@ void assert_address_in_answer(struct extracted_response *ex_response, int a, int for(i = 0; i < length; i++) { - ASSERT_RC(getdns_list_get_dict(ex_response->answer, i, &rr_dict), + ASSERT_RC(getdns_list_get_dict(ex_response->answer, i, &rr_dict), GETDNS_RETURN_GOOD, "Failed to extract \"answer\" record"); - ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type), + ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type), GETDNS_RETURN_GOOD, "Failed to extract \"type\" from answer record"); switch (type) { @@ -244,8 +248,8 @@ void callbackfn(struct getdns_context *context, /* * If userarg is NULL, either a negative test case - * erroneously reached the query state, or the value - * in userarg (verification function) was somehow + * erroneously reached the query state, or the value + * in userarg (verification function) was somehow * lost in transit. */ ck_assert_msg(userarg != NULL, "Callback called with NULL userarg"); @@ -282,8 +286,38 @@ void callbackfn(struct getdns_context *context, void update_callbackfn(struct getdns_context *context, uint16_t changed_item) { - - ck_assert_msg(changed_item == expected_changed_item, + + ck_assert_msg(changed_item == expected_changed_item, "Expected changed_item == %d, got %d", changed_item, expected_changed_item); } + +void run_event_loop(struct getdns_context* context, struct event_base* base) { + if (event_loop_type == 0) { + while (getdns_context_get_num_pending_requests(context, NULL) > 0) { + event_base_loop(base, EVLOOP_ONCE); + } + } else if (event_loop_type == 1) { + struct timeval tv; + while (getdns_context_get_num_pending_requests(context, &tv) > 0) { + int fd = getdns_context_fd(context); + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + select(fd + 1, &read_fds, NULL, NULL, &tv); + getdns_context_process_async(context); + } + } +} + +struct event_base* create_event_base(struct getdns_context* context) { + if (event_loop_type == 0) { + struct event_base* result = event_base_new(); + ck_assert_msg(result != NULL, "Event base creation failed"); + ASSERT_RC(getdns_extension_set_libevent_base(context, result), + GETDNS_RETURN_GOOD, + "Return code from getdns_extension_set_libevent_base()"); + return result; + } + return NULL; +} diff --git a/src/test/check_getdns_common.h b/src/test/check_getdns_common.h index 52858e0a..6cb58f40 100644 --- a/src/test/check_getdns_common.h +++ b/src/test/check_getdns_common.h @@ -1,6 +1,8 @@ #ifndef _check_getdns_common_h_ #define _check_getdns_common_h_ +#include "check_getdns_libevent.h" + #define TRUE 1 #define FALSE 0 #define MAXLEN 200 @@ -9,6 +11,7 @@ extern int callback_completed; extern int callback_canceled; extern uint16_t expected_changed_item; + extern int event_loop_type; struct extracted_response { uint32_t top_answer_type; @@ -64,20 +67,12 @@ * create an event base and put it in the * context. */ - #define EVENT_BASE_CREATE \ - event_base = event_base_new(); \ - ck_assert_msg(event_base != NULL, "Event base creation failed"); \ - ASSERT_RC(getdns_extension_set_libevent_base(context, event_base), \ - GETDNS_RETURN_GOOD, \ - "Return code from getdns_extension_set_libevent_base()"); + #define EVENT_BASE_CREATE event_base = create_event_base(context); /* * The RUN_EVENT_LOOP macro calls the event loop. */ - #define RUN_EVENT_LOOP \ - while (getdns_context_get_num_pending_requests(context, NULL) > 0) { \ - event_base_loop(event_base, EVLOOP_ONCE); \ - } + #define RUN_EVENT_LOOP run_event_loop(context, event_base); /* * The LIST_CREATE macro simply creates a @@ -185,4 +180,9 @@ void update_callbackfn(struct getdns_context *context, uint16_t changed_item); + /* run the event loop */ + void run_event_loop(struct getdns_context *context, struct event_base* event_base); + + struct event_base* create_event_base(struct getdns_context* context); + #endif