Implemented getaddrinfo(), including full mapping of struct addrinfo
between UNIX and Windows. Based on a patch by Mike Hearn.

diff --git a/configure b/configure
index e80550a..7828d85 100755
--- a/configure
+++ b/configure
@@ -14505,6 +14505,7 @@
 
 
 
+
 for ac_func in \
 	_lwp_create \
 	_lwp_self \
@@ -14527,6 +14528,7 @@
 	ftruncate \
 	futimes \
 	futimesat \
+	getaddrinfo \
 	getnetbyname \
 	getopt_long \
 	getpagesize \
diff --git a/configure.ac b/configure.ac
index 7ed9c26..39031d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1158,6 +1158,7 @@
 	ftruncate \
 	futimes \
 	futimesat \
+	getaddrinfo \
 	getnetbyname \
 	getopt_long \
 	getpagesize \
diff --git a/dlls/winsock/socket.c b/dlls/winsock/socket.c
index 9923fc4..f0fc266 100644
--- a/dlls/winsock/socket.c
+++ b/dlls/winsock/socket.c
@@ -314,6 +314,30 @@
     { 0, 0 }
 };
 
+static const int ws_aiflag_map[][2] =
+{
+    MAP_OPTION( AI_PASSIVE ),
+    MAP_OPTION( AI_CANONNAME ),
+    MAP_OPTION( AI_NUMERICHOST ),
+    /* Linux/UNIX knows a lot more. But Windows only
+     * has 3 as far as I could see. -Marcus
+     */
+    { 0, 0 }
+};
+
+static const int ws_eai_map[][2] =
+{
+    MAP_OPTION( EAI_AGAIN ),
+    MAP_OPTION( EAI_BADFLAGS ),
+    MAP_OPTION( EAI_FAIL ),
+    MAP_OPTION( EAI_FAMILY ),
+    MAP_OPTION( EAI_MEMORY ),
+    MAP_OPTION( EAI_NODATA ),
+    MAP_OPTION( EAI_SERVICE ),
+    MAP_OPTION( EAI_SOCKTYPE ),
+    { 0, 0 }
+};
+
 inline static DWORD NtStatusToWSAError( const DWORD status )
 {
     /* We only need to cover the status codes set by server async request handling */
@@ -860,9 +884,9 @@
 /* ----------------------------------- i/o APIs */
 
 #ifdef HAVE_IPX
-#define SUPPORTED_PF(pf) ((pf)==WS_AF_INET || (pf)== WS_AF_IPX)
+#define SUPPORTED_PF(pf) ((pf)==WS_AF_INET || (pf)== WS_AF_IPX || (pf) == WS_AF_INET6)
 #else
-#define SUPPORTED_PF(pf) ((pf)==WS_AF_INET)
+#define SUPPORTED_PF(pf) ((pf)==WS_AF_INET || (pf) == WS_AF_INET6)
 #endif
 
 
@@ -3031,6 +3055,168 @@
     return retval;
 }
 
