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
This commit is contained in:
Tommie Gannert 2010-12-18 22:31:39 +01:00 committed by Daniel Stenberg
parent bcfb9ea34c
commit 8ab137b2bc
3 changed files with 80 additions and 8 deletions

View File

@ -401,10 +401,27 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
conn->async.done = FALSE; /* not done */
conn->async.status = 0; /* clear */
conn->async.dns = NULL; /* clear */
conn->async.temp_ai = NULL; /* clear */
#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_host_callback)ares_query_completed_cb, conn);
ares_query_completed_cb, conn);
}
*waitp = 1; /* expect asynchronous response */
}

View File

@ -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;

View File

@ -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