diff -u3 -H -B -w curl-7.12-hostip2/lib/hostasyn.c hostasyn.c
--- curl-7.12-hostip2/lib/hostasyn.c	Wed Apr 21 17:19:59 2004
+++ hostasyn.c	Thu Apr 22 14:38:36 2004
@@ -93,9 +93,10 @@
 #endif

 /***********************************************************************
- * Only for builds using asynchronous name resolves
+ * Only for builds using asynchronous name resolves (except threaded
+ * getaddrinfo).
  **********************************************************************/
-#ifdef CURLRES_ASYNCH
+#if defined(CURLRES_ASYNCH) && !defined(USE_THREADING_GETADDRINFO)

 /*
  * Curl_host_callback() gets called by ares/gethostbyname_thread() when we got
diff -u3 -H -B -w curl-7.12-hostip2/lib/hostip.h hostip.h
--- curl-7.12-hostip2/lib/hostip.h	Thu Apr 22 11:18:06 2004
+++ hostip.h	Thu Apr 22 14:28:57 2004
@@ -131,7 +131,8 @@

 /* This function is used to init a threaded resolve when that is built */
 bool Curl_init_resolve_thread(struct connectdata *conn,
-                              const char *hostname, int port);
+                              const char *hostname, int port,
+                              const Curl_addrinfo *hints);

 /*
  * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
@@ -158,6 +159,11 @@
 #endif

 #ifdef USE_THREADING_GETHOSTBYNAME
+#define CURLRES_ASYNCH
+#define CURLRES_THREADED
+#endif
+
+#ifdef USE_THREADING_GETADDRINFO
 #define CURLRES_ASYNCH
 #define CURLRES_THREADED
 #endif
diff -u3 -H -B -w curl-7.12-hostip2/lib/hostip6.c hostip6.c
--- curl-7.12-hostip2/lib/hostip6.c	Thu Apr 22 11:11:53 2004
+++ hostip6.c	Thu Apr 22 14:30:02 2004
@@ -179,8 +179,9 @@
   return TRUE;
 }

+#ifndef USE_THREADING_GETADDRINFO
 /*
- * Curl_getaddrinfo() when built ipv6-enabled.
+ * Curl_getaddrinfo() when built ipv6-enabled (non-threading version).
  *
  * Returns name information about the given hostname and port number. If
  * successful, the 'addrinfo' is returned and the forth argument will point to
@@ -245,6 +246,6 @@

   return res;
 }
-
+#endif /* USE_THREADING_GETADDRINFO */
 #endif /* ipv6 */

diff -u3 -H -B -w curl-7.12-hostip2/lib/hostthre.c hostthre.c
--- curl-7.12-hostip2/lib/hostthre.c	Thu Apr 22 11:15:25 2004
+++ hostthre.c	Thu Apr 22 14:53:15 2004
@@ -97,7 +97,15 @@
  **********************************************************************/
 #ifdef CURLRES_THREADED

-#ifdef DEBUG_THREADING_GETHOSTBYNAME
+#ifdef CURLRES_IPV4
+  #define THREAD_FUNC  gethostbyname_thread
+  #define THREAD_NAME "gethostbyname_thread"
+#else
+  #define THREAD_FUNC  getaddrinfo_thread
+  #define THREAD_NAME "getaddrinfo_thread"
+#endif
+
+#if defined(DEBUG_THREADING_GETHOSTBYNAME) || defined(DEBUG_THREADING_GETADDRINFO)
 /* If this is defined, provide tracing */
 #define TRACE(args)  \
  do { trace_it("%u: ", __LINE__); trace_it args; } while (0)
@@ -115,30 +123,64 @@
     return;
   va_start (args, fmt);
   vfprintf (stderr, fmt, args);
-/*fflush (stderr); */  /* seems a bad idea in a multi-threaded app */
+  fflush (stderr);
   va_end (args);
 }
 #else
 #define TRACE(x)
 #endif