+/***********************************************************************
+ *		freeaddrinfo		(WS2_32.@)
+ */
+void WINAPI WS_freeaddrinfo(struct WS_addrinfo *res)
+{
+    while (res) {
+        struct WS_addrinfo *next;
+
+        HeapFree(GetProcessHeap(),0,res->ai_canonname);
+        HeapFree(GetProcessHeap(),0,res->ai_addr);
+        next = res->ai_next;
+        HeapFree(GetProcessHeap(),0,res);
+        res = next;
+    }
+}
+
+/* helper functions for getaddrinfo() */
+static int convert_aiflag_w2u(int winflags) {
+    int i, unixflags = 0;
+
+    for (i=0;ws_aiflag_map[i][0];i++) {
+        if (ws_aiflag_map[i][0] & winflags) {
+            unixflags |= ws_aiflag_map[i][1];
+            winflags &= ~ws_aiflag_map[i][0];
+        }
+    }
+    if (winflags)
+        FIXME("Unhandled windows AI_xxx flags %x\n", winflags);
+    return unixflags;
+}
+
+static int convert_aiflag_u2w(int unixflags) {
+    int i, winflags = 0;
+
+    for (i=0;ws_aiflag_map[i][0];i++) {
+        if (ws_aiflag_map[i][1] & unixflags) {
+            winflags |= ws_aiflag_map[i][0];
+            unixflags &= ~ws_aiflag_map[i][1];
+        }
+    }
+    if (unixflags) /* will warn usually */
+        WARN("Unhandled UNIX AI_xxx flags %x\n", unixflags);
+    return winflags;
+}
+
+static int convert_eai_u2w(int unixret) {
+    int i;
+
+    for (i=0;ws_eai_map[i][0];i++)
+        if (ws_eai_map[i][0] == unixret)
+            return ws_eai_map[i][1];
+    return unixret;
+}
+
+/***********************************************************************
+ *		getaddrinfo		(WS2_32.@)
+ */
+int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const ADDRINFOA *hints, ADDRINFOA **res)
+{
+#if HAVE_GETADDRINFO
+    struct addrinfo *unixaires = NULL;
+    int   result;
+    struct addrinfo unixhints, *punixhints = NULL;
+    CHAR *node = NULL, *serv = NULL;
+
+    if (nodename)
+        if (!(node = strdup_lower(nodename))) return WSA_NOT_ENOUGH_MEMORY;
+
+    if (servname) {
+        if (!(serv = strdup_lower(servname))) {
+            HeapFree(GetProcessHeap(), 0, node);
+            return WSA_NOT_ENOUGH_MEMORY;
+        }
+    }
+
+    if (hints) {
+        punixhints = &unixhints;
+
+        memset(&unixhints, 0, sizeof(unixhints));
+        punixhints->ai_flags    = convert_aiflag_w2u(hints->ai_flags);
+        punixhints->ai_family   = convert_af_w2u(hints->ai_family);
+        punixhints->ai_socktype = convert_socktype_w2u(hints->ai_socktype);
+        punixhints->ai_protocol = convert_proto_w2u(hints->ai_protocol);
+    }
+
+    /* getaddrinfo(3) is thread safe, no need to wrap in CS */
+    result = getaddrinfo(nodename, servname, punixhints, &unixaires);
+
+    TRACE("%s, %s %p -> %p %d\n", nodename, servname, hints, res, result);
+
+    HeapFree(GetProcessHeap(), 0, node);
+    HeapFree(GetProcessHeap(), 0, serv);
+
+    if (!result) {
+        struct addrinfo *xuai = unixaires;
+        struct WS_addrinfo **xai = res;
+
+        *xai = NULL;
+        while (xuai) {
+            struct WS_addrinfo *ai = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(struct WS_addrinfo));
+            int len;
+
+            if (!ai)
+                goto outofmem;
+
+            *xai = ai;xai = &ai->ai_next;
+            ai->ai_flags    = convert_aiflag_u2w(xuai->ai_flags);
+            ai->ai_family   = convert_af_u2w(xuai->ai_family);
+            ai->ai_socktype = convert_socktype_u2w(xuai->ai_socktype);
+            ai->ai_protocol = convert_proto_u2w(xuai->ai_protocol);
+            if (xuai->ai_canonname) {
+                TRACE("canon name - %s\n",debugstr_a(xuai->ai_canonname));
+                ai->ai_canonname = HeapAlloc(GetProcessHeap(),0,strlen(xuai->ai_canonname)+1);
+                if (!ai->ai_canonname)
+                    goto outofmem;
+                strcpy(ai->ai_canonname,xuai->ai_canonname);
+            }
+            len = xuai->ai_addrlen;
+            ai->ai_addr = HeapAlloc(GetProcessHeap(),0,len);
+            if (!ai->ai_addr)
+                goto outofmem;
+            ai->ai_addrlen = len;
+            do {
+                int winlen = ai->ai_addrlen;
+
+                if (!ws_sockaddr_u2ws(xuai->ai_addr, xuai->ai_addrlen, ai->ai_addr, &winlen)) {
+                    ai->ai_addrlen = winlen;
+                    break;
+                }
+                len = 2*len;
+                ai->ai_addr = HeapReAlloc(GetProcessHeap(),0,ai->ai_addr,len);
+                if (!ai->ai_addr)
+                    goto outofmem;
+                ai->ai_addrlen = len;
+            } while (1);
+            xuai = xuai->ai_next;
+        }
+        freeaddrinfo(unixaires);
+    } else {
+        result = convert_eai_u2w(result);
+    }
+    return result;
+
+outofmem:
+    if (*res) WS_freeaddrinfo(*res);
+    if (unixaires) freeaddrinfo(unixaires);
+    *res = NULL;
+    return WSA_NOT_ENOUGH_MEMORY;
+#else
+    FIXME("getaddrinfo() failed, not found during buildtime.\n");
+    return EAI_FAIL;
+#endif
+}
+
+/***********************************************************************
+ *		GetAddrInfoW		(WS2_32.@)
+ */
+int WINAPI GetAddrInfoW(LPCWSTR nodename, LPCWSTR servname, const ADDRINFOW *hints, ADDRINFOW **res)
+{
+    FIXME("empty stub!\n");
+    return EAI_FAIL;
+}
 
 /***********************************************************************
  *		getservbyport		(WS2_32.56)
diff --git a/dlls/winsock/ws2_32.spec b/dlls/winsock/ws2_32.spec
index 21a78a4..b36b854 100644
--- a/dlls/winsock/ws2_32.spec
+++ b/dlls/winsock/ws2_32.spec
@@ -50,6 +50,7 @@
 
 500 stub     WEP
 
+@ stdcall GetAddrInfoW(wstr wstr ptr ptr)
 @ stdcall WSApSetPostRoutine(ptr)
 @ stdcall WPUCompleteOverlappedRequest(long ptr long long ptr)
 @ stdcall WSAAccept(long ptr ptr ptr long)
@@ -113,6 +114,6 @@
 @ stub    WSCUpdateProvider
 @ stub    WSCWriteNameSpaceOrder
 @ stdcall WSCWriteProviderOrder(ptr long)
-@ stub    freeaddrinfo
-@ stub    getaddrinfo
+@ stdcall freeaddrinfo(ptr) WS_freeaddrinfo
+@ stdcall getaddrinfo(str str ptr ptr) WS_getaddrinfo
 @ stub    getnameinfo
diff --git a/include/config.h.in b/include/config.h.in
index 2de817a..4573236 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -146,6 +146,9 @@
 /* Define to 1 if you have the `futimesat' function. */
 #undef HAVE_FUTIMESAT
 
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
 /* Define to 1 if you have the `gethostbyname' function. */
 #undef HAVE_GETHOSTBYNAME
 
