]> granicus.if.org Git - curl/commitdiff
ares awareness/usage/support added. If configure --enable-ares is used, we
authorDaniel Stenberg <daniel@haxx.se>
Tue, 5 Aug 2003 14:40:59 +0000 (14:40 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 5 Aug 2003 14:40:59 +0000 (14:40 +0000)
build libcurl to use ares for asynch name resolves.

lib/Makefile.am
lib/connect.c
lib/ftp.c
lib/hostip.c
lib/hostip.h
lib/multi.c
lib/setup.h
lib/transfer.c
lib/url.c
lib/url.h
lib/urldata.h

index 421b4fecb9a993321990b82df15a316210b4ad90..ffa6be2b1508965ecf4dfd3e87fe74c264a2dac0 100644 (file)
@@ -12,10 +12,16 @@ EXTRA_DIST = getdate.y Makefile.b32 Makefile.b32.resp Makefile.m32      \
 
 lib_LTLIBRARIES = libcurl.la
 
+if ARES
+ARESINC = -I$(top_srcdir)/ares
+endif
+
 # we use srcdir/include for the static global include files
 # we use builddir/lib for the generated lib/config.h file to get found
 # we use srcdir/lib for the lib-private header files
-INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/lib -I$(top_srcdir)/lib
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/lib -I$(top_srcdir)/lib $(ARESINC)
+
+LDFLAGS = -L$(top_srcdir)/lib
 
 VERSION=-version-info 2:2:0
 
@@ -48,15 +54,18 @@ VERSION=-version-info 2:2:0
 #
 
 if NO_UNDEFINED
-# The -no-undefined flag is CRUCIAL for this to build fine on Cygwin. If we
-# find a case in which we need to remove this flag, we should most likely
-# write a configure check that detects when this flag is needed and when its
-# not.
-libcurl_la_LDFLAGS = -no-undefined $(VERSION)
+# The -no-undefined flag is CRUCIAL for this to build fine on Cygwin.
+UNDEF = -no-undefined
 else
-libcurl_la_LDFLAGS = $(VERSION)
+UNDEF =
 endif
 
+if ARES
+ARESLIB = -lares -L$(top_builddir)/ares
+endif
+
+libcurl_la_LDFLAGS = $(UNDEF) $(VERSION) $(ARESLIB)
+
 libcurl_la_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c  \
 base64.c file.h hostip.c progress.c timeval.h base64.h formdata.c      \
 hostip.h progress.h cookie.c formdata.h http.c sendf.c cookie.h ftp.c  \
index 681fc0039b1be0a3208a60be1d1a2ab2993cfa1b..9bc7d50766e7e029e403d50466a2cec26ccac488 100644 (file)
@@ -208,6 +208,7 @@ static CURLcode bindlocal(struct connectdata *conn,
     size_t size;
     char myhost[256] = "";
     in_addr_t in;
+    int rc;
 
     /* First check if the given name is an IP address */
     in=inet_addr(data->set.device);
@@ -217,7 +218,10 @@ static CURLcode bindlocal(struct connectdata *conn,
       /*
        * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
        */
-      h = Curl_resolv(data, myhost, 0);
+      rc = Curl_resolv(conn, myhost, 0, &h);
+      if(rc == 1)
+        rc = Curl_wait_for_resolv(conn, &h);
+
     }
     else {
       if(strlen(data->set.device)>1) {
@@ -225,11 +229,14 @@ static CURLcode bindlocal(struct connectdata *conn,
          * This was not an interface, resolve the name as a host name
          * or IP number
          */
-        h = Curl_resolv(data, data->set.device, 0);
-        if(h) {
+        rc = Curl_resolv(conn, data->set.device, 0, &h);
+        if(rc == 1)
+          rc = Curl_wait_for_resolv(conn, &h);
+
+        if(h)
           /* we know data->set.device is shorter than the myhost array */
           strcpy(myhost, data->set.device);
-        }
+
       }
     }
 
index 6acab245b0200c2bc5decbccd6f7c4498d56bf48..bb3b9feb3b45ee21fd8e4899b0facfc1837ec30b 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1231,18 +1231,24 @@ CURLcode ftp_use_port(struct connectdata *conn)
 
   if(data->set.ftpport) {
     in_addr_t in;
+    int rc;
 
     /* First check if the given name is an IP address */
     in=inet_addr(data->set.ftpport);
 
     if((in == CURL_INADDR_NONE) &&
        Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
-      h = Curl_resolv(data, myhost, 0);
+      rc = Curl_resolv(conn, myhost, 0, &h);
+      if(rc == 1)
+        rc = Curl_wait_for_resolv(conn, &h);
     }
     else {
       int len = strlen(data->set.ftpport);
-      if(len>1)
-        h = Curl_resolv(data, data->set.ftpport, 0);
+      if(len>1) {
+        rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
+        if(rc == 1)
+          rc = Curl_wait_for_resolv(conn, &h);
+      }
       if(h)
         strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
     }
@@ -1381,6 +1387,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
   CURLcode result;
   struct Curl_dns_entry *addr=NULL;
   Curl_ipconnect *conninfo;
+  int rc;
 
   /*
     Here's the excecutive summary on what to do:
@@ -1505,14 +1512,20 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
      * We don't want to rely on a former host lookup that might've expired
      * now, instead we remake the lookup here and now!
      */
-    addr = Curl_resolv(data, conn->proxyhost, conn->port);
+    rc = Curl_resolv(conn, conn->proxyhost, conn->port, &addr);
+    if(rc == 1)
+      rc = Curl_wait_for_resolv(conn, &addr);
+
     connectport =
       (unsigned short)conn->port; /* we connect to the proxy's port */    
 
   }
   else {
     /* normal, direct, ftp connection */
-    addr = Curl_resolv(data, newhostp, newport);
+    rc = Curl_resolv(conn, newhostp, newport, &addr);
+    if(rc == 1)
+      rc = Curl_wait_for_resolv(conn, &addr);
+
     if(!addr) {
       failf(data, "Can't resolve new host %s:%d", newhostp, newport);
       return CURLE_FTP_CANT_GET_HOST;
index b1b175d9e4ac7607866246499197daa6ee87ac3f..3e69d4ea95e7a5f4aaa8c8756e4a786ca81c9daf 100644 (file)
@@ -65,6 +65,7 @@
 #include "hostip.h"
 #include "hash.h"
 #include "share.h"
+#include "url.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
 static curl_hash hostname_cache;
 static int host_cache_initialized;
 
-static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
-                                       char *hostname,
-                                       int port,
-                                       char **bufp);
+static Curl_addrinfo *my_getaddrinfo(struct connectdata *conn,
+                                     char *hostname,
+                                     int port,
+                                     int *waitp);
+#if !defined(HAVE_GETHOSTBYNAME_R) || defined(USE_ARES)
+static struct hostent* pack_hostent(char** buf, struct hostent* orig);
+#endif
 
 void Curl_global_host_cache_init(void)
 {
@@ -135,15 +139,14 @@ create_hostcache_id(char *server, int port, ssize_t *entry_len)
   char *id = NULL;
 
   /* Get the length of the new entry id */
-  *entry_len = *entry_len +      /* Hostname length */
-               1 +               /* The ':' seperator */
-               _num_chars(port); /* The number of characters the port will take up */
+  *entry_len = *entry_len + /* Hostname length */
+    1 +                     /* ':' seperator */
+    _num_chars(port);       /* number of characters the port will take up */
   
   /* Allocate the new entry id */
   id = malloc(*entry_len + 1);
-  if (!id) {
+  if (!id)
     return NULL;
-  }
 
   /* Create the new entry */
   /* If sprintf() doesn't return the entry length, that signals failure */
@@ -192,47 +195,88 @@ hostcache_prune(curl_hash *hostcache, int cache_timeout, int now)
                                  hostcache_timestamp_remove);
 }
 
-#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
-/* Called from Curl_done() to check that there's no DNS cache entry with
-   a non-zero counter left. */
-void Curl_scan_cache_used(void *user, void *ptr)
+#ifdef HAVE_SIGSETJMP
+/* Beware this is a global and unique instance */
+sigjmp_buf curl_jmpenv;
+#endif
+
+
+/* When calling Curl_resolv() has resulted in a response with a returned
+   address, we call this function to store the information in the dns
+   cache etc */
+
+static struct Curl_dns_entry *
+cache_resolv_response(struct SessionHandle *data,
+                      Curl_addrinfo *addr,
+                      char *hostname,
+                      int port)
 {
-  struct Curl_dns_entry *e = ptr;
-  (void)user; /* prevent compiler warning */
-  if(e->inuse) {
-    fprintf(stderr, "*** WARNING: locked DNS cache entry detected: %s\n",
-            e->entry_id);
-    /* perform a segmentation fault to draw attention */
-    *(void **)0 = 0;
+  char *entry_id;
+  int entry_len;
+  struct Curl_dns_entry *dns;
+  time_t now;
+
+  /* Create an entry id, based upon the hostname and port */
+  entry_len = strlen(hostname);
+  entry_id = create_hostcache_id(hostname, port, &entry_len);
+  /* If we can't create the entry id, fail */
+  if (!entry_id)
+    return NULL;
+
+  /* Create a new cache entry */
+  dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
+  if (!dns) {
+    Curl_freeaddrinfo(addr);
+    free(entry_id);
+    return NULL;
   }
-}
-#endif
 
-/* Macro to save redundant free'ing of entry_id */
-#define HOSTCACHE_RETURN(dns) \
-{ \
-  free(entry_id); \
-  if(data->share) \
-  {               \
-    Curl_share_unlock(data, CURL_LOCK_DATA_DNS); \
-  }               \
-  return dns; \
+  dns->inuse = 0;
+  dns->addr = addr;
+
+  /* Store it in our dns cache */
+  Curl_hash_add(data->hostcache, entry_id, entry_len+1,
+                (const void *) dns);
+  time(&now);
+
+  dns->timestamp = now;
+  dns->inuse++;         /* mark entry as in-use */
+
+    
+  /* Remove outdated and unused entries from the hostcache */
+  hostcache_prune(data->hostcache, 
+                  data->set.dns_cache_timeout, 
+                  now);
+
+  /* free the allocated entry_id again */
+  free(entry_id);
+
+  return dns;
 }
 
-#ifdef HAVE_SIGSETJMP
-/* Beware this is a global and unique instance */
-sigjmp_buf curl_jmpenv;
-#endif
+/* Resolve a name and return a pointer in the 'entry' argument if one
+   is available.
 
-struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
-                                   char *hostname,
-                                   int port)
+   Return codes:
+
+   -1 = error, no pointer
+   0 = OK, pointer provided
+   1 = waiting for response, no pointer
+*/
+int Curl_resolv(struct connectdata *conn,
+                char *hostname,
+                int port,
+                struct Curl_dns_entry **entry)
 {
   char *entry_id = NULL;
   struct Curl_dns_entry *dns = NULL;
   ssize_t entry_len;
-  time_t now;
-  char *bufp;
+  int wait;
+  struct SessionHandle *data = conn->data;
+
+  /* default to failure */
+  int rc = -1;
+  *entry = NULL;
 
 #ifdef HAVE_SIGSETJMP
   /* this allows us to time-out from the name resolver, as the timeout
@@ -240,7 +284,7 @@ struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
   if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
     /* this is coming from a siglongjmp() */
     failf(data, "name lookup timed out");
-    return NULL;
+    return -1;
   }
 #endif
 
@@ -249,7 +293,7 @@ struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
   entry_id = create_hostcache_id(hostname, port, &entry_len);
   /* If we can't create the entry id, fail */
   if (!entry_id)
-    return NULL;
+    return -1;
 
   if(data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
@@ -257,39 +301,34 @@ struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
   /* See if its already in our dns cache */
   dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
 
+  /* free the allocated entry_id again */
+  free(entry_id);
+
   if (!dns) {
-    Curl_addrinfo *addr = my_getaddrinfo(data, hostname, port, &bufp);
+    /* The entry was not in the cache. Resolve it to IP address */
+      
+    /* If my_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
+       value indicating that we need to wait for the response to the resolve
+       call */
+    Curl_addrinfo *addr = my_getaddrinfo(conn, hostname, port, &wait);
     
     if (!addr) {
-      HOSTCACHE_RETURN(NULL);
+      if(wait)
+        /* the response to our resolve call will come asynchronously at 
+           a later time, good or bad */
+        rc = 1;
     }
-
-    /* Create a new cache entry */
-    dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
-    if (!dns) {
-      Curl_freeaddrinfo(addr);
-      HOSTCACHE_RETURN(NULL);
-    }
-
-    dns->inuse = 0;
-    dns->addr = addr;
-    /* Save it in our host cache */
-    Curl_hash_add(data->hostcache, entry_id, entry_len+1, (const void *) dns);
+    else
+      /* we got a response, store it in the cache */
+      dns = cache_resolv_response(data, addr, hostname, port);
   }
-  time(&now);
 
-  dns->timestamp = now;
-  dns->inuse++;         /* mark entry as in-use */
-#ifdef CURLDEBUG
-  dns->entry_id = entry_id;
-#endif
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
 
-  /* Remove outdated and unused entries from the hostcache */
-  hostcache_prune(data->hostcache, 
-                  data->set.dns_cache_timeout, 
-                  now);
+  *entry = dns;
 
-  HOSTCACHE_RETURN(dns);
+  return rc;
 }
 
 void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
@@ -314,7 +353,7 @@ void Curl_freeaddrinfo(Curl_addrinfo *p)
 #ifdef ENABLE_IPV6
   freeaddrinfo(p);
 #else
-  free(p);
+  free(p); /* works fine for the ARES case too */
 #endif
 }
 
@@ -332,7 +371,203 @@ void Curl_freednsinfo(void *freethis)
 
 /* --- resolve name or IP-number --- */
 
-#ifdef ENABLE_IPV6
+/* Allocate enough memory to hold the full name information structs and
+ * everything. OSF1 is known to require at least 8872 bytes. The buffer
+ * required for storing all possible aliases and IP numbers is according to
+ * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes!
+ */
+#define CURL_NAMELOOKUP_SIZE 9000
+
+#ifdef USE_ARES
+
+CURLcode Curl_multi_ares_fdset(struct connectdata *conn,
+                               fd_set *read_fd_set,
+                               fd_set *write_fd_set,
+                               int *max_fdp)
+
+{
+  int max = ares_fds(conn->data->state.areschannel,
+                     read_fd_set, write_fd_set);
+  *max_fdp = max;
+
+  return CURLE_OK;
+}
+
+/* called to check if the name is resolved now */
+CURLcode Curl_is_resolved(struct connectdata *conn, bool *done)
+{
+  fd_set read_fds, write_fds;
+  static const struct timeval tv={0,0};
+  int count;
+  struct SessionHandle *data = conn->data;
+  int nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
+
+  count = select(nfds, &read_fds, &write_fds, NULL,
+                 (struct timeval *)&tv);
+
+  if(count)
+    ares_process(data->state.areschannel, &read_fds, &write_fds);
+
+  if(conn->async.done) {
+    *done = TRUE;
+
+    if(!conn->async.dns)
+      return CURLE_COULDNT_RESOLVE_HOST;
+  }
+  else
+    *done = FALSE;
+
+  return CURLE_OK;
+}
+
+/* This is a function that locks and waits until the name resolve operation
+   has completed.
+
+   If 'entry' is non-NULL, make it point to the resolved dns entry
+
+   Return CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+   CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+*/
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+                              struct Curl_dns_entry **entry)
+{
+  CURLcode rc=CURLE_OK;
+  struct SessionHandle *data = conn->data;
+    
+  /* Wait for the name resolve query to complete. */
+  while (1) {
+    int nfds=0;
+    fd_set read_fds, write_fds;
+    struct timeval *tvp, tv;
+    int count;
+    
+    FD_ZERO(&read_fds);
+    FD_ZERO(&write_fds);
+    nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
+    if (nfds == 0)
+      break;
+    tvp = ares_timeout(data->state.areschannel,
+                       NULL, /* pass in our maximum time here */
+                       &tv);
+    count = select(nfds, &read_fds, &write_fds, NULL, tvp);
+    if (count < 0 && errno != EINVAL)
+      break;
+
+    ares_process(data->state.areschannel, &read_fds, &write_fds);
+  }
+
+  /* Operation complete, if the lookup was successful we now have the entry
+     in the cache. */
+    
+  /* this destroys the channel and we cannot use it anymore after this */
+  ares_destroy(data->state.areschannel);
+
+  if(entry)
+    *entry = conn->async.dns;
+
+  if(!conn->async.dns) {
+    /* a name was not resolved */
+    if(conn->async.done)
+      rc = CURLE_COULDNT_RESOLVE_HOST;
+    else
+      rc = CURLE_OPERATION_TIMEDOUT;
+
+    /* close the connection, since we can't return failure here without
+       cleaning up this connection properly */
+    Curl_disconnect(conn);
+  }
+  
+  return rc;
+}
+
+/* this function gets called by ares when we got the name resolved */
+static void host_callback(void *arg, /* "struct connectdata *" */
+                          int status,
+                          struct hostent *hostent)
+{
+  struct connectdata *conn = (struct connectdata *)arg;
+  struct Curl_dns_entry *dns = NULL;
+
+  conn->async.done = TRUE;
+  conn->async.status = status;
+
+  if(ARES_SUCCESS == status) {
+    /* we got a resolved name in 'hostent' */
+    char *bufp = (char *)malloc(CURL_NAMELOOKUP_SIZE);
+    if(bufp) {
+
+      /* pack_hostent() copies to and shrinks the target buffer */
+      struct hostent *he = pack_hostent(&bufp, hostent);
+
+      dns = cache_resolv_response(conn->data, he,
+                                  conn->async.hostname, conn->async.port);
+    }
+  }
+
+  conn->async.dns = dns;
+
+  /* The input hostent struct will be freed by ares when we return from this
+     function */
+}
+
+/*
+ * Return name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the forth argument will point to
+ * memory we need to free after use. That meory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+static Curl_addrinfo *my_getaddrinfo(struct connectdata *conn,
+                                     char *hostname,
+                                     int port,
+                                     int *waitp)
+{
+  int rc;
+  char *bufp;
+  struct SessionHandle *data = conn->data;
+
+  rc = ares_init(&data->state.areschannel);
+
+  *waitp = FALSE;
+  
+  if(!rc) {
+    /* only if success */
+
+    bufp = strdup(hostname);
+
+    if(bufp) {
+      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 */
+      
+      ares_gethostbyname(data->state.areschannel, hostname, PF_INET,
+                         host_callback, conn);
+
+      *waitp = TRUE; /* please wait for the response */      
+    }
+    else
+      ares_destroy(data->state.areschannel);
+  }
+
+  return NULL; /* no struct yet */
+  
+}
+#else
+/* For builds without ARES, Curl_resolv() can never return wait==TRUE,
+   so this function will never be called. If it still gets called, we
+   return failure at once. */
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+                              struct Curl_dns_entry **entry)
+{
+  (void)conn;
+  *entry=NULL;
+  return CURLE_COULDNT_RESOLVE_HOST;
+}
+#endif
+
+#if defined(ENABLE_IPV6) && !defined(USE_ARES)
 
 #ifdef CURLDEBUG
 /* These two are strictly for memory tracing and are using the same
@@ -377,15 +612,16 @@ void curl_freeaddrinfo(struct addrinfo *freethis,
  * memory we need to free after use. That meory *MUST* be freed with
  * Curl_freeaddrinfo(), nothing else.
  */