+#ifdef DEBUG_THREADING_GETADDRINFO
+
+/* inet_ntop.c */
+extern const char *Curl_inet_ntop (int af, const void *addr, char *buf, size_t size);
+
+static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai)
+{
+  TRACE(("dump_addrinfo:\n"));
+  for ( ; ai; ai = ai->ai_next) {
+    const struct in_addr  *addr4 = &((const struct sockaddr_in*)ai->ai_addr)->sin_addr;
+    const struct in6_addr *addr6 = &((const struct sockaddr_in6*)ai->ai_addr)->sin6_addr;
+    char  buf [INET6_ADDRSTRLEN];
+    int   af = ai->ai_family;
+
+    trace_it("    fam %2d, CNAME %s, ",
+             af, ai->ai_canonname ? ai->ai_canonname : "<none>");
+    if (Curl_inet_ntop(af, af == AF_INET6 ? addr6 : addr4, buf, sizeof(buf)))
+      trace_it("%s\n", buf);
+    else
+      trace_it("failed; %s\n", Curl_strerror(conn,WSAGetLastError()));
+  }
+}
+#endif
+
 struct thread_data {
   HANDLE thread_hnd;
   unsigned thread_id;
   DWORD  thread_status;
   curl_socket_t dummy_sock;   /* dummy for Curl_fdset() */
+  FILE *stderr_file;
+#ifdef CURLRES_IPV6
+  struct addrinfo hints;
+#endif
 };

+#if defined(CURLRES_IPV4)
 /*
  * gethostbyname_thread() resolves a name, calls the Curl_host_callback and
  * then exits.
+ *
+ * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on it.
  */
 static unsigned __stdcall gethostbyname_thread (void *arg)
 {
   struct connectdata *conn = (struct connectdata*) arg;
+  struct thread_data *td = (struct thread_data*) conn->async.os_specific;
   struct hostent *he;
   int    rc;

+  *stderr = *td->stderr_file;
+
   WSASetLastError (conn->async.status = NO_DATA); /* pending status */
   he = gethostbyname (conn->async.hostname);
   if (he) {
@@ -155,6 +197,74 @@
   /* An implicit _endthreadex() here */
 }

+#elif defined(CURLRES_IPV6)
+/*
+ * getaddrinfo_callback() gets called by getaddrinfo_thread() when we got
+ * the name resolved (or not!).
+ *
+ * This operation stores the resolved data (res) in the DNS cache. No need to do a
+ * "deep" copy since 'res' will be freed by DNS cache-handler (which calls freeaddrinfo).
+ *
+ * The storage operation locks and unlocks the DNS cache.
+ */
+static void getaddrinfo_callback (struct connectdata *conn, int status, struct addrinfo *res)
+{
+  struct Curl_dns_entry *dns = NULL;
+
+  conn->async.done = TRUE;
+  conn->async.status = status;
+
+  if (CURL_ASYNC_SUCCESS == status) {
+    struct SessionHandle *data = conn->data;
+
+    if (data->share)
+       Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+    dns = Curl_cache_addr(data, res, conn->async.hostname, conn->async.port);
+
+    if (data->share)
+       Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+  }
+  conn->async.dns = dns;
+}
+
+/*
+ * getaddrinfo_thread() resolves a name, calls getaddrinfo_callback and then exits.
+ *
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static unsigned __stdcall getaddrinfo_thread (void *arg)
+{
+  struct connectdata *conn = (struct connectdata*) arg;
+  struct thread_data *td   = (struct thread_data*) conn->async.os_specific;
+  struct addrinfo    *res;
+  char   service [NI_MAXSERV];
+  int    rc;
+
+  *stderr = *td->stderr_file;
+
+  itoa(conn->async.port, service, 10);
+
+  WSASetLastError(conn->async.status = NO_DATA); /* pending status */
+
+  rc = getaddrinfo(conn->async.hostname, service, &td->hints, &res);
+
+  if (rc == 0) {
+#ifdef DEBUG_THREADING_GETADDRINFO
+    dump_addrinfo (conn, res);
+#endif
+    getaddrinfo_callback(conn, CURL_ASYNC_SUCCESS, res);
+  }
+  else {
+    getaddrinfo_callback(conn, (int)WSAGetLastError(), NULL);
+    TRACE(("Winsock-error %d, no address\n", conn->async.status));
+  }
+  return (rc);
+  /* An implicit _endthreadex() here */
+}
+#endif
+
 /*
  * destroy_thread_data() cleans up async resolver data.
  * Complementary of ares_destroy.
@@ -182,7 +292,8 @@
  * Returns FALSE in case of failure, otherwise TRUE.
  */
 bool Curl_init_resolve_thread(struct connectdata *conn,
-                              const char *hostname, int port)
+                               const char *hostname, int port,
+                               const Curl_addrinfo *hints)
 {
   struct thread_data *td = calloc(sizeof(*td), 1);

@@ -206,8 +317,16 @@
   conn->async.os_specific = (void*) td;

   td->dummy_sock = CURL_SOCKET_BAD;
-  td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, gethostbyname_thread,
+  td->stderr_file = stderr;
+  td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
                                 conn, 0, &td->thread_id);
