]> granicus.if.org Git - curl/commitdiff
ares: ask for both IPv4 and IPv6 addresses
authorTommie Gannert <tommie@spotify.com>
Sat, 18 Dec 2010 21:31:39 +0000 (22:31 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 18 Dec 2010 21:33:27 +0000 (22:33 +0100)
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
lib/hostasyn.c
lib/urldata.h

index 97cb27ab91e67a45d7b07277b2a1e8c8e7682e2d..a86ba435b651940bead43304073d24c30e67f6d9 100644 (file)
@@ -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 */
   }
index 127b8d332017c781e0a617429babd0e29b6f400b..7d35fa0e7c79451109fdccee602417d3a47c86ec 100644 (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;
 
index 83b646ea5c0323d67fec0ddeddbb305c03ca2f9e..208ff4e6b0a51fff1fe4b55dfb519e2a9c54b515 100644 (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