-static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
+static Curl_addrinfo *my_getaddrinfo(struct connectdata *conn,
                                      char *hostname,
                                      int port,
-                                     char **bufp)
+                                     int *waitp)
 {
   struct addrinfo hints, *res;
   int error;
   char sbuf[NI_MAXSERV];
   int s, pf = PF_UNSPEC;
+  struct SessionHandle *data = conn->data;
 
   /* see if we have an IPv6 stack */
   s = socket(PF_INET6, SOCK_DGRAM, 0);
@@ -410,20 +646,18 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
     infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);    
     return NULL;
   }
-  *bufp=(char *)res; /* make it point to the result struct */
+  *waitp=0; /* don't wait, we have the response now */
 
   return res;
 }
 #else /* following code is IPv4-only */
 
-#ifndef HAVE_GETHOSTBYNAME_R
+#if !defined(HAVE_GETHOSTBYNAME_R) || defined(USE_ARES)
 static void hostcache_fixoffset(struct hostent *h, int offset);
-/**
+/*
  * Performs a "deep" copy of a hostent into a buffer (returns a pointer to the
  * copy). Make absolutely sure the destination buffer is big enough!
- *
- * Keith McGuigan 
- * 10/3/2001 */
+ */
 static struct hostent* pack_hostent(char** buf, struct hostent* orig)
 {
   char *bufptr;
@@ -512,6 +746,25 @@ static struct hostent* pack_hostent(char** buf, struct hostent* orig)
 }
 #endif
 