diff --git a/include/ws2tcpip.h b/include/ws2tcpip.h
index 8e58bcd..87f7550 100644
--- a/include/ws2tcpip.h
+++ b/include/ws2tcpip.h
@@ -159,4 +159,38 @@
 #define WS_IP_DONTFRAGMENT     14
 #endif /* USE_WS_PREFIX */
 
+/* Possible Windows flags for getaddrinfo() */
+#ifndef USE_WS_PREFIX
+# define AI_PASSIVE     0x0001
+# define AI_CANONNAME   0x0002
+# define AI_NUMERICHOST 0x0004
+/* getaddrinfo error codes */
+# define EAI_AGAIN	WSATRY_AGAIN
+# define EAI_BADFLAGS	WSAEINVAL
+# define EAI_FAIL	WSANO_RECOVERY
+# define EAI_FAMILY	WSAEAFNOSUPPORT
+# define EAI_MEMORY	WSA_NOT_ENOUGH_MEMORY
+# define EAI_NODATA	WSANO_DATA
+# define EAI_NONAME	WSAHOST_NOT_FOUND
+# define EAI_SERVICE	WSATYPE_NOT_FOUND
+# define EAI_SOCKTYPE	WSAESOCKTNOSUPPORT
+#else
+# define WS_AI_PASSIVE     0x0001
+# define WS_AI_CANONNAME   0x0002
+# define WS_AI_NUMERICHOST 0x0004
+/* getaddrinfo error codes */
+# define WS_EAI_AGAIN	WSATRY_AGAIN
+# define WS_EAI_BADFLAGS	WSAEINVAL
+# define WS_EAI_FAIL	WSANO_RECOVERY
+# define WS_EAI_FAMILY	WSAEAFNOSUPPORT
+# define WS_EAI_MEMORY	WSA_NOT_ENOUGH_MEMORY
+# define WS_EAI_NODATA	WSANO_DATA
+# define WS_EAI_NONAME	WSAHOST_NOT_FOUND
+# define WS_EAI_SERVICE	WSATYPE_NOT_FOUND
+# define WS_EAI_SOCKTYPE	WSAESOCKTNOSUPPORT
+#endif
+
+int WINAPI WS(getaddrinfo)(LPCSTR,LPCSTR,const ADDRINFOA *,ADDRINFOA **);
+int WINAPI GetAddrInfoW(LPCWSTR,LPCWSTR,const ADDRINFOW *,ADDRINFOW **);
+
 #endif /* __WS2TCPIP__ */