+#ifdef CURLRES_IPV6
+  curlassert(hints);
+  td->hints = *hints;
+#else
+  (void) hints;
+#endif
+
   if (!td->thread_hnd) {
      SetLastError(errno);
      TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn,errno)));
@@ -256,13 +376,13 @@
       */
      WSASetLastError(conn->async.status);
      GetExitCodeThread(td->thread_hnd, &td->thread_status);
-     TRACE(("gethostbyname_thread() status %lu, thread retval %lu, ",
-            status, td->thread_status));
+     TRACE(("%s() status %lu, thread retval %lu, ",
+            THREAD_NAME, status, td->thread_status));
   }
   else {
      conn->async.done = TRUE;
      td->thread_status = (DWORD)-1;
-     TRACE(("gethostbyname_thread() timeout, "));
+     TRACE(("%s() timeout, ", THREAD_NAME));
   }

   TRACE(("elapsed %lu ms\n", GetTickCount()-ticks));
@@ -333,6 +453,7 @@
     FD_SET(td->dummy_sock,write_fd_set);
     *max_fdp = td->dummy_sock;
   }
+  (void) read_fd_set;
   return CURLE_OK;
 }

@@ -344,23 +465,83 @@
                                 int port,
                                 int *waitp)
 {
-  in_addr_t in = inet_addr(hostname);
+  struct addrinfo hints, *res;
+  int error;
+  char sbuf[NI_MAXSERV];
+  curl_socket_t s;
+  int pf;
+  struct SessionHandle *data = conn->data;
+  struct in_addr a4;
+  struct in6_addr a6;

   *waitp = FALSE; /* default to synch response */

-  if (in != CURL_INADDR_NONE)
+  /*! Need an 'struct addrinfo' version of Curl_ip2addr().
+   *  Or let getaddrinfo() do it?
+   */
+#if 0
+  if (Curl_inet_pton(AF_INET,hostname,&a4))
     /* This is a dotted IP address 123.123.123.123-style */
-    return Curl_ip2addr(in, hostname);
+    return Curl_ip2addr(a4.s_addr, hostname);
+
+  if (Curl_inet_pton(AF_INET6,hostname,&a6))
+    /* This is a literal IPv6 address */
+    return Curl_ip2addr(&a6.s6_addr, hostname);
+#endif
+
+  /* see if we have an IPv6 stack */
+  s = socket(PF_INET6, SOCK_DGRAM, 0);
+  if (s < 0) {
+    /* 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);
+
+    /*
+     * Check if a more limited name resolve has been requested.
+     */
+    switch(data->set.ip_version) {
+    case CURL_IPRESOLVE_V4:
+      pf = PF_INET;
+      break;
+    case CURL_IPRESOLVE_V6:
+      pf = PF_INET6;
+      break;
+    default:
+      pf = PF_UNSPEC;
+      break;
+    }
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_CANONNAME;
+  snprintf(sbuf, sizeof(sbuf), "%d", port);

   /* fire up a new resolver thread! */
-  if (Curl_init_resolve_thread(conn, hostname, port)) {
+  if (Curl_init_resolve_thread(conn, hostname, port, &hints)) {
     *waitp = TRUE;  /* please wait for the response */
     return NULL;
   }
+
+  /* fall-back to blocking version */
   infof(data, "Curl_init_resolve_thread() failed for %s; code %lu\n",
         hostname, GetLastError());

+  error = getaddrinfo(hostname, sbuf, &hints, &res);
+  if (error) {
+    infof(data, "getaddrinfo() failed for %s:%d; %s\n",
+          hostname, port, Curl_strerror(conn,WSAGetLastError()));
   return NULL;
 }
-
+  return res;
+}
 #endif /* CURLRES_THREADED */
diff -u3 -H -B -w curl-7.12-hostip2/lib/setup.h setup.h
--- curl-7.12-hostip2/lib/setup.h	Mon Apr 19 08:03:24 2004
+++ setup.h	Thu Apr 22 12:43:02 2004
@@ -261,8 +261,12 @@
 #error "ares does not yet support IPv6. Disable IPv6 or ares and rebuild"
 #endif

-#if defined(WIN32) && !defined(__CYGWIN32__) && !defined(USE_ARES) && !defined(ENABLE_IPV6)
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES)
+#ifdef ENABLE_IPV6
+#define USE_THREADING_GETADDRINFO
+#else
 #define USE_THREADING_GETHOSTBYNAME  /* Cygwin uses alarm() function */
+#endif
 #endif

 /*
diff -u3 -H -B -w curl-7.12-hostip2/lib/url.c url.c
--- curl-7.12-hostip2/lib/url.c	Wed Apr 21 13:15:02 2004
+++ url.c	Thu Apr 22 12:59:03 2004
@@ -84,6 +84,11 @@

 #endif

+#ifdef USE_LIBIDN
+#include <idna.h>
+#include <stringprep.h>
+#endif
+
 #ifdef HAVE_OPENSSL_ENGINE_H
 #include <openssl/engine.h>
 #endif
@@ -145,6 +150,11 @@
                                     struct connectdata *conn);
 static bool safe_strequal(char* str1, char* str2);

+#ifdef USE_LIBIDN
+static bool is_ASCII_name (const char *hostname);
+static bool is_ACE_name (const char *hostname);
+#endif
+
 #ifndef USE_ARES
 /* not for Win32, unless it is cygwin
    not for ares builds */
@@ -1384,7 +1394,8 @@
   Curl_safefree(conn->allocptr.host);
   Curl_safefree(conn->allocptr.cookiehost);
   Curl_safefree(conn->proxyhost);
-#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME)
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+    defined(USE_THREADING_GETADDRINFO)
   /* possible left-overs from the async name resolve */
   Curl_safefree(conn->async.hostname);
   Curl_safefree(conn->async.os_specific);
@@ -3070,6 +3081,26 @@
   }
 #endif /* USE_ARES */