+static void hostcache_fixoffset(struct hostent *h, int offset)
+{
+  int i=0;
+  h->h_name=(char *)((long)h->h_name+offset);
+  h->h_aliases=(char **)((long)h->h_aliases+offset);
+  while(h->h_aliases[i]) {
+    h->h_aliases[i]=(char *)((long)h->h_aliases[i]+offset);
+    i++;
+  }
+  h->h_addr_list=(char **)((long)h->h_addr_list+offset);
+  i=0;
+  while(h->h_addr_list[i]) {
+    h->h_addr_list[i]=(char *)((long)h->h_addr_list[i]+offset);
+    i++;
+  }
+}
+
+#ifndef USE_ARES
+
 static char *MakeIP(unsigned long num, char *addr, int addr_len)
 {
 #if defined(HAVE_INET_NTOA) || defined(HAVE_INET_NTOA_R)
@@ -533,43 +786,24 @@ static char *MakeIP(unsigned long num, char *addr, int addr_len)
   return (addr);
 }
 
-static void hostcache_fixoffset(struct hostent *h, int offset)
-{
-  int i=0;
-  h->h_name=(char *)((long)h->h_name+offset);
-  h->h_aliases=(char **)((long)h->h_aliases+offset);
-  while(h->h_aliases[i]) {
-    h->h_aliases[i]=(char *)((long)h->h_aliases[i]+offset);
-    i++;
-  }
-  h->h_addr_list=(char **)((long)h->h_addr_list+offset);
-  i=0;
-  while(h->h_addr_list[i]) {
-    h->h_addr_list[i]=(char *)((long)h->h_addr_list[i]+offset);
-    i++;
-  }
-}
-
 /* The original code to this function was once stolen from the Dancer source
    code, written by Bjorn Reese, it has since been patched and modified
    considerably. */
