From 80f1730de4edaf8e7d1ff8fc3a4524e4a53a1ea2 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Mon, 31 Jan 2011 00:10:35 +0100
Subject: [PATCH 3/3] async resolvers: further cleanups

I've continued to push towards making asyn-ares.c and asyn-thread.c two
implementations that both provide the internal API defined in asyn.h for
asynch resolvers.
---
 lib/Makefile.inc  |    6 +-
 lib/asyn-ares.c   |  610 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/asyn-thread.c |  645 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/asyn.h        |  169 ++++++++++++++
 lib/connect.c     |    2 +-
 lib/ftp.c         |    6 +-
 lib/hostares.c    |  605 -------------------------------------------------
 lib/hostasyn.c    |   39 ++++
 lib/hostip.c      |    4 +-
 lib/hostip.h      |   70 +------
 lib/hostsyn.c     |  102 ---------
 lib/hostthre.c    |  642 ----------------------------------------------------
 lib/multi.c       |    4 +-
 lib/socks.c       |    4 +-
 lib/transfer.c    |    4 +-
 lib/url.c         |   70 ++-----
 lib/url.h         |    4 +-
 17 files changed, 1500 insertions(+), 1486 deletions(-)
 create mode 100644 lib/asyn-ares.c
 create mode 100644 lib/asyn-thread.c
 create mode 100644 lib/asyn.h
 delete mode 100644 lib/hostares.c
 delete mode 100644 lib/hostthre.c

diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index a71900b..f0657ee 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -21,7 +21,8 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c	\
   socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c		\
   curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c	\
   warnless.c hmac.c polarssl.c curl_rtmp.c openldap.c curl_gethostname.c\
-  gopher.c axtls.c idn_win32.c http_negotiate_sspi.c cyassl.c
+  gopher.c axtls.c idn_win32.c http_negotiate_sspi.c cyassl.c           \
+  asyn-ares.c asyn-thread.c
 
 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\
   progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h	\
@@ -36,5 +37,6 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\
   curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h	\
   curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h	\
   warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h      \
