From 8ab137b2bc9630ce20f45fd09b4ed2149afa45fd Mon Sep 17 00:00:00 2001 From: Tommie Gannert Date: Sat, 18 Dec 2010 22:31:39 +0100 Subject: [PATCH] ares: ask for both IPv4 and IPv6 addresses Make the c-ares resolver code ask for both IPv4 and IPv6 addresses when IPv6 is enabled. This is a workaround for the missing ares_getaddrinfo() and is a lot easier to implement. Note that as long as c-ares returns IPv4 addresses when IPv6 addresses were requested but missing, this will cause a host's IPv4 addresses to occur twice in the DNS cache. URL: http://curl.haxx.se/mail/lib-2010-12/0041.html --- lib/hostares.c | 29 +++++++++++++++++++------ lib/hostasyn.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-- lib/urldata.h | 2 ++ 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/lib/hostares.c b/lib/hostares.c index 97cb27ab9..a86ba435b 100644 --- a/lib/hostares.c +++ b/lib/hostares.c @@ -398,13 +398,30 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, Curl_safefree(conn->async.hostname); conn->async.hostname = bufp; conn->async.port = port; - conn->async.done = FALSE; /* not done */ - conn->async.status = 0; /* clear */ - conn->async.dns = NULL; /* clear */ + conn->async.done = FALSE; /* not done */ + conn->async.status = 0; /* clear */ + conn->async.dns = NULL; /* clear */ + conn->async.temp_ai = NULL; /* clear */ - /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname(data->state.areschannel, hostname, family, - (ares_host_callback)ares_query_completed_cb, conn); +#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ + if(family == PF_UNSPEC) { + conn->async.num_pending = 2; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname(data->state.areschannel, hostname, PF_INET, + ares_query_completed_cb, conn); + ares_gethostbyname(data->state.areschannel, hostname, PF_INET6, + ares_query_completed_cb, conn); + } + else +#endif /* CURLRES_IPV6 */ + { + conn->async.num_pending = 1; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname(data->state.areschannel, hostname, family, + ares_query_completed_cb, conn); + } *waitp = 1; /* expect asynchronous response */ } diff --git a/lib/hostasyn.c b/lib/hostasyn.c index 127b8d332..7d35fa0e7 100644 --- a/lib/hostasyn.c +++ b/lib/hostasyn.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -95,6 +95,20 @@ CURLcode Curl_addrinfo_callback(struct connectdata * conn, if(ai) { struct SessionHandle *data = conn->data; +#if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ + Curl_addrinfo *ai_tail = ai; + + while (ai_tail->ai_next) + ai_tail = ai_tail->ai_next; + + /* Add the new results to the list of old results. */ + ai_tail->ai_next = conn->async.temp_ai; + conn->async.temp_ai = ai; + + if(--conn->async.num_pending > 0) + /* We are not done yet. Just return. */ + return CURLE_OK; +#endif if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); @@ -110,9 +124,48 @@ CURLcode Curl_addrinfo_callback(struct connectdata * conn, if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } - else + else { +#if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ + if(--conn->async.num_pending > 0) { + /* We are not done yet. Clean up and return. + This function will be called again. */ + if(conn->async.temp_ai) + Curl_freeaddrinfo(conn->async.temp_ai); + return CURLE_OUT_OF_MEMORY; + } +#endif rc = CURLE_OUT_OF_MEMORY; + } } +#if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ + else + { + if(--conn->async.num_pending > 0) + /* We are not done yet. Just return. */ + return CURLE_OK; + + if(conn->async.temp_ai) { + /* We are done, and while this latest request + failed, some previous results exist. */ + struct SessionHandle *data = conn->data; + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + dns = Curl_cache_addr(data, conn->async.temp_ai, + conn->async.hostname, + conn->async.port); + if(!dns) { + /* failed to store, cleanup and return error */ + Curl_freeaddrinfo(conn->async.temp_ai); + rc = CURLE_OUT_OF_MEMORY; + } + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + } + } +#endif conn->async.dns = dns; diff --git a/lib/urldata.h b/lib/urldata.h index 83b646ea5..208ff4e6b 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -479,6 +479,8 @@ struct Curl_async { bool done; /* set TRUE when the lookup is complete */ int status; /* if done is TRUE, this is the status from the callback */ void *os_specific; /* 'struct thread_data' for Windows */ + int num_pending; /* number of ares_gethostbyname() requests */ + Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ }; #endif