-static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
+static Curl_addrinfo *my_getaddrinfo(struct connectdata *conn,
                                      char *hostname,
                                      int port,
-                                     char **bufp)
+                                     int *waitp)
 {
   struct hostent *h = NULL;
   in_addr_t in;
   int ret; /* this variable is unused on several platforms but used on some */
+  struct SessionHandle *data = conn->data;
 
-#define CURL_NAMELOOKUP_SIZE 9000
-  /* Allocate enough memory to hold the full name information structs and
-   * everything. OSF1 is known to require at least 8872 bytes. The buffer
-   * required for storing all possible aliases and IP numbers is according to
-   * Stevens' Unix Network Programming 2nd editor, p. 304: 8192 bytes! */
-  port=0; /* unused in IPv4 code */
+  (void)port; /* unused in IPv4 code */
   ret = 0; /* to prevent the compiler warning */
 
+  *waitp = 0; /* don't wait, we act synchronously */
+
   in=inet_addr(hostname);
   if (in != CURL_INADDR_NONE) {
     struct in_addr *addrentry;
@@ -581,7 +815,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
     } *buf = (struct namebuf *)malloc(sizeof(struct namebuf));
     if(!buf)
       return NULL; /* major failure */
-    *bufp = (char *)buf;
 
     h = &buf->hostentry;
     h->h_addr_list = &buf->h_addr_list[0];
@@ -602,7 +835,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
     int *buf = (int *)malloc(CURL_NAMELOOKUP_SIZE);
     if(!buf)
       return NULL; /* major failure */
-    *bufp=(char *)buf;
 
      /* Workaround for gethostbyname_r bug in qnx nto. It is also _required_
         for some of these functions. */
@@ -638,7 +870,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
       offset=(long)h-(long)buf;
       hostcache_fixoffset(h, offset);
       buf=(int *)h;
-      *bufp=(char *)buf;
     }
     else
 #endif