-  gopher.h axtls.h cyassl.h
+  gopher.h axtls.h cyassl.h asyn.h
+
 
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c
new file mode 100644
index 0000000..6b71e03
--- /dev/null
+++ b/lib/asyn-ares.c
@@ -0,0 +1,610 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+/***********************************************************************
+ * Only for ares-enabled builds
+ * And only for functions that fulfill the asynch resolver backend API
+ * as defined in asyn.h, nothing else belongs in this file!
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
+#include "progress.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
+     (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
+#    define CARES_STATICLIB
+#  endif
+#  include <ares.h>
+
+#if ARES_VERSION >= 0x010500
+/* c-ares 1.5.0 or later, the callback proto is modified */
+#define HAVE_CARES_CALLBACK_TIMEOUTS 1
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct ResolverResults {
+  int num_pending; /* number of ares_gethostbyname() requests */
+  Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
+  int last_status;
+};
+
+/*
+ * Curl_resolver_global_init() - the generic low-level asynchronous name
+ * resolve API.  Called from curl_global_init() to initialize global resolver
+ * environment.  Initializes ares library.
+ */
+int Curl_resolver_global_init(void)
+{
+#ifdef CARES_HAVE_ARES_LIBRARY_INIT
+  if(ares_library_init(ARES_LIB_INIT_ALL)) {
+    return CURLE_FAILED_INIT;
+  }
+#endif
+  return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_global_cleanup()
+ *
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Deinitializes ares library.
+ */
+void Curl_resolver_global_cleanup(void)
+{
+#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
+  ares_library_cleanup();
+#endif
+}
+
+/*
+ * Curl_resolver_init()
+ *
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Fills the passed pointer by the initialized ares_channel.
+ */
+int Curl_resolver_init(void **resolver)
+{
+  int status = ares_init((ares_channel*)resolver);
+  if(status != ARES_SUCCESS) {
+    if(status == ARES_ENOMEM)
+      return CURLE_OUT_OF_MEMORY;
+    else
+      return CURLE_FAILED_INIT;
+  }
+  return CURLE_OK;
+  /* make sure that all other returns from this function should destroy the
+     ares channel before returning error! */
+}
+
+/*
+ * Curl_resolver_cleanup()
+ *
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Destroys the ares channel.
+ */
+void Curl_resolver_cleanup(void *resolver)
+{
+  ares_destroy((ares_channel)resolver);
+}
+
+/*
+ * Curl_resolver_duphandle()
+ *
+ * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
+ * environment ('resolver' member of the UrlState structure).  Duplicates the
+ * 'from' ares channel and passes the resulting channel to the 'to' pointer.
+ */
+int Curl_resolver_duphandle(void **to, void *from)
+{
+  /* Clone the ares channel for the new handle */
+  if(ARES_SUCCESS != ares_dup((ares_channel*)to,(ares_channel)from))
+    return CURLE_FAILED_INIT;
+  return CURLE_OK;
+}
+
+static void destroy_async_data (struct Curl_async *async);
+
+/*
+ * Cancel all possibly still on-going resolves for this connection.
+ */
+void Curl_resolver_cancel(struct connectdata *conn)
+{
+  if( conn && conn->data && conn->data->state.resolver )
+    ares_cancel((ares_channel)conn->data->state.resolver);
+  destroy_async_data(&conn->async);
+}
+
+/*
+ * destroy_async_data() cleans up async resolver data.
+ */
+static void destroy_async_data (struct Curl_async *async)
+{
+  if(async->hostname)
+    free(async->hostname);
+
+  if(async->os_specific) {
+    struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
+    if( res ) {
+      if( res->temp_ai ) {
+        Curl_freeaddrinfo(res->temp_ai);
+        res->temp_ai = NULL;
+      }
+      free(res);
+    }
+    async->os_specific = NULL;
+  }
+
+  async->hostname = NULL;
+}
+
+/*
+ * Curl_resolver_fdset() is called when someone from the outside world (using
+ * curl_multi_fdset()) wants to get our fd_set setup and we're talking with
+ * ares. The caller must make sure that this function is only called when we
+ * have a working ares channel.
+ *
+ * Returns: CURLE_OK always!
+ */
+
+int Curl_resolver_getsock(struct connectdata *conn,
+                          curl_socket_t *socks,
+                          int numsocks)
+
+{
+  struct timeval maxtime;
+  struct timeval timebuf;
+  struct timeval *timeout;
+  int max = ares_getsock((ares_channel)conn->data->state.resolver,
+                         (ares_socket_t *)socks, numsocks);
+
+
+  maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
+  maxtime.tv_usec = 0;
+
+  timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
+                         &timebuf);
+
+  Curl_expire(conn->data,
+              (timeout->tv_sec * 1000) + (timeout->tv_usec/1000));
+
+  return max;
+}
+
+/*
+ * waitperform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on
+ */
+
+static int waitperform(struct connectdata *conn, int timeout_ms)
+{
+  struct SessionHandle *data = conn->data;
+  int nfds;
+  int bitmask;
+  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+  int i;
+  int num = 0;
+
+  bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
+                         ARES_GETSOCK_MAXNUM);
+
+  for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
+    pfd[i].events = 0;
+    pfd[i].revents = 0;
+    if(ARES_GETSOCK_READABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLRDNORM|POLLIN;
+    }
+    if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLWRNORM|POLLOUT;
+    }
+    if(pfd[i].events != 0)
+      num++;
+    else
+      break;
+  }
+
+  if(num)
+    nfds = Curl_poll(pfd, num, timeout_ms);
+  else
+    nfds = 0;
+
+  if(!nfds)
+    /* Call ares_process() unconditonally here, even if we simply timed out
+       above, as otherwise the ares name resolve won't timeout! */
+    ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
+                    ARES_SOCKET_BAD);
+  else {
+    /* move through the descriptors and ask for processing on them */
+    for(i=0; i < num; i++)
+      ares_process_fd((ares_channel)data->state.resolver,
+                      pfd[i].revents & (POLLRDNORM|POLLIN)?
+                      pfd[i].fd:ARES_SOCKET_BAD,
+                      pfd[i].revents & (POLLWRNORM|POLLOUT)?
+                      pfd[i].fd:ARES_SOCKET_BAD);
+  }
+  return nfds;
+}
+
+/*
+ * Curl_resolver_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+                                   struct Curl_dns_entry **dns)
+{
+  struct SessionHandle *data = conn->data;
+  struct ResolverResults *res = (struct ResolverResults *)
+    conn->async.os_specific;
+
+  *dns = NULL;
+
+  waitperform(conn, 0);
+
+  if( res && !res->num_pending ) {
+    (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
+    /* temp_ai ownership is moved to the connection, so we need not free-up
+       them */
+    res->temp_ai = NULL;
+    destroy_async_data(&conn->async);
+    if(!conn->async.dns) {
+      failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
+            ares_strerror(conn->async.status));
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+    *dns = conn->async.dns;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+                                   struct Curl_dns_entry **entry)
+{
+  CURLcode rc=CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  long timeout;
+  struct timeval now = Curl_tvnow();
+  struct Curl_dns_entry *temp_entry;
+
+  timeout = Curl_timeleft(data, &now, TRUE);
+  if(!timeout)
+    timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
+
+  /* Wait for the name resolve query to complete. */
+  for(;;) {
+    struct timeval *tvp, tv, store;
+    long timediff;
+    int itimeout;
+    int timeout_ms;
+
+    itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
+
+    store.tv_sec = itimeout/1000;
+    store.tv_usec = (itimeout%1000)*1000;
+
+    tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
+
+    /* use the timeout period ares returned to us above if less than one
+       second is left, otherwise just use 1000ms to make sure the progress
+       callback gets called frequent enough */
+    if(!tvp->tv_sec)
+      timeout_ms = (int)(tvp->tv_usec/1000);
+    else
+      timeout_ms = 1000;
+
+    waitperform(conn, timeout_ms);
+    Curl_resolver_is_resolved(conn,&temp_entry);
+
+    if(conn->async.done)
+      break;
+
+    if(Curl_pgrsUpdate(conn)) {
+      rc = CURLE_ABORTED_BY_CALLBACK;
+      timeout = -1; /* trigger the cancel below */
+    }
+    else {
+      struct timeval now2 = Curl_tvnow();
+      timediff = Curl_tvdiff(now2, now); /* spent time */
+      timeout -= timediff?timediff:1; /* always deduct at least 1 */
+      now = now2; /* for next loop */
+    }
+    if(timeout < 0) {
+      /* our timeout, so we cancel the ares operation */
+      ares_cancel((ares_channel)data->state.resolver);
+      break;
+    }
+  }
+
+  /* Operation complete, if the lookup was successful we now have the entry
+     in the cache. */
+
+  if(entry)
+    *entry = conn->async.dns;
+
+  if(!conn->async.dns) {
+    /* a name was not resolved */
+    if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
+      if (conn->bits.httpproxy) {
+        failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname);
+        rc = CURLE_COULDNT_RESOLVE_PROXY;
+      }
+      else {
+        failf(data, "Resolving host timed out: %s", conn->host.dispname);
+        rc = CURLE_COULDNT_RESOLVE_HOST;
+      }
+    }
+    else if(conn->async.done) {
+      if (conn->bits.httpproxy) {
+        failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname,
+              ares_strerror(conn->async.status));
+        rc = CURLE_COULDNT_RESOLVE_PROXY;
+      }
+      else {
+        failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
+              ares_strerror(conn->async.status));
+        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 */
+    conn->bits.close = TRUE;
+  }
+
+  return rc;
+}
+
+/* Connects results to the list */
+static void compound_results(struct ResolverResults *res,
+                             Curl_addrinfo *ai)
+{
+  Curl_addrinfo *ai_tail;
+  if(!ai)
+    return;
+  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 = res->temp_ai;
+  res->temp_ai = ai;
+}
+
+/*
+ * ares_query_completed_cb() is the callback that ares will call when
+ * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
+ * when using ares, is completed either successfully or with failure.
+ */
+static void query_completed_cb(void *arg,  /* (struct connectdata *) */
+                               int status,
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+                               int timeouts,
+#endif
+                               struct hostent *hostent)
+{
+  struct connectdata *conn = (struct connectdata *)arg;
+  struct ResolverResults *res;
+
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+  (void)timeouts; /* ignored */
+#endif
+
+  if(ARES_EDESTRUCTION == status)
+    /* when this ares handle is getting destroyed, the 'arg' pointer may not
+       be valid so only defer it when we know the 'status' says its fine! */
+    return;
+
+  res = (struct ResolverResults *)conn->async.os_specific;
+  res->num_pending--;
+
+  if(CURL_ASYNC_SUCCESS == status) {
+    Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
+    if(ai) {
+      compound_results(res, ai);
+    }
+  }
+  /* A successful result overwrites any previous error */
+  if( res->last_status != ARES_SUCCESS )
+    res->last_status = status;
+}
+
+/*
+ * Curl_resolver_getaddrinfo() - when using ares
+ *
+ * Returns 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 memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+                                         const char *hostname,
+                                         int port,
+                                         int *waitp)
+{
+  char *bufp;
+  struct SessionHandle *data = conn->data;
+  struct in_addr in;
+  int family = PF_INET;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+  struct in6_addr in6;
+#endif /* CURLRES_IPV6 */
+
+  *waitp = 0; /* default to synchronous response */
+
+  /* First check if this is an IPv4 address string */
+  if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(AF_INET, &in, hostname, port);
+  }
+
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+  /* Otherwise, check if this is an IPv6 address string */
+  if (Curl_inet_pton (AF_INET6, hostname, &in6) > 0) {
+    /* This must be an IPv6 address literal.  */
+    return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+  }
+
+  switch(conn->ip_version) {
+  default:
+#if ARES_VERSION >= 0x010601
+    family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
+                           c-ares versions this just falls through and defaults
+                           to PF_INET */
+    break;
+#endif
+  case CURL_IPRESOLVE_V4:
+    family = PF_INET;
+    break;
+  case CURL_IPRESOLVE_V6:
+    family = PF_INET6;
+    break;
+  }
+#endif /* CURLRES_IPV6 */
+
+  bufp = strdup(hostname);
+  if(bufp) {
+    struct ResolverResults *res = NULL;
+    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 */
+    res = (struct ResolverResults *)calloc(sizeof(struct ResolverResults),1);
+    if( !res ) {
+      Curl_safefree(conn->async.hostname);
+      conn->async.hostname = NULL;
+      return NULL;
+    }
+    conn->async.os_specific = res;
+
+    /* initial status - failed */
+    res->last_status = ARES_ENOTFOUND;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+    if(family == PF_UNSPEC) {
+      res->num_pending = 2;
+
+      /* areschannel is already setup in the Curl_open() function */
+      ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET,
+                         query_completed_cb, conn);
+      ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET6,
+                         query_completed_cb, conn);
+    }
+    else
+#endif /* CURLRES_IPV6 */
+    {
+      res->num_pending = 1;
+
+      /* areschannel is already setup in the Curl_open() function */
+      ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
+                         query_completed_cb, conn);
+    }
+
+    *waitp = 1; /* expect asynchronous response */
+  }
+  return NULL; /* no struct yet */
+}
+#endif /* CURLRES_ARES */
diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c
new file mode 100644
index 0000000..e93dcbc
--- /dev/null
+++ b/lib/asyn-thread.c
@@ -0,0 +1,645 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+
+#if defined(USE_THREADS_POSIX)
+#  ifdef HAVE_PTHREAD_H
+#    include <pthread.h>
+#  endif
+#elif defined(USE_THREADS_WIN32)
+#  ifdef HAVE_PROCESS_H
+#    include <process.h>
+#  endif
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_pton.h"
+#include "inet_ntop.h"
+#include "curl_threads.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for threaded name resolves builds
+ **********************************************************************/
+#ifdef CURLRES_THREADED
+
+/*
+ * Curl_resolver_global_init()
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Does nothing here.
+ */
+int Curl_resolver_global_init(void)
+{
+  return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Does nothing here.
+ */
+void Curl_resolver_global_cleanup(void)
+{
+}
+
+/*
+ * Curl_resolver_init()
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Does nothing here.
+ */
+int Curl_resolver_init(void **resolver)
+{
+  (void)resolver;
+  return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_cleanup()
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Does nothing here.
+ */
+void Curl_resolver_cleanup(void *resolver)
+{
+  (void)resolver;
+}
+
+/*
+ * Curl_resolver_duphandle()
+ * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
+ * environment ('resolver' member of the UrlState structure).  Does nothing
+ * here.
+ */
+int Curl_resolver_duphandle(void **to, void *from)
+{
+  (void)to;
+  (void)from;
+  return CURLE_OK;
+}
+
+static void destroy_async_data(struct Curl_async *);
+
+/*
+ * Cancel all possibly still on-going resolves for this connection.
+ */
+void Curl_resolver_cancel(struct connectdata *conn)
+{
+  destroy_async_data(&conn->async);
+}
+
+/* This function is used to init a threaded resolve */
+static bool init_resolve_thread(struct connectdata *conn,
+                                const char *hostname, int port,
+                                const struct addrinfo *hints);
+
+
+/* Data for synchronization between resolver thread and its parent */
+struct thread_sync_data {
+  curl_mutex_t * mtx;
+  int done;
+
+  char * hostname;        /* hostname to resolve, Curl_async.hostname
+                             duplicate */
+  int port;
+  int sock_error;
+  Curl_addrinfo *res;
+#ifdef HAVE_GETADDRINFO
+  struct addrinfo hints;
+#endif
+};
+
+struct thread_data {
+  curl_thread_t thread_hnd;
+  curl_socket_t dummy_sock;
+  unsigned int poll_interval;
+  int interval_end;
+  struct thread_sync_data tsd;
+};
+
+static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
+{
+  return &(((struct thread_data *)conn->async.os_specific)->tsd);
+}
+
+#define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd);
+
+/* Destroy resolver thread synchronization data */
+static
+void destroy_thread_sync_data(struct thread_sync_data * tsd)
+{
+  if (tsd->mtx) {
+    Curl_mutex_destroy(tsd->mtx);
+    free(tsd->mtx);
+  }
+
+  if(tsd->hostname)
+    free(tsd->hostname);
+
+  if (tsd->res)
+    Curl_freeaddrinfo(tsd->res);
+
+  memset(tsd,0,sizeof(*tsd));
+}
+
+/* Initialize resolver thread synchronization data */
+static
+int init_thread_sync_data(struct thread_sync_data * tsd,
+                           const char * hostname,
+                           int port,
+                           const struct addrinfo *hints)
+{
+  memset(tsd, 0, sizeof(*tsd));
+
+  tsd->port = port;
+#ifdef CURLRES_IPV6
+  DEBUGASSERT(hints);
+  tsd->hints = *hints;
+#else
+  (void) hints;
+#endif
+
+  tsd->mtx = malloc(sizeof(curl_mutex_t));
+  if (tsd->mtx == NULL) goto err_exit;
+
+  Curl_mutex_init(tsd->mtx);
+
+  tsd->sock_error = CURL_ASYNC_SUCCESS;
+
+  /* Copying hostname string because original can be destroyed by parent
+   * thread during gethostbyname execution.
+   */
+  tsd->hostname = strdup(hostname);
+  if (!tsd->hostname) goto err_exit;
+
+  return 1;
+
+ err_exit:
+  /* Memory allocation failed */
+  destroy_thread_sync_data(tsd);
+  return 0;
+}
+
+static int getaddrinfo_complete(struct connectdata *conn)
+{
+  struct thread_sync_data *tsd = conn_thread_sync_data(conn);
+  int rc;
+
+  rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
+  /* The tsd->res structure has been copied to async.dns and perhaps the DNS
+     cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
+  */
+  tsd->res = NULL;
+
+  return rc;
+}
+
+
+#ifdef HAVE_GETADDRINFO
+
+/*
+ * getaddrinfo_thread() resolves a name and then exits.
+ *
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
+{
+  struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
+  char   service [NI_MAXSERV];
+  int rc;
+
+  snprintf(service, sizeof(service), "%d", tsd->port);
+
+  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
+
+  if (rc != 0) {
+    tsd->sock_error = SOCKERRNO;
+    if (tsd->sock_error == 0)
+      tsd->sock_error = ENOMEM;
+  }
+
+  Curl_mutex_acquire(tsd->mtx);
+  tsd->done = 1;
+  Curl_mutex_release(tsd->mtx);
+
+  return 0;
+}
+
+#else /* HAVE_GETADDRINFO */
+
+/*
+ * gethostbyname_thread() resolves a name and then exits.
+ */
+static unsigned int CURL_STDCALL gethostbyname_thread (void *arg)
+{
+  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
+
+  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
+
+  if (!tsd->res) {
+    tsd->sock_error = SOCKERRNO;
+    if (tsd->sock_error == 0)
+      tsd->sock_error = ENOMEM;
+  }
+
+  Curl_mutex_acquire(tsd->mtx);
+  tsd->done = 1;
+  Curl_mutex_release(tsd->mtx);
+
+  return 0;
+}
+
+#endif /* HAVE_GETADDRINFO */
+
+/*
+ * destroy_async_data() cleans up async resolver data and thread handle.
+ */
+static void destroy_async_data (struct Curl_async *async)
+{
+  if(async->hostname)
+    free(async->hostname);
+
+  if(async->os_specific) {
+    struct thread_data *td = (struct thread_data*) async->os_specific;
+
+    if (td->dummy_sock != CURL_SOCKET_BAD)
+      sclose(td->dummy_sock);
+
+    if (td->thread_hnd != curl_thread_t_null)
+      Curl_thread_join(&td->thread_hnd);
+
+    destroy_thread_sync_data(&td->tsd);
+
+    free(async->os_specific);
+  }
+  async->hostname = NULL;
+  async->os_specific = NULL;
+}
+
+/*
+ * init_resolve_thread() starts a new thread that performs the actual
+ * resolve. This function returns before the resolve is done.
+ *
+ * Returns FALSE in case of failure, otherwise TRUE.
+ */
+static bool init_resolve_thread (struct connectdata *conn,
+                                 const char *hostname, int port,
+                                 const struct addrinfo *hints)
+{
+  struct thread_data *td = calloc(1, sizeof(struct thread_data));
+  int err = ENOMEM;
+
+  conn->async.os_specific = (void*) td;
+  if(!td)
+    goto err_exit;
+
+  conn->async.port = port;
+  conn->async.done = FALSE;
+  conn->async.status = 0;
+  conn->async.dns = NULL;
+  td->dummy_sock = CURL_SOCKET_BAD;
+  td->thread_hnd = curl_thread_t_null;
+
+  if (!init_thread_sync_data(&td->tsd, hostname, port, hints))
+    goto err_exit;
+
+  Curl_safefree(conn->async.hostname);
+  conn->async.hostname = strdup(hostname);
+  if(!conn->async.hostname)
+    goto err_exit;
+
+#ifdef WIN32
+  /* This socket is only to keep Curl_resolver_fdset() and select() happy;
+   * should never become signalled for read since it's unbound but
+   * Windows needs at least 1 socket in select().
+   */
+  td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
+  if (td->dummy_sock == CURL_SOCKET_BAD)
+    goto err_exit;
+#endif
+
+#ifdef HAVE_GETADDRINFO
+  td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
+#else
+  td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
+#endif
+
+  if(!td->thread_hnd) {
+#ifndef _WIN32_WCE
+    err = errno;
+#endif
+    goto err_exit;
+  }
+
+  return TRUE;
+
+ err_exit:
+  destroy_async_data(&conn->async);
+
+  SET_ERRNO(err);
+
+  return FALSE;
+}
+
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * This is the version for resolves-in-a-thread.
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+                                   struct Curl_dns_entry **entry)
+{
+  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
+  struct SessionHandle *data = conn->data;
+  CURLcode rc = CURLE_OK;
+
+  DEBUGASSERT(conn && td);
+
+  /* wait for the thread to resolve the name */
+  if (Curl_thread_join(&td->thread_hnd)) {
+    rc = getaddrinfo_complete(conn);
+  } else {
+    DEBUGASSERT(0);
+  }
+
+  conn->async.done = TRUE;
+
+  if(entry)
+    *entry = conn->async.dns;
+
+  if(!conn->async.dns) {
+    /* a name was not resolved */
+    if (conn->bits.httpproxy) {
+      failf(data, "Could not resolve proxy: %s; %s",
+            conn->async.hostname, Curl_strerror(conn, conn->async.status));
+      rc = CURLE_COULDNT_RESOLVE_PROXY;
+    } else {
+      failf(data, "Could not resolve host: %s; %s",
+            conn->async.hostname, Curl_strerror(conn, conn->async.status));
+      rc = CURLE_COULDNT_RESOLVE_HOST;
+    }
+  }
+
+  destroy_async_data(&conn->async);
+
+  if(!conn->async.dns)
+    conn->bits.close = TRUE;
+
+  return (rc);
+}
+
+/*
+ * Curl_resolver_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+                                   struct Curl_dns_entry **entry)
+{
+  struct SessionHandle *data = conn->data;
+  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
+  int done = 0;
+
+  *entry = NULL;
+
+  if (!td) {
+    DEBUGASSERT(td);
+    return CURLE_COULDNT_RESOLVE_HOST;
+  }
+
+  Curl_mutex_acquire(td->tsd.mtx);
+  done = td->tsd.done;
+  Curl_mutex_release(td->tsd.mtx);
+
+  if (done) {
+    getaddrinfo_complete(conn);
+    destroy_async_data(&conn->async);
+
+    if(!conn->async.dns) {
+      failf(data, "Could not resolve host: %s; %s",
+            conn->host.name, Curl_strerror(conn, conn->async.status));
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+    *entry = conn->async.dns;
+  } else {
+    /* poll for name lookup done with exponential backoff up to 250ms */
+    int elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+    if (elapsed < 0)
+      elapsed = 0;
+
+    if (td->poll_interval == 0)
+      /* Start at 1ms poll interval */
+      td->poll_interval = 1;
+    else if (elapsed >= td->interval_end)
+      /* Back-off exponentially if last interval expired  */
+      td->poll_interval *= 2;
+
+    if (td->poll_interval > 250)
+      td->poll_interval = 250;
+
+    td->interval_end = elapsed + td->poll_interval;
+    Curl_expire(conn->data, td->poll_interval);
+  }
+
+  return CURLE_OK;
+}
+
+int Curl_resolver_getsock(struct connectdata *conn,
+                          curl_socket_t *socks,
+                          int numsocks)
+{
+  const struct thread_data *td =
+    (const struct thread_data *) conn->async.os_specific;
+
+  if(td && td->dummy_sock != CURL_SOCKET_BAD) {
+    if(numsocks) {
+      /* return one socket waiting for readable, even though this is just
+         a dummy */
+      socks[0] = td->dummy_sock;
+      return GETSOCK_READSOCK(0);
+    }
+  }
+  return 0;
+}
+
+#ifndef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo() - for platforms without getaddrinfo
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+                                         const char *hostname,
+                                         int port,
+                                         int *waitp)
+{
+  struct in_addr in;
+
+  *waitp = 0; /* default to synchronous response */
+
+  if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+  /* fire up a new resolver thread! */
+  if(init_resolve_thread(conn, hostname, port, NULL)) {
+    *waitp = 1; /* expect asynchronous response */
+    return NULL;
+  }
+
+  /* fall-back to blocking version */
+  return Curl_ipv4_resolve_r(hostname, port);
+}
+
+#else /* !HAVE_GETADDRINFO */
+
+/*
+ * Curl_resolver_getaddrinfo() - for getaddrinfo
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+                                         const char *hostname,
+                                         int port,
+                                         int *waitp)
+{
+  struct addrinfo hints;
+  Curl_addrinfo *res;
+  int error;
+  char sbuf[NI_MAXSERV];
+  int pf = PF_INET;
+  struct SessionHandle *data = conn->data;
+
+  *waitp = 0; /* default to synchronous response */
+
+#ifndef CURLRES_IPV4
+  /*
+   * Check if a limited name resolve has been requested.
+   */
+  switch(conn->ip_version) {
+  case CURL_IPRESOLVE_V4:
+    pf = PF_INET;
+    break;
+  case CURL_IPRESOLVE_V6:
+    pf = PF_INET6;
+    break;
+  default:
+    pf = PF_UNSPEC;
+    break;
+  }
+
+  if (pf != PF_INET) {
+    /* see if we have an IPv6 stack */
+    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
+    if(s == CURL_SOCKET_BAD) {
+      /* Some non-IPv6 stacks have been found to make very slow name resolves
+       * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
+       * the stack seems to be a non-ipv6 one. */
+
+      pf = PF_INET;
+    }
+    else {
+      /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
+       * possible checks. And close the socket again.
+       */
+      sclose(s);
+    }
+  }
+#endif /* !CURLRES_IPV4 */
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = conn->socktype;
+
+  snprintf(sbuf, sizeof(sbuf), "%d", port);
+
+  /* fire up a new resolver thread! */
+  if(init_resolve_thread(conn, hostname, port, &hints)) {
+    *waitp = 1; /* expect asynchronous response */
+    return NULL;
+  }
+
+  /* fall-back to blocking version */
+  infof(data, "init_resolve_thread() failed for %s; %s\n",
+        hostname, Curl_strerror(conn, ERRNO));
+
+  error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
+  if(error) {
+    infof(data, "getaddrinfo() failed for %s:%d; %s\n",
+          hostname, port, Curl_strerror(conn, SOCKERRNO));
+    return NULL;
+  }
+  return res;
+}
+
+#endif /* !HAVE_GETADDRINFO */
+
+#endif /* CURLRES_THREADED */
diff --git a/lib/asyn.h b/lib/asyn.h
new file mode 100644
index 0000000..801ae79
--- /dev/null
+++ b/lib/asyn.h
@@ -0,0 +1,169 @@
+#ifndef HEADER_CURL_ASYN_H
+#define HEADER_CURL_ASYN_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+#include "curl_addrinfo.h"
+
+struct addrinfo;
+struct hostent;
+struct SessionHandle;
+struct connectdata;
+struct Curl_dns_entry;
+
+/*
+ * This header defines all functions in the internal asynch resolver interface.
+ * All asynch resolvers need to provide these functions.
+ * asyn-ares.c and asyn-thread.c are the current implementations of asynch
+ * resolver backends.
+ */
+
+/*
+ * Curl_resolver_global_init()
+ *
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Returning anything else than CURLE_OK fails curl_global_init().
+ */
+int Curl_resolver_global_init(void);
+
+/*
+ * Curl_resolver_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ */
+void Curl_resolver_global_cleanup(void);
+
+/*
+ * Curl_resolver_init()
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Should fill the passed pointer by the initialized handler.
+ * Returning anything else than CURLE_OK fails curl_easy_init() with the
+ * correspondent code.
+ */
+int Curl_resolver_init(void **resolver);
+
+/*
+ * Curl_resolver_cleanup()
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Should destroy the handler and free all resources connected to
+ * it.
+ */
+void Curl_resolver_cleanup(void *resolver);
+
+/*
+ * Curl_resolver_duphandle()
+ * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
+ * environment ('resolver' member of the UrlState structure).  Should
+ * duplicate the 'from' handle and pass the resulting handle to the 'to'
+ * pointer.  Returning anything else than CURLE_OK causes failed
+ * curl_easy_duphandle() call.
+ */
+int Curl_resolver_duphandle(void **to, void *from);
+
+/*
+ * Curl_resolver_cancel().
+ *
+ * It is called from inside other functions to cancel currently performing
+ * resolver request. Should also free any temporary resources allocated to
+ * perform a request.
+ */
+void Curl_resolver_cancel(struct connectdata *conn);
+
+/* Curl_resolver_getsock()
+ *
+ * This function is called from the multi_getsock() function.  'sock' is a
+ * pointer to an array to hold the file descriptors, with 'numsock' being the
+ * size of that array (in number of entries). This function is supposed to
+ * return bitmask indicating what file descriptors (referring to array indexes
+ * in the 'sock' array) to wait for, read/write.
+ */
+int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock,
+                          int numsocks);
+
+/*
+ * Curl_resolver_is_resolved()
+ *
+ * Called repeatedly to check if a previous name resolve request has
+ * completed. It should also make sure to time-out if the operation seems to
+ * take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+                                   struct Curl_dns_entry **dns);
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+                                   struct Curl_dns_entry **dnsentry);
+
+/*
+ * Curl_resolver_getaddrinfo() - when using this resolver
+ *
+ * Returns 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 memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ *
+ * Each resolver backend must of course make sure to return data in the
+ * correct format to comply with this.
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+                                         const char *hostname,
+                                         int port,
+                                         int *waitp);
+
+#ifndef CURLRES_ASYNCH
+/* convert these functions if an asynch resolver isn't used */
+#define Curl_resolver_cancel(x)
+#define Curl_async_resolved(x,y) CURLE_OK
+#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_resolver_getsock(x,y,z) 0
+#define Curl_resolver_duphandle(x,y) CURLE_OK
+#define Curl_resolver_init(x) CURLE_OK
+#define Curl_resolver_global_init() CURLE_OK
+#define Curl_resolver_global_cleanup()
+#define Curl_resolver_cleanup(x)
+#endif
+
+#ifdef CURLRES_ASYNCH
+#define Curl_resolver_asynch() 1
+#else
+#define Curl_resolver_asynch() 0
+#endif
+
+
+/********** end of generic resolver interface functions *****************/
+#endif /* HEADER_CURL_ASYN_H */
diff --git a/lib/connect.c b/lib/connect.c
index 261b215..b8ed4a9 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -324,7 +324,7 @@ static CURLcode bindlocal(struct connectdata *conn,
 
       rc = Curl_resolv(conn, dev, 0, &h);
       if(rc == CURLRESOLV_PENDING)
-        (void)Curl_wait_for_resolv(conn, &h);
+        (void)Curl_resolver_wait_resolv(conn, &h);
       conn->ip_version = ipver;
 
       if(h) {
diff --git a/lib/ftp.c b/lib/ftp.c
index af6b4ad..59b38c4 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -836,7 +836,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   /* resolv ip/host to ip */
   rc = Curl_resolv(conn, host, 0, &h);
   if(rc == CURLRESOLV_PENDING)
-    (void)Curl_wait_for_resolv(conn, &h);
+    (void)Curl_resolver_wait_resolv(conn, &h);
   if(h) {
     res = h->addr;
     /* when we return from this function, we can forget about this entry
@@ -1652,7 +1652,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
     if(rc == CURLRESOLV_PENDING)
       /* BLOCKING, ignores the return code but 'addr' will be NULL in
          case of failure */
-      (void)Curl_wait_for_resolv(conn, &addr);
+      (void)Curl_resolver_wait_resolv(conn, &addr);
 
     connectport =
       (unsigned short)conn->port; /* we connect to the proxy's port */
@@ -1668,7 +1668,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
     rc = Curl_resolv(conn, newhost, newport, &addr);
     if(rc == CURLRESOLV_PENDING)
       /* BLOCKING */
-      (void)Curl_wait_for_resolv(conn, &addr);
+      (void)Curl_resolver_wait_resolv(conn, &addr);
 
     connectport = newport; /* we connect to the remote port */
 
diff --git a/lib/hostares.c b/lib/hostares.c
deleted file mode 100644
index cc60016..0000000
--- a/lib/hostares.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2011, 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
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>     /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>     /* for the close() proto */
-#endif
-#ifdef __VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
-/***********************************************************************
- * Only for ares-enabled builds
- **********************************************************************/
-
-#ifdef CURLRES_ARES
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-#include "multiif.h"
-#include "inet_pton.h"
-#include "connect.h"
-#include "select.h"
-#include "progress.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
-     (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
-#    define CARES_STATICLIB
-#  endif
-#  include <ares.h>
-
-#if ARES_VERSION >= 0x010500
-/* c-ares 1.5.0 or later, the callback proto is modified */
-#define HAVE_CARES_CALLBACK_TIMEOUTS 1
-#endif
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-struct ResolverResults {
-  int num_pending; /* number of ares_gethostbyname() requests */
-  Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
-  int last_status;
-};
-
-/*
- * Curl_resolver_global_init() - the generic low-level asynchronous name
- * resolve API.  Called from curl_global_init() to initialize global resolver
- * environment.  Initializes ares library.
- */
-int Curl_resolver_global_init(void)
-{
-#ifdef CARES_HAVE_ARES_LIBRARY_INIT
-  if(ares_library_init(ARES_LIB_INIT_ALL)) {
-    return CURLE_FAILED_INIT;
-  }
-#endif
-  return CURLE_OK;
-}
-
-/*
- * Curl_resolver_global_cleanup()
- *
- * Called from curl_global_cleanup() to destroy global resolver environment.
- * Deinitializes ares library.
- */
-void Curl_resolver_global_cleanup(void)
-{
-#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
-  ares_library_cleanup();
-#endif
-}
-
-/*
- * Curl_resolver_init()
- *
- * Called from curl_easy_init() -> Curl_open() to initialize resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Fills the passed pointer by the initialized ares_channel.
- */
-int Curl_resolver_init(void **resolver)
-{
-  int status = ares_init((ares_channel*)resolver);
-  if(status != ARES_SUCCESS) {
-    if(status == ARES_ENOMEM)
-      return CURLE_OUT_OF_MEMORY;
-    else
-      return CURLE_FAILED_INIT;
-  }
-  return CURLE_OK;
-  /* make sure that all other returns from this function should destroy the
-     ares channel before returning error! */
-}
-
-/*
- * Curl_resolver_cleanup()
- *
- * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Destroys the ares channel.
- */
-void Curl_resolver_cleanup(void *resolver)
-{
-  ares_destroy((ares_channel)resolver);
-}
-
-/*
- * Curl_resolver_duphandle()
- *
- * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
- * environment ('resolver' member of the UrlState structure).  Duplicates the
- * 'from' ares channel and passes the resulting channel to the 'to' pointer.
- */
-int Curl_resolver_duphandle(void **to, void *from)
-{
-  /* Clone the ares channel for the new handle */
-  if(ARES_SUCCESS != ares_dup((ares_channel*)to,(ares_channel)from))
-    return CURLE_FAILED_INIT;
-  return CURLE_OK;
-}
-
-static void destroy_async_data (struct Curl_async *async);
-/*
- * Cancel all possibly still on-going resolves for this connection.
- */
-void Curl_async_cancel(struct connectdata *conn)
-{
-  if( conn && conn->data && conn->data->state.resolver )
-    ares_cancel((ares_channel)conn->data->state.resolver);
-  destroy_async_data(&conn->async);
-}
-
-/*
- * destroy_async_data() cleans up async resolver data.
- */
-static void destroy_async_data (struct Curl_async *async)
-{
-  if(async->hostname)
-    free(async->hostname);
-
-  if(async->os_specific) {
-    struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
-    if( res ) {
-      if( res->temp_ai ) {
-        Curl_freeaddrinfo(res->temp_ai);
-        res->temp_ai = NULL;
-      }
-      free(res);
-    }
-    async->os_specific = NULL;
-  }
-
-  async->hostname = NULL;
-}
-
-/*
- * Curl_resolv_fdset() is called when someone from the outside world (using
- * curl_multi_fdset()) wants to get our fd_set setup and we're talking with
- * ares. The caller must make sure that this function is only called when we
- * have a working ares channel.
- *
- * Returns: CURLE_OK always!
- */
-
-int Curl_resolv_getsock(struct connectdata *conn,
-                        curl_socket_t *socks,
-                        int numsocks)
-
-{
-  struct timeval maxtime;
-  struct timeval timebuf;
-  struct timeval *timeout;
-  int max = ares_getsock((ares_channel)conn->data->state.resolver,
-                         (ares_socket_t *)socks, numsocks);
-
-
-  maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
-  maxtime.tv_usec = 0;
-
-  timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
-                         &timebuf);
-
-  Curl_expire(conn->data,
-              (timeout->tv_sec * 1000) + (timeout->tv_usec/1000));
-
-  return max;
-}
-
-/*
- * waitperform()
- *
- * 1) Ask ares what sockets it currently plays with, then
- * 2) wait for the timeout period to check for action on ares' sockets.
- * 3) tell ares to act on all the sockets marked as "with action"
- *
- * return number of sockets it worked on
- */
-
-static int waitperform(struct connectdata *conn, int timeout_ms)
-{
-  struct SessionHandle *data = conn->data;
-  int nfds;
-  int bitmask;
-  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
-  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
-  int i;
-  int num = 0;
-
-  bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
-                         ARES_GETSOCK_MAXNUM);
-
-  for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
-    pfd[i].events = 0;
-    pfd[i].revents = 0;
-    if(ARES_GETSOCK_READABLE(bitmask, i)) {
-      pfd[i].fd = socks[i];
-      pfd[i].events |= POLLRDNORM|POLLIN;
-    }
-    if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
-      pfd[i].fd = socks[i];
-      pfd[i].events |= POLLWRNORM|POLLOUT;
-    }
-    if(pfd[i].events != 0)
-      num++;
-    else
-      break;
-  }
-
-  if(num)
-    nfds = Curl_poll(pfd, num, timeout_ms);
-  else
-    nfds = 0;
-
-  if(!nfds)
-    /* Call ares_process() unconditonally here, even if we simply timed out
-       above, as otherwise the ares name resolve won't timeout! */
-    ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
-                    ARES_SOCKET_BAD);
-  else {
-    /* move through the descriptors and ask for processing on them */
-    for(i=0; i < num; i++)
-      ares_process_fd((ares_channel)data->state.resolver,
-                      pfd[i].revents & (POLLRDNORM|POLLIN)?
-                      pfd[i].fd:ARES_SOCKET_BAD,
-                      pfd[i].revents & (POLLWRNORM|POLLOUT)?
-                      pfd[i].fd:ARES_SOCKET_BAD);
-  }
-  return nfds;
-}
-
-/*
- * Curl_is_resolved() is called repeatedly to check if a previous name resolve
- * request has completed. It should also make sure to time-out if the
- * operation seems to take too long.
- *
- * Returns normal CURLcode errors.
- */
-CURLcode Curl_is_resolved(struct connectdata *conn,
-                          struct Curl_dns_entry **dns)
-{
-  struct SessionHandle *data = conn->data;
-  struct ResolverResults *res = (struct ResolverResults *)
-    conn->async.os_specific;
-
-  *dns = NULL;
-
-  waitperform(conn, 0);
-
-  if( res && !res->num_pending ) {
-    (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
-    /* temp_ai ownership is moved to the connection, so we need not free-up
-       them */
-    res->temp_ai = NULL;
-    destroy_async_data(&conn->async);
-    if(!conn->async.dns) {
-      failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
-            ares_strerror(conn->async.status));
-      return CURLE_COULDNT_RESOLVE_HOST;
-    }
-    *dns = conn->async.dns;
-  }
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_wait_for_resolv() waits for a resolve to finish. This function should
- * be avoided since using this risk getting the multi interface to "hang".
- *
- * If 'entry' is non-NULL, make it point to the resolved dns entry
- *
- * Returns 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;
-  long timeout;
-  struct timeval now = Curl_tvnow();
-  struct Curl_dns_entry *temp_entry;
-
-  timeout = Curl_timeleft(data, &now, TRUE);
-  if(!timeout)
-    timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
-
-  /* Wait for the name resolve query to complete. */
-  for(;;) {
-    struct timeval *tvp, tv, store;
-    long timediff;
-    int itimeout;
-    int timeout_ms;
-
-    itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
-
-    store.tv_sec = itimeout/1000;
-    store.tv_usec = (itimeout%1000)*1000;
-
-    tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
-
-    /* use the timeout period ares returned to us above if less than one
-       second is left, otherwise just use 1000ms to make sure the progress
-       callback gets called frequent enough */
-    if(!tvp->tv_sec)
-      timeout_ms = (int)(tvp->tv_usec/1000);
-    else
-      timeout_ms = 1000;
-
-    waitperform(conn, timeout_ms);
-    Curl_is_resolved(conn,&temp_entry);
-
-    if(conn->async.done)
-      break;
-
-    if(Curl_pgrsUpdate(conn)) {
-      rc = CURLE_ABORTED_BY_CALLBACK;
-      timeout = -1; /* trigger the cancel below */
-    }
-    else {
-      struct timeval now2 = Curl_tvnow();
-      timediff = Curl_tvdiff(now2, now); /* spent time */
-      timeout -= timediff?timediff:1; /* always deduct at least 1 */
-      now = now2; /* for next loop */
-    }
-    if(timeout < 0) {
-      /* our timeout, so we cancel the ares operation */
-      ares_cancel((ares_channel)data->state.resolver);
-      break;
-    }
-  }
-
-  /* Operation complete, if the lookup was successful we now have the entry
-     in the cache. */
-
-  if(entry)
-    *entry = conn->async.dns;
-
-  if(!conn->async.dns) {
-    /* a name was not resolved */
-    if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
-      if (conn->bits.httpproxy) {
-        failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname);
-        rc = CURLE_COULDNT_RESOLVE_PROXY;
-      }
-      else {
-        failf(data, "Resolving host timed out: %s", conn->host.dispname);
-        rc = CURLE_COULDNT_RESOLVE_HOST;
-      }
-    }
-    else if(conn->async.done) {
-      if (conn->bits.httpproxy) {
-        failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname,
-              ares_strerror(conn->async.status));
-        rc = CURLE_COULDNT_RESOLVE_PROXY;
-      }
-      else {
-        failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
-              ares_strerror(conn->async.status));
-        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 */
-    conn->bits.close = TRUE;
-  }
-
-  return rc;
-}
-
-/* Connects results to the list */
-static void compound_results(struct ResolverResults *res,
-                             Curl_addrinfo *ai)
-{
-  Curl_addrinfo *ai_tail;
-  if(!ai)
-    return;
-  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 = res->temp_ai;
-  res->temp_ai = ai;
-}
-
-/*
- * ares_query_completed_cb() is the callback that ares will call when
- * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
- * when using ares, is completed either successfully or with failure.
- */
-static void query_completed_cb(void *arg,  /* (struct connectdata *) */
-                               int status,
-#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
-                               int timeouts,
-#endif
-                               struct hostent *hostent)
-{
-  struct connectdata *conn = (struct connectdata *)arg;
-  struct ResolverResults *res;
-
-#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
-  (void)timeouts; /* ignored */
-#endif
-
-  if(ARES_EDESTRUCTION == status)
-    /* when this ares handle is getting destroyed, the 'arg' pointer may not
-       be valid so only defer it when we know the 'status' says its fine! */
-    return;
-
-  res = (struct ResolverResults *)conn->async.os_specific;
-  res->num_pending--;
-
-  if(CURL_ASYNC_SUCCESS == status) {
-    Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
-    if(ai) {
-      compound_results(res, ai);
-    }
-  }
-  /* A successful result overwrites any previous error */
-  if( res->last_status != ARES_SUCCESS )
-    res->last_status = status;
-}
-
-/*
- * Curl_getaddrinfo() - when using ares
- *
- * Returns 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 memory *MUST* be freed with
- * Curl_freeaddrinfo(), nothing else.
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                const char *hostname,
-                                int port,
-                                int *waitp)
-{
-  char *bufp;
-  struct SessionHandle *data = conn->data;
-  struct in_addr in;
-  int family = PF_INET;
-#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
-  struct in6_addr in6;
-#endif /* CURLRES_IPV6 */
-
-  *waitp = 0; /* default to synchronous response */
-
-  /* First check if this is an IPv4 address string */
-  if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
-    /* This is a dotted IP address 123.123.123.123-style */
-    return Curl_ip2addr(AF_INET, &in, hostname, port);
-  }
-
-#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
-  /* Otherwise, check if this is an IPv6 address string */
-  if (Curl_inet_pton (AF_INET6, hostname, &in6) > 0) {
-    /* This must be an IPv6 address literal.  */
-    return Curl_ip2addr(AF_INET6, &in6, hostname, port);
-  }
-
-  switch(conn->ip_version) {
-  default:
-#if ARES_VERSION >= 0x010601
-    family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
-                           c-ares versions this just falls through and defaults
-                           to PF_INET */
-    break;
-#endif
-  case CURL_IPRESOLVE_V4:
-    family = PF_INET;
-    break;
-  case CURL_IPRESOLVE_V6:
-    family = PF_INET6;
-    break;
-  }
-#endif /* CURLRES_IPV6 */
-
-  bufp = strdup(hostname);
-  if(bufp) {
-    struct ResolverResults *res = NULL;
-    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 */
-    res = (struct ResolverResults *)calloc(sizeof(struct ResolverResults),1);
-    if( !res ) {
-      Curl_safefree(conn->async.hostname);
-      conn->async.hostname = NULL;
-      return NULL;
-    }
-    conn->async.os_specific = res;
-
-    /* initial status - failed */
-    res->last_status = ARES_ENOTFOUND;
-#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
-    if(family == PF_UNSPEC) {
-      res->num_pending = 2;
-
-      /* areschannel is already setup in the Curl_open() function */
-      ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET,
-                         query_completed_cb, conn);
-      ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET6,
-                         query_completed_cb, conn);
-    }
-    else
-#endif /* CURLRES_IPV6 */
-    {
-      res->num_pending = 1;
-
-      /* areschannel is already setup in the Curl_open() function */
-      ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
-                         query_completed_cb, conn);
-    }
-
-    *waitp = 1; /* expect asynchronous response */
-  }
-  return NULL; /* no struct yet */
-}
-#endif /* CURLRES_ARES */
diff --git a/lib/hostasyn.c b/lib/hostasyn.c
index 5269c08..50f6b01 100644
--- a/lib/hostasyn.c
+++ b/lib/hostasyn.c
@@ -127,4 +127,43 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
   return rc;
 }
 