+#ifdef USE_LIBIDN
+  /*************************************************************
+   * Check name for non-ASCII and convert hostname to ACE form.
+   *************************************************************/
+
+  if(!conn->bits.reuse && conn->remote_port) {
+    const char *host = conn->hostname;
+    char *ace_hostname;
+
+    if (!is_ASCII_name(host) && !is_ACE_name(host)) {
+       int rc = idna_to_ascii_lz (host, &ace_hostname, 0);
+
+       if (rc == IDNA_SUCCESS)
+          conn->ace_hostname = ace_hostname;
+       else
+          infof(data, "Failed to convert %s to ACE; IDNA error %d\n", host, rc);
+    }
+  }
+#endif
+
   /*************************************************************
    * Resolve the name of the server or proxy
    *************************************************************/
@@ -3277,7 +3308,8 @@
    then a successful name resolve has been received */
 CURLcode Curl_async_resolved(struct connectdata *conn)
 {
-#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME)
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+    defined(USE_THREADING_GETADDRINFO)
   CURLcode code = SetupConnection(conn, conn->async.dns);

   if(code)
@@ -3504,3 +3536,20 @@
   if(sslc->random_file)
     free(sslc->random_file);
 }
+
+/*
+ * Helpers for IDNA convertions. To do.
+ */
+#ifdef USE_LIBIDN
+static bool is_ASCII_name (const char *hostname)
+{
+  (void) hostname;
+  return (TRUE);
+}
+
+static bool is_ACE_name (const char *hostname)
+{
+  (void) hostname;
+  return (FALSE);
+}
+#endif
diff -u3 -H -B -w curl-7.12-hostip2/lib/urldata.h urldata.h
--- curl-7.12-hostip2/lib/urldata.h	Wed Apr 21 15:19:27 2004
+++ urldata.h	Thu Apr 22 09:33:19 2004
@@ -381,7 +381,8 @@
   bool ignorebody;  /* we read a response-body but we ignore it! */
 };

-#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME)
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+    defined(USE_THREADING_GETADDRINFO)
 struct Curl_async {
   char *hostname;
   int port;
@@ -430,6 +431,9 @@
   char *namebuffer; /* allocated buffer to store the hostname in */
   char *hostname;  /* hostname to use, as parsed from url. points to
                       somewhere within the namebuffer[] area */
+#ifdef USE_LIBIDN
+  char *ace_hostname; /* hostname possibly converted to ACE form */
+#endif
   char *pathbuffer;/* allocated buffer to store the URL's path part in */
   char *path;      /* path to use, points to somewhere within the pathbuffer
                       area */
@@ -579,7 +583,8 @@

   char syserr_buf [256]; /* buffer for Curl_strerror() */

-#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME)
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+    defined(USE_THREADING_GETADDRINFO)
   /* data used for the asynch name resolve callback */
   struct Curl_async async;
 #endif