@@ -687,7 +918,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
       offset=(long)h-(long)buf;
       hostcache_fixoffset(h, offset);
       buf=(int *)h;
-      *bufp=(char *)buf;
     }
     else
 #endif
@@ -730,13 +960,11 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
       infof(data, "gethostbyname_r(2) failed for %s\n", hostname);
       h = NULL; /* set return code to NULL */
       free(buf);
-      *bufp=NULL;
     }
 #else
   else {
     if ((h = gethostbyname(hostname)) == NULL ) {
       infof(data, "gethostbyname(2) failed for %s\n", hostname);
-      *bufp=NULL;
     }
     else 
     {
@@ -745,7 +973,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
          static one we got a pointer to might get removed when we don't
          want/expect that */
       h = pack_hostent(&buf, h);
-      *bufp=(char *)buf;
     }
 #endif
   }
@@ -753,3 +980,5 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
 }
 
 #endif /* end of IPv4-specific code */
+
+#endif /* end of !USE_ARES */
index 36828ee1b169a22835db3f238557b4d48c5efc1a..2f53f4f16ff3b6288dc345905a40630395d17c4c 100644 (file)
@@ -29,6 +29,7 @@
 struct addrinfo;
 struct hostent;
 struct SessionHandle;
+struct connectdata;
 
 void Curl_global_host_cache_init(void);
 void Curl_global_host_cache_dtor(void);
@@ -41,9 +42,6 @@ struct Curl_dns_entry {
   time_t timestamp;
   long inuse;      /* use-counter, make very sure you decrease this
                       when you're done using the address you received */
-#ifdef CURLDEBUG
-  char *entry_id;
-#endif
 };
 
 /*
@@ -54,10 +52,18 @@ struct Curl_dns_entry {
  * use, or we'll leak memory!
  */
 
-struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
-                                   char *hostname,
-                                   int port);
+int Curl_resolv(struct connectdata *conn,
+                char *hostname,
+                int port,
+                struct Curl_dns_entry **dnsentry);
 
+CURLcode Curl_is_resolved(struct connectdata *conn, bool *done);
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+                              struct Curl_dns_entry **dnsentry);
+CURLcode Curl_multi_ares_fdset(struct connectdata *conn,
+                               fd_set *read_fd_set,
+                               fd_set *write_fd_set,
+                               int *max_fdp);
 /* unlock a previously resolved dns entry */
 void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns);
 