+/* Call this function after Curl_connect() has returned async=TRUE and
+   then a successful name resolve has been received.
+
+   Note: this function disconnects and frees the conn data in case of
+   resolve failure */
+CURLcode Curl_async_resolved(struct connectdata *conn,
+                             bool *protocol_done)
+{
+  CURLcode code;
+
+  if(conn->async.dns) {
+    conn->dns_entry = conn->async.dns;
+    conn->async.dns = NULL;
+  }
+
+  code = Curl_setup_conn(conn, protocol_done);
+
+  if(code)
+    /* We're not allowed to return failure with memory left allocated
+       in the connectdata struct, free those here */
+    Curl_disconnect(conn, FALSE); /* close the connection */
+
+  return code;
+}
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                const char *hostname,
+                                int port,
+                                int *waitp)
+{
+  return Curl_resolver_getaddrinfo(conn, hostname, port, waitp);
+}
+
 #endif /* CURLRES_ASYNCH */
diff --git a/lib/hostip.c b/lib/hostip.c
index 3db5b49..9dddc0c 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, 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
@@ -464,7 +464,7 @@ int Curl_resolv(struct connectdata *conn,
         /* the response to our resolve call will come asynchronously at
            a later time, good or bad */
         /* First, check that we haven't received the info by now */
-        result = Curl_is_resolved(conn, &dns);
+        result = Curl_resolver_is_resolved(conn, &dns);
         if(result) /* error detected */
           return CURLRESOLV_ERROR;
         if(dns)
diff --git a/lib/hostip.h b/lib/hostip.h
index d88dcd0..c0672d5 100644
--- a/lib/hostip.h
+++ b/lib/hostip.h
@@ -25,6 +25,7 @@
 #include "setup.h"
 #include "hash.h"
 #include "curl_addrinfo.h"
+#include "asyn.h"
 
 #ifdef HAVE_SETJMP_H
 #include <setjmp.h>
@@ -95,52 +96,6 @@ int Curl_resolv_timeout(struct connectdata *conn, const char *hostname,
  */
 bool Curl_ipvalid(struct connectdata *conn);
 
-/********* functions in the internal asynch resolver interface ****** */
-
-/*
- * Curl_resolver_global_init()
- *
- * Called from curl_global_init() to initialize global resolver environment.
- * Returning anything else than CURLE_OK fails curl_global_init().
- */
-int Curl_resolver_global_init(void);
-
-/*
- * Curl_resolver_global_cleanup()
- * Called from curl_global_cleanup() to destroy global resolver environment.
- */
-void Curl_resolver_global_cleanup(void);
-
-/*
- * Curl_resolver_init()
- * Called from curl_easy_init() -> Curl_open() to initialize resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Should fill the passed pointer by the initialized handler.
- * Returning anything else than CURLE_OK fails curl_easy_init() with the
- * correspondent code.
- */
-int Curl_resolver_init(void **resolver);
-
-/*
- * Curl_resolver_cleanup()
- * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Should destroy the handler and free all resources connected to
- * it.
- */
-void Curl_resolver_cleanup(void *resolver);
-
-/*
- * Curl_resolver_duphandle()
- * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
- * environment ('resolver' member of the UrlState structure).  Should
- * duplicate the 'from' handle and pass the resulting handle to the 'to'
- * pointer.  Returning anything else than CURLE_OK causes failed
- * curl_easy_duphandle() call.
- */
-int Curl_resolver_duphandle(void **to, void *from);
-
-/********** end of generic resolver interface functions *****************/
 
 /*
  * Curl_getaddrinfo() is the generic low-level name resolve API within this
@@ -153,29 +108,6 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
                                 int port,
                                 int *waitp);
 
-#ifdef CURLRES_ASYNCH
-/*
- * Curl_async_cancel() is the generic low-level asynchronous name resolve API.
- * It is called from inside other functions to cancel currently performing resolver
- * request. Should also free any temporary resources allocated to perform a request.
- */
-void Curl_async_cancel(struct connectdata *conn);
-#endif
-
-CURLcode Curl_is_resolved(struct connectdata *conn,
-                          struct Curl_dns_entry **dns);
-CURLcode Curl_wait_for_resolv(struct connectdata *conn,
-                              struct Curl_dns_entry **dnsentry);
-
-/* Curl_resolv_getsock() is a generic function that exists in multiple
-   versions depending on what name resolve technology we've built to use. The
-   function is called from the multi_getsock() function.  'sock' is a pointer
-   to an array to hold the file descriptors, with 'numsock' being the size of
-   that array (in number of entries). This function is supposed to return
-   bitmask indicating what file descriptors (referring to array indexes in the
-   'sock' array) to wait for, read/write. */
-int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *sock,
-                        int numsocks);
 
 /* unlock a previously resolved dns entry */
 void Curl_resolv_unlock(struct SessionHandle *data,
diff --git a/lib/hostsyn.c b/lib/hostsyn.c
index 01d0289..a5e9765 100644
--- a/lib/hostsyn.c
+++ b/lib/hostsyn.c
@@ -72,107 +72,5 @@
  **********************************************************************/
 #ifdef CURLRES_SYNCH
 
-/*
- * Curl_resolver_global_init()
- * Called from curl_global_init() to initialize global resolver environment.
- * Does nothing here.
- */
-int Curl_resolver_global_init(void)
-{
-  return CURLE_OK;
-}
-
-/*
- * Curl_resolver_global_cleanup()
- * Called from curl_global_cleanup() to destroy global resolver environment.
- * Does nothing here.
- */
-void Curl_resolver_global_cleanup(void)
-{
-}
-
-/*
- * Curl_resolver_init()
- * Called from curl_easy_init() -> Curl_open() to initialize resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Does nothing here.
- */
-int Curl_resolver_init(void **resolver)
-{
-  (void)resolver;
-  return CURLE_OK;
-}
-
-/*
- * Curl_resolver_cleanup()
- * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Does nothing here.
- */
-void Curl_resolver_cleanup(void *resolver)
-{
-  (void)resolver;
-}
-
-/*
- * Curl_resolver_duphandle()
- * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
- * environment ('resolver' member of the UrlState structure).  Does nothing
- * here.
- */
-int Curl_resolver_duphandle(void **to, void *from)
-{
-  (void)to;
-  (void)from;
-  return CURLE_OK;
-}
-
-/*
- * Curl_wait_for_resolv() for synch-builds.  Curl_resolv() can never return
- * wait==TRUE, so this function will never be called. If it still gets called,
- * we return failure at once.
- *
- * We provide this function only to allow multi.c to remain unaware if we are
- * doing asynch resolves or not.
- */
-CURLcode Curl_wait_for_resolv(struct connectdata *conn,
-                              struct Curl_dns_entry **entry)
-{
-  (void)conn;
-  *entry=NULL;
-  return CURLE_COULDNT_RESOLVE_HOST;
-}
-
-/*
- * This function will never be called when synch-built. If it still gets
- * called, we return failure at once.
- *
- * We provide this function only to allow multi.c to remain unaware if we are
- * doing asynch resolves or not.
- */
-CURLcode Curl_is_resolved(struct connectdata *conn,
-                          struct Curl_dns_entry **dns)
-{
-  (void)conn;
-  *dns = NULL;
-
-  return CURLE_COULDNT_RESOLVE_HOST;
-}
-
-/*
- * We just return OK, this function is never actually used for synch builds.
- * It is present here to keep #ifdefs out from multi.c
- */
-
-int Curl_resolv_getsock(struct connectdata *conn,
-                        curl_socket_t *sock,
-                        int numsocks)
-{
-  (void)conn;
-  (void)sock;
-  (void)numsocks;
-
-  return 0; /* no bits since we don't use any socks */
-}
 
 #endif /* truly sync */
diff --git a/lib/hostthre.c b/lib/hostthre.c
deleted file mode 100644
index 09e21a9..0000000
--- a/lib/hostthre.c
+++ /dev/null
@@ -1,642 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2011, 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
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-#include <errno.h>
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>     /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>     /* for the close() proto */
-#endif
-#ifdef __VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#if defined(USE_THREADS_POSIX)
-#  ifdef HAVE_PTHREAD_H
-#    include <pthread.h>
-#  endif
-#elif defined(USE_THREADS_WIN32)
-#  ifdef HAVE_PROCESS_H
-#    include <process.h>
-#  endif
-#endif
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-#include "multiif.h"
-#include "inet_pton.h"
-#include "inet_ntop.h"
-#include "curl_threads.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/***********************************************************************
- * Only for threaded name resolves builds
- **********************************************************************/
-#ifdef CURLRES_THREADED
-
-/*
- * Curl_resolver_global_init()
- * Called from curl_global_init() to initialize global resolver environment.
- * Does nothing here.
- */
-int Curl_resolver_global_init(void)
-{
-  return CURLE_OK;
-}
-
-/*
- * Curl_resolver_global_cleanup()
- * Called from curl_global_cleanup() to destroy global resolver environment.
- * Does nothing here.
- */
-void Curl_resolver_global_cleanup(void)
-{
-}
-
-/*
- * Curl_resolver_init()
- * Called from curl_easy_init() -> Curl_open() to initialize resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Does nothing here.
- */
-int Curl_resolver_init(void **resolver)
-{
-  (void)resolver;
-  return CURLE_OK;
-}
-
-/*
- * Curl_resolver_cleanup()
- * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
- * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Does nothing here.
- */
-void Curl_resolver_cleanup(void *resolver)
-{
-  (void)resolver;
-}
-
-/*
- * Curl_resolver_duphandle()
- * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
- * environment ('resolver' member of the UrlState structure).  Does nothing
- * here.
- */
-int Curl_resolver_duphandle(void **to, void *from)
-{
-  (void)to;
-  (void)from;
-  return CURLE_OK;
-}
-
-static void destroy_async_data(struct Curl_async *);
-/*
- * Cancel all possibly still on-going resolves for this connection.
- */
-void Curl_async_cancel(struct connectdata *conn)
-{
-  destroy_async_data(&conn->async);
-}
-
-/* This function is used to init a threaded resolve */
-static bool init_resolve_thread(struct connectdata *conn,
-                                const char *hostname, int port,
-                                const struct addrinfo *hints);
-
-
-/* Data for synchronization between resolver thread and its parent */
-struct thread_sync_data {
-  curl_mutex_t * mtx;
-  int done;
-
-  char * hostname;        /* hostname to resolve, Curl_async.hostname
-                             duplicate */
-  int port;
-  int sock_error;
-  Curl_addrinfo *res;
-#ifdef HAVE_GETADDRINFO
-  struct addrinfo hints;
-#endif
-};
-
-struct thread_data {
-  curl_thread_t thread_hnd;
-  curl_socket_t dummy_sock;
-  unsigned int poll_interval;
-  int interval_end;
-  struct thread_sync_data tsd;
-};
-
-static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
-{
-  return &(((struct thread_data *)conn->async.os_specific)->tsd);
-}
-
-#define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd);
-
-/* Destroy resolver thread synchronization data */
-static
-void destroy_thread_sync_data(struct thread_sync_data * tsd)
-{
-  if (tsd->mtx) {
-    Curl_mutex_destroy(tsd->mtx);
-    free(tsd->mtx);
-  }
-
-  if(tsd->hostname)
-    free(tsd->hostname);
-
-  if (tsd->res)
-    Curl_freeaddrinfo(tsd->res);
-
-  memset(tsd,0,sizeof(*tsd));
-}
-
-/* Initialize resolver thread synchronization data */
-static
-int init_thread_sync_data(struct thread_sync_data * tsd,
-                           const char * hostname,
-                           int port,
-                           const struct addrinfo *hints)
-{
-  memset(tsd, 0, sizeof(*tsd));
-
-  tsd->port = port;
-#ifdef CURLRES_IPV6
-  DEBUGASSERT(hints);
-  tsd->hints = *hints;
-#else
-  (void) hints;
-#endif
-
-  tsd->mtx = malloc(sizeof(curl_mutex_t));
-  if (tsd->mtx == NULL) goto err_exit;
-
-  Curl_mutex_init(tsd->mtx);
-
-  tsd->sock_error = CURL_ASYNC_SUCCESS;
-
-  /* Copying hostname string because original can be destroyed by parent
-   * thread during gethostbyname execution.
-   */
-  tsd->hostname = strdup(hostname);
-  if (!tsd->hostname) goto err_exit;
-
-  return 1;
-
- err_exit:
-  /* Memory allocation failed */
-  destroy_thread_sync_data(tsd);
-  return 0;
-}
-
-static int getaddrinfo_complete(struct connectdata *conn)
-{
-  struct thread_sync_data *tsd = conn_thread_sync_data(conn);
-  int rc;
-
-  rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
-  /* The tsd->res structure has been copied to async.dns and perhaps the DNS
-     cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
-  */
-  tsd->res = NULL;
-
-  return rc;
-}
-
-
-#ifdef HAVE_GETADDRINFO
-
-/*
- * getaddrinfo_thread() resolves a name and then exits.
- *
- * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
- * and wait on it.
- */
-static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
-{
-  struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
-  char   service [NI_MAXSERV];
-  int rc;
-
-  snprintf(service, sizeof(service), "%d", tsd->port);
-
-  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
-
-  if (rc != 0) {
-    tsd->sock_error = SOCKERRNO;
-    if (tsd->sock_error == 0)
-      tsd->sock_error = ENOMEM;
-  }
-
-  Curl_mutex_acquire(tsd->mtx);
-  tsd->done = 1;
-  Curl_mutex_release(tsd->mtx);
-
-  return 0;
-}
-
-#else /* HAVE_GETADDRINFO */
-
-/*
- * gethostbyname_thread() resolves a name and then exits.
- */
-static unsigned int CURL_STDCALL gethostbyname_thread (void *arg)
-{
-  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
-
-  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
-
-  if (!tsd->res) {
-    tsd->sock_error = SOCKERRNO;
-    if (tsd->sock_error == 0)
-      tsd->sock_error = ENOMEM;
-  }
-
-  Curl_mutex_acquire(tsd->mtx);
-  tsd->done = 1;
-  Curl_mutex_release(tsd->mtx);
-
-  return 0;
-}
-
-#endif /* HAVE_GETADDRINFO */
-
-/*
- * destroy_async_data() cleans up async resolver data and thread handle.
- */
-static void destroy_async_data (struct Curl_async *async)
-{
-  if(async->hostname)
-    free(async->hostname);
-
-  if(async->os_specific) {
-    struct thread_data *td = (struct thread_data*) async->os_specific;
-
-    if (td->dummy_sock != CURL_SOCKET_BAD)
-      sclose(td->dummy_sock);
-
-    if (td->thread_hnd != curl_thread_t_null)
-      Curl_thread_join(&td->thread_hnd);
-
-    destroy_thread_sync_data(&td->tsd);
-
-    free(async->os_specific);
-  }
-  async->hostname = NULL;
-  async->os_specific = NULL;
-}
-
-/*
- * init_resolve_thread() starts a new thread that performs the actual
- * resolve. This function returns before the resolve is done.
- *
- * Returns FALSE in case of failure, otherwise TRUE.
- */
-static bool init_resolve_thread (struct connectdata *conn,
-                                 const char *hostname, int port,
-                                 const struct addrinfo *hints)
-{
-  struct thread_data *td = calloc(1, sizeof(struct thread_data));
-  int err = ENOMEM;
-
-  conn->async.os_specific = (void*) td;
-  if(!td)
-    goto err_exit;
-
-  conn->async.port = port;
-  conn->async.done = FALSE;
-  conn->async.status = 0;
-  conn->async.dns = NULL;
-  td->dummy_sock = CURL_SOCKET_BAD;
-  td->thread_hnd = curl_thread_t_null;
-
-  if (!init_thread_sync_data(&td->tsd, hostname, port, hints))
-    goto err_exit;
-
-  Curl_safefree(conn->async.hostname);
-  conn->async.hostname = strdup(hostname);
-  if(!conn->async.hostname)
-    goto err_exit;
-
-#ifdef WIN32
-  /* This socket is only to keep Curl_resolv_fdset() and select() happy;
-   * should never become signalled for read since it's unbound but
-   * Windows needs at least 1 socket in select().
-   */
-  td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
-  if (td->dummy_sock == CURL_SOCKET_BAD)
-    goto err_exit;
-#endif
-
-#ifdef HAVE_GETADDRINFO
-  td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
-#else
-  td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
-#endif
-
-  if(!td->thread_hnd) {
-#ifndef _WIN32_WCE
-    err = errno;
-#endif
-    goto err_exit;
-  }
-
-  return TRUE;
-
- err_exit:
-  destroy_async_data(&conn->async);
-
-  SET_ERRNO(err);
-
-  return FALSE;
-}
-
-
-/*
- * Curl_wait_for_resolv() waits for a resolve to finish. This function should
- * be avoided since using this risk getting the multi interface to "hang".
- *
- * If 'entry' is non-NULL, make it point to the resolved dns entry
- *
- * This is the version for resolves-in-a-thread.
- */
-CURLcode Curl_wait_for_resolv(struct connectdata *conn,
-                              struct Curl_dns_entry **entry)
-{
-  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
-  struct SessionHandle *data = conn->data;
-  CURLcode rc = CURLE_OK;
-
-  DEBUGASSERT(conn && td);
-
-  /* wait for the thread to resolve the name */
-  if (Curl_thread_join(&td->thread_hnd)) {
-    rc = getaddrinfo_complete(conn);
-  } else {
-    DEBUGASSERT(0);
-  }
-
-  conn->async.done = TRUE;
-
-  if(entry)
-    *entry = conn->async.dns;
-
-  if(!conn->async.dns) {
-    /* a name was not resolved */
-    if (conn->bits.httpproxy) {
-      failf(data, "Could not resolve proxy: %s; %s",
-            conn->async.hostname, Curl_strerror(conn, conn->async.status));
-      rc = CURLE_COULDNT_RESOLVE_PROXY;
-    } else {
-      failf(data, "Could not resolve host: %s; %s",
-            conn->async.hostname, Curl_strerror(conn, conn->async.status));
-      rc = CURLE_COULDNT_RESOLVE_HOST;
-    }
-  }
-
-  destroy_async_data(&conn->async);
-
-  if(!conn->async.dns)
-    conn->bits.close = TRUE;
-
-  return (rc);
-}
-
-/*
- * Curl_is_resolved() is called repeatedly to check if a previous name resolve
- * request has completed. It should also make sure to time-out if the
- * operation seems to take too long.
- */
-CURLcode Curl_is_resolved(struct connectdata *conn,
-                          struct Curl_dns_entry **entry)
-{
-  struct SessionHandle *data = conn->data;
-  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
-  int done = 0;
-
-  *entry = NULL;
-
-  if (!td) {
-    DEBUGASSERT(td);
-    return CURLE_COULDNT_RESOLVE_HOST;
-  }
-
-  Curl_mutex_acquire(td->tsd.mtx);
-  done = td->tsd.done;
-  Curl_mutex_release(td->tsd.mtx);
-
-  if (done) {
-    getaddrinfo_complete(conn);
-    destroy_async_data(&conn->async);
-
-    if(!conn->async.dns) {
-      failf(data, "Could not resolve host: %s; %s",
-            conn->host.name, Curl_strerror(conn, conn->async.status));
-      return CURLE_COULDNT_RESOLVE_HOST;
-    }
-    *entry = conn->async.dns;
-  } else {
-    /* poll for name lookup done with exponential backoff up to 250ms */
-    int elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
-    if (elapsed < 0)
-      elapsed = 0;
-
-    if (td->poll_interval == 0)
-      /* Start at 1ms poll interval */
-      td->poll_interval = 1;
-    else if (elapsed >= td->interval_end)
-      /* Back-off exponentially if last interval expired  */
-      td->poll_interval *= 2;
-
-    if (td->poll_interval > 250)
-      td->poll_interval = 250;
-
-    td->interval_end = elapsed + td->poll_interval;
-    Curl_expire(conn->data, td->poll_interval);
-  }
-
-  return CURLE_OK;
-}
-
-int Curl_resolv_getsock(struct connectdata *conn,
-                        curl_socket_t *socks,
-                        int numsocks)
-{
-  const struct thread_data *td =
-    (const struct thread_data *) conn->async.os_specific;
-
-  if(td && td->dummy_sock != CURL_SOCKET_BAD) {
-    if(numsocks) {
-      /* return one socket waiting for readable, even though this is just
-         a dummy */
-      socks[0] = td->dummy_sock;
-      return GETSOCK_READSOCK(0);
-    }
-  }
-  return 0;
-}
-
-#ifndef HAVE_GETADDRINFO
-/*
- * Curl_getaddrinfo() - for platforms without getaddrinfo
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                const char *hostname,
-                                int port,
-                                int *waitp)
-{
-  struct in_addr in;
-
-  *waitp = 0; /* default to synchronous response */
-
-  if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
-    /* This is a dotted IP address 123.123.123.123-style */
-    return Curl_ip2addr(AF_INET, &in, hostname, port);
-
-  /* fire up a new resolver thread! */
-  if(init_resolve_thread(conn, hostname, port, NULL)) {
-    *waitp = 1; /* expect asynchronous response */
-    return NULL;
-  }
-
-  /* fall-back to blocking version */
-  return Curl_ipv4_resolve_r(hostname, port);
-}
-
-#else /* !HAVE_GETADDRINFO */
-
-/*
- * Curl_getaddrinfo() - for getaddrinfo
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                const char *hostname,
-                                int port,
-                                int *waitp)
-{
-  struct addrinfo hints;
-  Curl_addrinfo *res;
-  int error;
-  char sbuf[NI_MAXSERV];
-  int pf = PF_INET;
-  struct SessionHandle *data = conn->data;
-
-  *waitp = 0; /* default to synchronous response */
-
-#ifndef CURLRES_IPV4
-  /*
-   * Check if a limited name resolve has been requested.
-   */
-  switch(conn->ip_version) {
-  case CURL_IPRESOLVE_V4:
-    pf = PF_INET;
-    break;
-  case CURL_IPRESOLVE_V6:
-    pf = PF_INET6;
-    break;
-  default:
-    pf = PF_UNSPEC;
-    break;
-  }
-
-  if (pf != PF_INET) {
-    /* see if we have an IPv6 stack */
-    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
-    if(s == CURL_SOCKET_BAD) {
-      /* Some non-IPv6 stacks have been found to make very slow name resolves
-       * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
-       * the stack seems to be a non-ipv6 one. */
-
-      pf = PF_INET;
-    }
-    else {
-      /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
-       * possible checks. And close the socket again.
-       */
-      sclose(s);
-    }
-  }
-#endif /* !CURLRES_IPV4 */
-
-  memset(&hints, 0, sizeof(hints));
-  hints.ai_family = pf;
-  hints.ai_socktype = conn->socktype;
-
-  snprintf(sbuf, sizeof(sbuf), "%d", port);
-
-  /* fire up a new resolver thread! */
-  if(init_resolve_thread(conn, hostname, port, &hints)) {
-    *waitp = 1; /* expect asynchronous response */
-    return NULL;
-  }
-
-  /* fall-back to blocking version */
-  infof(data, "init_resolve_thread() failed for %s; %s\n",
-        hostname, Curl_strerror(conn, ERRNO));
-
-  error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
-  if(error) {
-    infof(data, "getaddrinfo() failed for %s:%d; %s\n",
-          hostname, port, Curl_strerror(conn, SOCKERRNO));
-    return NULL;
-  }
-  return res;
-}
-
-#endif /* !HAVE_GETADDRINFO */
-
-#endif /* CURLRES_THREADED */
diff --git a/lib/multi.c b/lib/multi.c
index 91d92df..08a2531 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -855,7 +855,7 @@ static int multi_getsock(struct Curl_one_easy *easy,
     return 0;
 
   case CURLM_STATE_WAITRESOLVE:
-    return Curl_resolv_getsock(easy->easy_conn, socks, numsocks);
+    return Curl_resolver_getsock(easy->easy_conn, socks, numsocks);
 
   case CURLM_STATE_PROTOCONNECT:
     return Curl_protocol_getsock(easy->easy_conn, socks, numsocks);
@@ -1070,7 +1070,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       struct Curl_dns_entry *dns = NULL;
 
       /* check if we have the name resolved by now */
-      easy->result = Curl_is_resolved(easy->easy_conn, &dns);
+      easy->result = Curl_resolver_is_resolved(easy->easy_conn, &dns);
 
       if(dns) {
         /* Update sockets here. Mainly because the socket(s) may have been
diff --git a/lib/socks.c b/lib/socks.c
index 419d1d7..bd28e28 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -175,7 +175,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
 
     if(rc == CURLRESOLV_PENDING)
       /* ignores the return code, but 'dns' remains NULL on failure */
-      (void)Curl_wait_for_resolv(conn, &dns);
+      (void)Curl_resolver_wait_resolv(conn, &dns);
 
     /*
      * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
@@ -603,7 +603,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
 
     if(rc == CURLRESOLV_PENDING) {
       /* this requires that we're in "wait for resolve" state */
-      code = Curl_wait_for_resolv(conn, &dns);
+      code = Curl_resolver_wait_resolv(conn, &dns);
       if(code != CURLE_OK)
         return code;
     }
diff --git a/lib/transfer.c b/lib/transfer.c
index 63ab5c4..352652b 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -1980,7 +1980,7 @@ connect_host(struct SessionHandle *data,
   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);
+    res = Curl_resolver_wait_resolv(*conn, NULL);
     if(CURLE_OK == res)
       /* Resolved, continue with the connection */
       res = Curl_async_resolved(*conn, &protocol_done);
@@ -2032,7 +2032,7 @@ Curl_reconnect_request(struct connectdata **connp)
       if(async) {
         /* Now, if async is TRUE here, we need to wait for the name
            to resolve */
-        result = Curl_wait_for_resolv(conn, NULL);
+        result = Curl_resolver_wait_resolv(conn, NULL);
         if(result)
           return result;
 
diff --git a/lib/url.c b/lib/url.c
index 85d8e2a..1e6c44c 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2557,9 +2557,7 @@ static void conn_free(struct connectdata *conn)
     return;
 
   /* possible left-overs from the async name resolvers */
-#if defined(CURLRES_ASYNCH)
-  Curl_async_cancel(conn);
-#endif
+  Curl_resolver_cancel(conn);
 
   /* close the SSL stuff before we close any sockets since they will/may
      write to the sockets */
@@ -2967,16 +2965,16 @@ ConnectionExists(struct SessionHandle *data,
         continue;
       }
 
-#ifdef CURLRES_ASYNCH
-      /* ip_addr_str[0] is NUL only if the resolving of the name hasn't
-         completed yet and until then we don't re-use this connection */
-      if(!check->ip_addr_str[0]) {
-        infof(data,
-              "Connection #%ld hasn't finished name resolve, can't reuse\n",
-              check->connectindex);
-        continue;
+      if(Curl_resolver_asynch()) {
+        /* ip_addr_str[0] is NUL only if the resolving of the name hasn't
+           completed yet and until then we don't re-use this connection */
+        if(!check->ip_addr_str[0]) {
+          infof(data,
+                "Connection #%ld hasn't finished name resolve, can't reuse\n",
+                check->connectindex);
+          continue;
+        }
       }
-#endif
 
       if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || check->bits.close) {
         /* Don't pick a connection that hasn't connected yet or that is going
@@ -4675,7 +4673,7 @@ static void reuse_conn(struct connectdata *old_conn,
  * @param data The sessionhandle pointer
  * @param in_connect is set to the next connection data pointer
  * @param async is set TRUE when an async DNS resolution is pending
- * @see setup_conn()
+ * @see Curl_setup_conn()
  *
  * *NOTE* this function assigns the conn->data pointer!
  */
@@ -5015,16 +5013,16 @@ static CURLcode create_conn(struct SessionHandle *data,
   return result;
 }
 
-/* setup_conn() is called after the name resolve initiated in
+/* Curl_setup_conn() is called after the name resolve initiated in
  * create_conn() is all done.
  *
- * setup_conn() also handles reused connections
+ * Curl_setup_conn() also handles reused connections
  *
  * conn->data MUST already have been setup fine (in create_conn)
  */
 
-static CURLcode setup_conn(struct connectdata *conn,
-                           bool *protocol_done)
+CURLcode Curl_setup_conn(struct connectdata *conn,
+                         bool *protocol_done)
 {
   CURLcode result=CURLE_OK;
   struct SessionHandle *data = conn->data;
@@ -5147,7 +5145,7 @@ CURLcode Curl_connect(struct SessionHandle *data,
       /* DNS resolution is done: that's either because this is a reused
          connection, in which case DNS was unnecessary, or because DNS
          really did finish already (synch resolver/fast async resolve) */
-      code = setup_conn(*in_connect, protocol_done);
+      code = Curl_setup_conn(*in_connect, protocol_done);
     }
   }
 
@@ -5161,38 +5159,6 @@ CURLcode Curl_connect(struct SessionHandle *data,
   return code;
 }
 
-/* Call this function after Curl_connect() has returned async=TRUE and
-   then a successful name resolve has been received.
-
-   Note: this function disconnects and frees the conn data in case of
-   resolve failure */
-CURLcode Curl_async_resolved(struct connectdata *conn,
-                             bool *protocol_done)
-{
-#ifdef CURLRES_ASYNCH
-  CURLcode code;
-
-  if(conn->async.dns) {
-    conn->dns_entry = conn->async.dns;
-    conn->async.dns = NULL;
-  }
-
-  code = setup_conn(conn, protocol_done);
-
-  if(code)
-    /* We're not allowed to return failure with memory left allocated
-       in the connectdata struct, free those here */
-    Curl_disconnect(conn, FALSE); /* close the connection */
-
-  return code;
-#else
-  (void)conn;
-  (void)protocol_done;
-  return CURLE_OK;
-#endif
-}
-
-
 CURLcode Curl_done(struct connectdata **connp,
                    CURLcode status,  /* an error if this is called after an
                                         error was detected */
@@ -5232,9 +5198,7 @@ CURLcode Curl_done(struct connectdata **connp,
     data->req.location = NULL;
   }
 
-#if defined(CURLRES_ASYNCH)
-  Curl_async_cancel(conn);
-#endif
+  Curl_resolver_cancel(conn);
 
   if(conn->dns_entry) {
     Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
diff --git a/lib/url.h b/lib/url.h
index 241dc28..d6bb068 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2011, 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
@@ -47,6 +47,8 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
 CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
 CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
 void Curl_safefree(void *ptr);
+CURLcode Curl_setup_conn(struct connectdata *conn,
+                         bool *protocol_done);
 
 /* create a connection cache */
 struct conncache *Curl_mk_connc(int type, long amount);
-- 
1.7.4.1

