diff options
Diffstat (limited to 'lib/asyn-ares.c')
-rw-r--r-- | lib/asyn-ares.c | 117 |
1 files changed, 73 insertions, 44 deletions
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 375f1a6eb..bb3f4af0b 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -237,26 +237,6 @@ CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl) return result; } -static void async_ares_cleanup(struct Curl_easy *data); - -void Curl_async_ares_shutdown(struct Curl_easy *data) -{ - struct async_ares_ctx *ares = &data->state.async.ares; - if(ares->channel) - ares_cancel(ares->channel); - async_ares_cleanup(data); -} - -void Curl_async_ares_destroy(struct Curl_easy *data) -{ - struct async_ares_ctx *ares = &data->state.async.ares; - Curl_async_ares_shutdown(data); - if(ares->channel) { - ares_destroy(ares->channel); - ares->channel = NULL; - } -} - /* * async_ares_cleanup() cleans up async resolver data. */ @@ -272,6 +252,26 @@ static void async_ares_cleanup(struct Curl_easy *data) #endif } +void Curl_async_ares_shutdown(struct Curl_easy *data) +{ + /* c-ares has a method to "cancel" operations on a channel, but + * as reported in #18216, this does not totally reset the channel + * and ares may get stuck. + * We need to destroy the channel and on demand create a new + * one to avoid that. */ + Curl_async_ares_destroy(data); +} + +void Curl_async_ares_destroy(struct Curl_easy *data) +{ + struct async_ares_ctx *ares = &data->state.async.ares; + if(ares->channel) { + ares_destroy(ares->channel); + ares->channel = NULL; + } + async_ares_cleanup(data); +} + /* * Curl_async_pollset() is called when someone from the outside world * (using curl_multi_fdset()) wants to get our fd_set setup. @@ -337,28 +337,55 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, Curl_resolv_unlink(data, &data->state.async.dns); data->state.async.done = TRUE; result = ares->result; - if(ares->last_status == CURL_ASYNC_SUCCESS && !result) { + if(ares->ares_status == ARES_SUCCESS && !result) { data->state.async.dns = Curl_dnscache_mk_entry(data, ares->temp_ai, data->state.async.hostname, 0, data->state.async.port, FALSE); ares->temp_ai = NULL; /* temp_ai now owned by entry */ #ifdef HTTPSRR_WORKS - if(data->state.async.dns) { - struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&ares->hinfo); - if(!lhrr) - result = CURLE_OUT_OF_MEMORY; - else - data->state.async.dns->hinfo = lhrr; - } + if(data->state.async.dns) { + struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&ares->hinfo); + if(!lhrr) + result = CURLE_OUT_OF_MEMORY; + else + data->state.async.dns->hinfo = lhrr; + } #endif if(!result && data->state.async.dns) result = Curl_dnscache_add(data, data->state.async.dns); } /* if we have not found anything, report the proper * CURLE_COULDNT_RESOLVE_* code */ - if(!result && !data->state.async.dns) + if(!result && !data->state.async.dns) { result = Curl_resolver_error(data); + if(ares->ares_status != ARES_SUCCESS) { + const char *msg; + switch(ares->ares_status) { + case ARES_ECONNREFUSED: + msg = "connection to DNS server refused"; + break; + case ARES_ETIMEOUT: + msg = "query to DNS server timed out"; + break; + case ARES_ENOTFOUND: + msg = "DNS server did not find the address"; + break; + case ARES_EREFUSED: + msg = "DNS server refused query"; + break; + default: + msg = "resolve failed"; + break; + } + CURL_TRC_DNS(data, "asyn-ares: %s (error %d)", msg, ares->ares_status); +#if ARES_VERSION >= 0x011800 /* >= v1.24.0 */ + CURL_TRC_DNS(data, "asyn-ares config: %s", + ares_get_servers_csv(ares->channel)); +#endif + } + } + if(result) Curl_resolv_unlink(data, &data->state.async.dns); *dns = data->state.async.dns; @@ -511,14 +538,14 @@ static void async_ares_hostbyname_cb(void *user_data, be valid so only defer it when we know the 'status' says its fine! */ return; - if(CURL_ASYNC_SUCCESS == status) { - ares->last_status = status; /* one success overrules any error */ + if(ARES_SUCCESS == status) { + ares->ares_status = status; /* one success overrules any error */ async_addr_concat(&ares->temp_ai, Curl_he2ai(hostent, data->state.async.port)); } - else if(ares->last_status != ARES_SUCCESS) { - /* no success so far, remember error */ - ares->last_status = status; + else if(ares->ares_status != ARES_SUCCESS) { + /* no success so far, remember last error */ + ares->ares_status = status; } ares->num_pending--; @@ -666,21 +693,22 @@ async_ares_node2addr(struct ares_addrinfo_node *node) } static void async_ares_addrinfo_cb(void *user_data, int status, int timeouts, - struct ares_addrinfo *result) + struct ares_addrinfo *ares_ai) { struct Curl_easy *data = (struct Curl_easy *)user_data; struct async_ares_ctx *ares = &data->state.async.ares; (void)timeouts; - CURL_TRC_DNS(data, "asyn-ares: addrinfo callback, status=%d", status); - if(ARES_SUCCESS == status) { - ares->temp_ai = async_ares_node2addr(result->nodes); - ares->last_status = CURL_ASYNC_SUCCESS; - ares_freeaddrinfo(result); + if(ares->ares_status != ARES_SUCCESS) /* do not overwrite success */ + ares->ares_status = status; + if(status == ARES_SUCCESS) { + ares->temp_ai = async_ares_node2addr(ares_ai->nodes); + ares_freeaddrinfo(ares_ai); } ares->num_pending--; - CURL_TRC_DNS(data, "ares: addrinfo done, status=%d, pending=%d, " - "addr=%sfound", - status, ares->num_pending, ares->temp_ai ? "" : "not "); + CURL_TRC_DNS(data, "ares: addrinfo done, query status=%d, " + "overall status=%d, pending=%d, addr=%sfound", + status, ares->ares_status, ares->num_pending, + ares->temp_ai ? "" : "not "); } #endif @@ -736,7 +764,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, return NULL; /* initial status - failed */ - ares->last_status = ARES_ENOTFOUND; + ares->ares_status = ARES_ENOTFOUND; + ares->result = CURLE_OK; #ifdef HAVE_CARES_GETADDRINFO { |