index f6749f18f5cd7fb68702efdae8bea58a65624913..0d2fcf7ff38bdbcab6c9f538052a439f5144ebc9 100644 (file)
@@ -56,7 +56,8 @@ struct Curl_message {
 
 typedef enum {
   CURLM_STATE_INIT,
-  CURLM_STATE_CONNECT,     /* connect has been sent off */
+  CURLM_STATE_CONNECT,     /* resolve/connect has been sent off */
+  CURLM_STATE_WAITRESOLVE, /* we're awaiting the resolve to finalize */
   CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
   CURLM_STATE_DO,          /* send off the request (part 1) */
   CURLM_STATE_DO_MORE,     /* send off the request (part 2) */
@@ -239,6 +240,14 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
     switch(easy->state) {
     default:
       break;
+    case CURLM_STATE_WAITRESOLVE:
+      /* waiting for a resolve to complete */
+      Curl_multi_ares_fdset(easy->easy_conn, read_fd_set, write_fd_set,
+                            &this_max_fd);
+      if(this_max_fd > *max_fd)
+        *max_fd = this_max_fd;
+      break;
+
     case CURLM_STATE_WAITCONNECT:
     case CURLM_STATE_DO_MORE:
       {
@@ -293,6 +302,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
   CURLMcode result=CURLM_OK;
   struct Curl_message *msg = NULL;
   bool connected;
+  bool async;
 
   *running_handles = 0; /* bump this once for every living handle */
 
@@ -320,6 +330,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
         easy->easy_handle->state.used_interface = Curl_if_multi;
       }
       break;
+
     case CURLM_STATE_CONNECT:
       if (Curl_global_host_cache_use(easy->easy_handle)) {
         easy->easy_handle->hostcache = Curl_global_host_cache_get();
@@ -333,16 +344,46 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
 
       /* Connect. We get a connection identifier filled in. */
       Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
-      easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
+      easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn, &async);
 
-      /* after the connect has been sent off, go WAITCONNECT */
       if(CURLE_OK == easy->result) {
-        easy->state = CURLM_STATE_WAITCONNECT;
-        result = CURLM_CALL_MULTI_PERFORM; 
+        if(async)
+          /* We're now waiting for an asynchronous name lookup */
+          easy->state = CURLM_STATE_WAITRESOLVE;
+        else {
+          /* after the connect has been sent off, go WAITCONNECT */
+          easy->state = CURLM_STATE_WAITCONNECT;
+          result = CURLM_CALL_MULTI_PERFORM;
+        }
+      }
+      break;
+
+    case CURLM_STATE_WAITRESOLVE:
+      /* awaiting an asynch name resolve to complete */
+      {
+        bool done;
+
+        /* check if we have the name resolved by now */
+        easy->result = Curl_is_resolved(easy->easy_conn, &done);
+
+        if(done) {
+          /* Perform the next step in the connection phase, and then move on
+             to the WAITCONNECT state */
+          easy->result = Curl_async_resolved(easy->easy_conn);
+
+          easy->state = CURLM_STATE_WAITCONNECT;
+        }
+        
+        if(CURLE_OK != easy->result) {
+          /* failure detected */
+          easy->easy_conn = NULL;           /* no more connection */
+          break;
+        }
       }
       break;
 
     case CURLM_STATE_WAITCONNECT:
+      /* awaiting a completion of an asynch connect */
       {
         bool connected;
         easy->result = Curl_is_connected(easy->easy_conn,
index 4af61f97e38b09bdae183913dafc20519ba7b620..ef1514505eec7e9787b4b5631fe39319ff89621f 100644 (file)
@@ -185,7 +185,7 @@ int fileno( FILE *stream);
  * Information regarding a single IP witin a Curl_addrinfo MUST be stored in
  * a Curl_ipconnect struct.
  */
-#ifdef ENABLE_IPV6
+#if defined(ENABLE_IPV6) && !defined(USE_ARES)
 typedef struct addrinfo Curl_addrinfo;
 typedef struct addrinfo Curl_ipconnect;
 #else
index 445975b0aab9ca9b4d5d636adabc996ee2645810..c4b1c90faf3469a6cc96ade019688a84314f8004 100644 (file)
@@ -605,8 +605,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
                 len = end-start+1;
               
                 /* allocate memory of a cloned copy */
-                if(data->info.contenttype)
-                  free(data->info.contenttype);
+                Curl_safefree(data->info.contenttype);
               
                 data->info.contenttype = malloc(len + 1);
                 if (NULL == data->info.contenttype)
@@ -1903,10 +1902,22 @@ CURLcode Curl_perform(struct SessionHandle *data)
   do {  
     int urlchanged = FALSE;
     do {
+      bool async;
       Curl_pgrsTime(data, TIMER_STARTSINGLE);
       data->change.url_changed = FALSE;
-      res = Curl_connect(data, &conn);
+      res = Curl_connect(data, &conn, &async);
 
+      if((CURLE_OK == res) && async) {
+        /* Now, if async is TRUE here, we need to wait for the name
+           to resolve */
+        res = Curl_wait_for_resolv(conn, NULL);
+        if(CURLE_OK == res)
+          /* Resolved, continue with the connection */
+          res = Curl_async_resolved(conn);              
+      }
+      if(res)
+        break;
+      
       /* If a callback (or something) has altered the URL we should use within
          the Curl_connect(), we detect it here and act as if we are redirected
          to the new URL */
index f1095bceeb71ed62234b10ca8d46e1fc6a0a3394..84f3bbb0f6f64e00aa1bee05ebc7982aa96f2f52 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -147,7 +147,11 @@ static unsigned int ConnectionStore(struct SessionHandle *data,
                                     struct connectdata *conn);
 static bool safe_strequal(char* str1, char* str2);
 
-#if !defined(WIN32)||defined(__CYGWIN32__)
+#ifndef USE_ARES
+/* not for Win32, unless it is cygwin
+   not for ares builds */
+#if !defined(WIN32) || defined(__CYGWIN32__)
+
 #ifndef RETSIGTYPE
 #define RETSIGTYPE void
 #endif
@@ -165,6 +169,7 @@ RETSIGTYPE alarmfunc(int signal)
   return;
 }
 #endif
+#endif /* USE_ARES */
 
 void Curl_safefree(void *ptr)
 {
@@ -1286,7 +1291,11 @@ CURLcode Curl_disconnect(struct connectdata *conn)
   Curl_safefree(conn->allocptr.host);
   Curl_safefree(conn->allocptr.cookiehost);
   Curl_safefree(conn->proxyhost);
-
+#ifdef USE_ARES
+  /* possible left-overs from the async name resolve */
+  Curl_safefree(conn->async.hostname);
+#endif
+  
   Curl_free_ssl_config(&conn->ssl_config);
 
   free(conn); /* free all the connection oriented data */
@@ -1632,7 +1641,15 @@ static int handleSock5Proxy(
 #ifndef ENABLE_IPV6
     struct Curl_dns_entry *dns;
     Curl_addrinfo *hp=NULL;
-    dns = Curl_resolv(conn->data, conn->hostname, conn->remote_port);
+    int rc = Curl_resolv(conn, conn->hostname, conn->remote_port, &dns);
+    
+    if(rc == -1)
+      return CURLE_COULDNT_RESOLVE_HOST;
+
+    if(rc == 1)
+      /* this requires that we're in "wait for resolve" state */
+      rc = Curl_wait_for_resolv(conn, &dns);
+    
     /*
      * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
      * returns a Curl_addrinfo pointer that may not always look the same.
@@ -1841,8 +1858,19 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
   return result; /* pass back status */
 }
 
+/*
+ * CreateConnection() sets up a new connectdata struct, or re-uses an already
+ * existing one, and resolves host name.
+ *
+ * if this function returns CURLE_OK and *async is set to TRUE, the resolve
+ * response will be coming asynchronously. If *async is FALSE, the name is
+ * already resolved.
+ */
+
 static CURLcode CreateConnection(struct SessionHandle *data,
-                                 struct connectdata **in_connect)
+                                 struct connectdata **in_connect,
+                                 struct Curl_dns_entry **addr,
+                                 bool *async)
 {
   char *tmp;
   CURLcode result=CURLE_OK;
@@ -1859,7 +1887,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
   char passwd[MAX_CURL_PASSWORD_LENGTH];
   bool passwdgiven=FALSE; /* set TRUE if an application-provided password has
                              been set */
-
+  int rc;
 
 #ifdef HAVE_SIGACTION
   struct sigaction keep_sigact;   /* store the old struct here */
@@ -1870,6 +1898,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
 #endif
 #endif
 
+  *addr = NULL; /* nothing yet */
+  *async = FALSE;
+  
   /*************************************************************
    * Check input data
    *************************************************************/
@@ -2875,8 +2906,10 @@ static CURLcode CreateConnection(struct SessionHandle *data,
   /* else, no chunky upload */
   FALSE;
 
+#ifndef USE_ARES
   /*************************************************************
-   * Set timeout if that is being used
+   * Set timeout if that is being used, and we're not using an asynchronous
+   * name resolve.
    *************************************************************/
   if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
     /*************************************************************
@@ -2919,7 +2952,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
        has been done since then until now. */
 #endif
   }
-
+#endif
+  
   /*************************************************************
    * Resolve the name of the server or proxy
    *************************************************************/
@@ -2935,9 +2969,11 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     conn->port =  conn->remote_port; /* it is the same port */
 
     /* Resolve target host right on */
-    hostaddr = Curl_resolv(data, conn->name, conn->port);
+    rc = Curl_resolv(conn, conn->name, conn->port, &hostaddr);
+    if(rc == 1)
+      *async = TRUE;
 
-    if(!hostaddr) {
+    else if(!hostaddr) {
       failf(data, "Couldn't resolve host '%s'", conn->name);
       result =  CURLE_COULDNT_RESOLVE_HOST;
       /* don't return yet, we need to clean up the timeout first */
@@ -2947,15 +2983,19 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     /* This is a proxy that hasn't been resolved yet. */
 
     /* resolve proxy */
-    hostaddr = Curl_resolv(data, conn->proxyhost, conn->port);
+    rc = Curl_resolv(conn, conn->proxyhost, conn->port, &hostaddr);
+
+    if(rc == 1)
+      *async = TRUE;
 
-    if(!hostaddr) {
+    else if(!hostaddr) {
       failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost);
       result = CURLE_COULDNT_RESOLVE_PROXY;
       /* don't return yet, we need to clean up the timeout first */
     }
   }
-  Curl_pgrsTime(data, TIMER_NAMELOOKUP);
+  *addr = hostaddr;
+
 #ifdef HAVE_ALARM
   if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
 #ifdef HAVE_SIGACTION
@@ -2995,7 +3035,25 @@ static CURLcode CreateConnection(struct SessionHandle *data,
       alarm(0); /* just shut it off */
   }
 #endif
-  if(result)
+
+  return result;
+}
+
+/* SetupConnection() should be called after the name resolve initiated in
+ * CreateConnection() is all done.
+ */
+static CURLcode SetupConnection(struct connectdata *conn,
+                                struct Curl_dns_entry *hostaddr)
+{
+  struct SessionHandle *data = conn->data;
+  CURLcode result=CURLE_OK;
+
+  Curl_pgrsTime(data, TIMER_NAMELOOKUP);
+
+  if(conn->protocol & PROT_FILE)
+    /* There's nothing in this function to setup if we're only doing
+       a file:// transfer */
     return result;
 
   /*************************************************************
@@ -3007,8 +3065,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
              conn->proxyuser, conn->proxypasswd);
     if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
                           &authorization) >= 0) {
-      if(conn->allocptr.proxyuserpwd)
-        free(conn->allocptr.proxyuserpwd);
+      Curl_safefree(conn->allocptr.proxyuserpwd);
       conn->allocptr.proxyuserpwd =
         aprintf("Proxy-authorization: Basic %s\015\012", authorization);
       free(authorization);
@@ -3022,16 +3079,14 @@ static CURLcode CreateConnection(struct SessionHandle *data,
   if((conn->protocol&PROT_HTTP) ||
      (data->change.proxy && *data->change.proxy)) {
     if(data->set.useragent) {
-      if(conn->allocptr.uagent)
-        free(conn->allocptr.uagent);
+      Curl_safefree(conn->allocptr.uagent);
       conn->allocptr.uagent =
         aprintf("User-Agent: %s\015\012", data->set.useragent);
     }
   }
 
   if(data->set.encoding) {
-    if(conn->allocptr.accept_encoding)
-      free(conn->allocptr.accept_encoding);
+    Curl_safefree(conn->allocptr.accept_encoding);
     conn->allocptr.accept_encoding =
       aprintf("Accept-Encoding: %s\015\012", data->set.encoding);
   }
@@ -3083,26 +3138,60 @@ static CURLcode CreateConnection(struct SessionHandle *data,
 }
 
 CURLcode Curl_connect(struct SessionHandle *data,
-                      struct connectdata **in_connect)
+                      struct connectdata **in_connect,
+                      bool *asyncp)
 {
   CURLcode code;
-  struct connectdata *conn;
+  struct Curl_dns_entry *dns;
 
+  *asyncp = FALSE; /* assume synchronous resolves by default */
+  
   /* call the stuff that needs to be called */
-  code = CreateConnection(data, in_connect);
-
+  code = CreateConnection(data, in_connect, &dns, asyncp);
+
+  if(CURLE_OK == code) {
+    /* no error */
+    if(dns || !*asyncp)
+      /* If an address is available it means that we already have the name
+         resolved, OR it isn't async.
+         If so => continue connecting from here */
+      code = SetupConnection(*in_connect, dns);
+    /* else
+         response will be received and treated async wise */
+  }
+  
   if(CURLE_OK != code) {
     /* We're not allowed to return failure with memory left allocated
        in the connectdata struct, free those here */
-    conn = (struct connectdata *)*in_connect;
-    if(conn) {
-      Curl_disconnect(conn);      /* close the connection */
-      *in_connect = NULL;         /* return a NULL */
+    if(*in_connect) {
+      Curl_disconnect(*in_connect); /* close the connection */
+      *in_connect = NULL;           /* return a NULL */
     }
   }
+
   return code;
 }
 
+/* Call this function after Curl_connect() has returned async=TRUE and
+   then a successful name resolve has been received */
+CURLcode Curl_async_resolved(struct connectdata *conn)
+{
+#ifdef USE_ARES
+  CURLcode code = SetupConnection(conn, conn->async.dns);
+
+  if(code)
+    /* We're not allowed to return failure with memory left allocated
+       in the connectdata struct, free those here */
+    Curl_disconnect(conn); /* close the connection */
+
+  return code;
+#else
+  (void)conn;
+  return CURLE_OK;
+#endif
+}
+
+
 CURLcode Curl_done(struct connectdata *conn)
 {
   struct SessionHandle *data=conn->data;
@@ -3179,11 +3268,28 @@ CURLcode Curl_do(struct connectdata **connp)
       conn->bits.close = TRUE; /* enforce close of this connetion */
       result = Curl_done(conn);   /* we are so done with this */
       if(CURLE_OK == result) {
+        bool async;
         /* Now, redo the connect and get a new connection */
-        result = Curl_connect(data, connp);
-        if(CURLE_OK == result)
+        result = Curl_connect(data, connp, &async);
+        if(CURLE_OK == result) {
+          /* We have connected or sent away a name resolve query fine */
+
+          if(async) {
+            /* Now, if async is TRUE here, we need to wait for the name
+               to resolve */
+            result = Curl_wait_for_resolv(conn, NULL);
+            if(result)
+              return result;
+            
+            /* Resolved, continue with the connection */
+            result = Curl_async_resolved(conn);              
+            if(result)
+              return result;
+          }
+          
           /* ... finally back to actually retry the DO phase */
-          result = conn->curl_do(*connp);
+          result = conn->curl_do(conn);
+        }
       }
     }
   }
index 59ac39058781ad340a62213517f1c2b452dd7b00..002b112492b3979032c3cd19dfe0a3f75b4f9f34 100644 (file)
--- a/lib/url.h
+++ b/lib/url.h
@@ -30,7 +30,9 @@
 CURLcode Curl_open(struct SessionHandle **curl);
 CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
 CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
-CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);
+CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
+                      bool *async);
+CURLcode Curl_async_resolved(struct connectdata *conn);
 CURLcode Curl_do(struct connectdata **);
 CURLcode Curl_do_more(struct connectdata *);
 CURLcode Curl_done(struct connectdata *);
index 165b90fe101488b5905f9d7516753915f69bbb35..0218935abebc721377995d7373299c8ddc98280d 100644 (file)
 #include <gssapi.h>
 #endif
 
+#ifdef USE_ARES
+#include <ares.h>
+#endif
+
 /* Download buffer size, keep it fairly big for speed reasons */
 #define BUFSIZE CURL_MAX_WRITE_SIZE
 
@@ -364,6 +368,16 @@ struct Curl_transfer_keeper {
   bool ignorebody;  /* we read a response-body but we ignore it! */
 };
 
+#ifdef USE_ARES
+struct Curl_async {
+  char *hostname;
+  int port;
+  struct Curl_dns_entry *dns;
+  bool done;  /* set TRUE when the lookup is complete */
+  int status; /* if done is TRUE, this is the status from the callback */
+};
+#endif
+
 /*
  * The connectdata struct contains all fields and variables that should be
  * unique for an entire connection.
@@ -538,6 +552,11 @@ struct connectdata {
                                because it authenticates connections, not
                                single requests! */
   struct ntlmdata proxyntlm; /* NTLM data for proxy */
+
+#ifdef USE_ARES
+  /* data used for the asynch name resolve callback */
+  struct Curl_async async;
+#endif
 };
 
 /* The end of connectdata. */
@@ -669,6 +688,10 @@ struct UrlState {
 
   long authwant;  /* inherited from what the user set with CURLOPT_HTTPAUTH */
   long authavail; /* what the server reports */
+
+#ifdef USE_ARES
+  ares_channel areschannel; /* for name resolves */
+#endif
 };