summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTommie Gannert <tommie@spotify.com>2010-12-18 22:31:39 +0100
committerDaniel Stenberg <daniel@haxx.se>2010-12-18 22:33:27 +0100
commit8ab137b2bc9630ce20f45fd09b4ed2149afa45fd (patch)
treed7142eff2af46a955cc74a2929819bc2e0cbfc65 /lib
parentbcfb9ea34cc7cddbbf74376aa16043681e4745a7 (diff)
downloadcurl-8ab137b2bc9630ce20f45fd09b4ed2149afa45fd.tar.gz
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
Diffstat (limited to 'lib')
-rw-r--r--lib/hostares.c29
-rw-r--r--lib/hostasyn.c57
-rw-r--r--lib/urldata.h2
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, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, 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