From 4c096231fd622d4fe743b48411b1c906e1fa3344 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 20 Feb 2015 01:17:38 +0100 Subject: [PATCH] cares: fix set_servers during active queries `ares_set_servers()` should terminate all active queries to previous servers before destroying them. When invoking query callback remove it from the queue, to ensure that it won't be called two times. Fix: iojs/io.js#894 --- deps/cares/src/ares_cancel.c | 3 ++- deps/cares/src/ares_destroy.c | 46 +++++++++++++++++------------------ deps/cares/src/ares_private.h | 2 ++ deps/cares/src/ares_process.c | 16 ++++++++++-- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/deps/cares/src/ares_cancel.c b/deps/cares/src/ares_cancel.c index 465cc9e95ee16d..9b0dcb9ab722f2 100644 --- a/deps/cares/src/ares_cancel.c +++ b/deps/cares/src/ares_cancel.c @@ -48,8 +48,9 @@ void ares_cancel(ares_channel channel) { query = list_node->data; list_node = list_node->next; /* since we're deleting the query */ + ares__free_query_pre(query); query->callback(query->arg, ARES_ECANCELLED, 0, NULL, 0); - ares__free_query(query); + ares__free_query_post(query); } } if (!(channel->flags & ARES_FLAG_STAYOPEN) && ares__is_list_empty(&(channel->all_queries))) diff --git a/deps/cares/src/ares_destroy.c b/deps/cares/src/ares_destroy.c index 6c1f32442ea90f..243124ba683b2f 100644 --- a/deps/cares/src/ares_destroy.c +++ b/deps/cares/src/ares_destroy.c @@ -41,10 +41,32 @@ void ares_destroy_options(struct ares_options *options) void ares_destroy(ares_channel channel) { int i; + + ares__destroy_servers_state(channel); + + if (channel->domains) { + for (i = 0; i < channel->ndomains; i++) + free(channel->domains[i]); + free(channel->domains); + } + + if(channel->sortlist) + free(channel->sortlist); + + if (channel->lookups) + free(channel->lookups); + + free(channel); +} + +void ares__destroy_servers_state(ares_channel channel) +{ + struct server_state *server; + int i; struct query *query; struct list_node* list_head; struct list_node* list_node; - + if (!channel) return; @@ -71,28 +93,6 @@ void ares_destroy(ares_channel channel) } #endif - ares__destroy_servers_state(channel); - - if (channel->domains) { - for (i = 0; i < channel->ndomains; i++) - free(channel->domains[i]); - free(channel->domains); - } - - if(channel->sortlist) - free(channel->sortlist); - - if (channel->lookups) - free(channel->lookups); - - free(channel); -} - -void ares__destroy_servers_state(ares_channel channel) -{ - struct server_state *server; - int i; - if (channel->servers) { for (i = 0; i < channel->nservers; i++) diff --git a/deps/cares/src/ares_private.h b/deps/cares/src/ares_private.h index ab5be5a58aa6c9..fa258eefa49cfd 100644 --- a/deps/cares/src/ares_private.h +++ b/deps/cares/src/ares_private.h @@ -324,6 +324,8 @@ void ares__close_sockets(ares_channel channel, struct server_state *server); int ares__get_hostent(FILE *fp, int family, struct hostent **host); int ares__read_line(FILE *fp, char **buf, size_t *bufsize); void ares__free_query(struct query *query); +void ares__free_query_pre(struct query *query); +void ares__free_query_post(struct query *query); unsigned short ares__generate_new_id(rc4_key* key); struct timeval ares__tvnow(void); int ares__expand_name_for_response(const unsigned char *encoded, diff --git a/deps/cares/src/ares_process.c b/deps/cares/src/ares_process.c index bbeca5e737e73f..8d3bf9a2170165 100644 --- a/deps/cares/src/ares_process.c +++ b/deps/cares/src/ares_process.c @@ -1298,9 +1298,11 @@ static void end_query (ares_channel channel, struct query *query, int status, } } + ares__free_query_pre(query); + /* Invoke the callback */ query->callback(query->arg, status, query->timeouts, abuf, alen); - ares__free_query(query); + ares__free_query_post(query); /* Simple cleanup policy: if no queries are remaining, close all network * sockets unless STAYOPEN is set. @@ -1313,13 +1315,17 @@ static void end_query (ares_channel channel, struct query *query, int status, } } -void ares__free_query(struct query *query) +void ares__free_query_pre(struct query *query) { /* Remove the query from all the lists in which it is linked */ ares__remove_from_list(&(query->queries_by_qid)); ares__remove_from_list(&(query->queries_by_timeout)); ares__remove_from_list(&(query->queries_to_server)); ares__remove_from_list(&(query->all_queries)); +} + +void ares__free_query_post(struct query *query) +{ /* Zero out some important stuff, to help catch bugs */ query->callback = NULL; query->arg = NULL; @@ -1328,3 +1334,9 @@ void ares__free_query(struct query *query) free(query->server_info); free(query); } + +void ares__free_query(struct query *query) +{ + ares__free_query_pre(query); + ares__free_query_post(query); +}