ws2_32: Try harder to get the host name address in getaddrinfo()

Bruno Jesus 00cpxxx at gmail.com
Sat Dec 13 13:36:40 CST 2014


When the host name is not resolvable getaddrinfo/GetAddrInfoW will
fail, this is not expected for some applications like League of
Legends [1][2][3]. We can deal with this in two ways:
- Try harder and use a NULL name to resolve the localhost address
(user transparent).
- Just warn the user and give up (requires the user to understand the
issue and fix /etc/hosts).

This patch tries harder and at the same time warns the user.

Tested on PC-BSD 9 and Debian 7 by removing the host name in /etc/hosts.

Fixes bug https://bugs.winehq.org/show_bug.cgi?id=29609 for some people.

[1] https://bugs.winehq.org/show_bug.cgi?id=29609#c10
[2] https://bugs.winehq.org/show_bug.cgi?id=29609#c13
[3] http://www.playonlinux.com/fr/topic-10056-League_of_Legends_crash_after_champ_select.html
-------------- next part --------------
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index b6aad67..d5404b7 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -5621,19 +5621,19 @@ int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const struct WS_addr
     struct addrinfo *unixaires = NULL;
     int   result;
     struct addrinfo unixhints, *punixhints = NULL;
-    char *hostname = NULL;
+    char *hostname;
     const char *node;
 
     *res = NULL;
     if (!nodename && !servname) return WSAHOST_NOT_FOUND;
 
+    hostname = get_hostname();
+    if (!hostname) return WSA_NOT_ENOUGH_MEMORY;
+
     if (!nodename)
         node = NULL;
     else if (!nodename[0])
-    {
-        node = hostname = get_hostname();
-        if (!node) return WSA_NOT_ENOUGH_MEMORY;
-    }
+        node = hostname;
     else
         node = nodename;
 
@@ -5677,6 +5677,14 @@ int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const struct WS_addr
     /* getaddrinfo(3) is thread safe, no need to wrap in CS */
     result = getaddrinfo(node, servname, punixhints, &unixaires);
 
+    if (result && !strcmp(hostname, node))
+    {
+        /* If it didn't work it means the host name IP is not in /etc/hosts, try again
+         * by sending a NULL host and avoid sending a NULL servname too because that
+         * is invalid */
+        ERR_(winediag)("Failed to resolve your host name IP, attempting to resolve as NULL. You should fix this!\n");
+        result = getaddrinfo(NULL, servname ? servname : "0", punixhints, &unixaires);
+    }
     TRACE("%s, %s %p -> %p %d\n", debugstr_a(nodename), debugstr_a(servname), hints, res, result);
     HeapFree(GetProcessHeap(), 0, hostname);
 
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 49ebbf5..c322e73 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -5802,12 +5802,17 @@ static void test_GetAddrInfoW(void)
     static const WCHAR zero[] = {'0',0};
     int i, ret;
     ADDRINFOW *result, *result2, *p, hint;
+    char computernameA[256];
+    WCHAR computername[sizeof(computernameA)];
 
     if (!pGetAddrInfoW || !pFreeAddrInfoW)
     {
         win_skip("GetAddrInfoW and/or FreeAddrInfoW not present\n");
         return;
     }
+    ret = gethostname(computernameA, sizeof(computernameA));
+    ok(!ret, "Expected gethostname to work\n");
+    MultiByteToWideChar(CP_ACP, 0, computernameA, -1, computername, sizeof(computernameA));
     memset(&hint, 0, sizeof(ADDRINFOW));
 
     result = (ADDRINFOW *)0xdeadbeef;
@@ -5867,6 +5872,25 @@ static void test_GetAddrInfoW(void)
     ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError());
     pFreeAddrInfoW(result);
 
+    ret = pGetAddrInfoW(computername, NULL, NULL, &result);
+    ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError());
+    pFreeAddrInfoW(result);
+
+    result = NULL;
+    ret = pGetAddrInfoW(computername, empty, NULL, &result);
+    ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError());
+    pFreeAddrInfoW(result);
+
+    result = NULL;
+    ret = pGetAddrInfoW(computername, zero, NULL, &result);
+    ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError());
+    pFreeAddrInfoW(result);
+
+    result = NULL;
+    ret = pGetAddrInfoW(computername, port, NULL, &result);
+    ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError());
+    pFreeAddrInfoW(result);
+
     result = NULL;
     ret = pGetAddrInfoW(localhost, NULL, &hint, &result);
     ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError());
@@ -5953,12 +5977,15 @@ static void test_getaddrinfo(void)
 {
     int i, ret;
     ADDRINFOA *result, *result2, *p, hint;
+    char computername[256];
 
     if (!pgetaddrinfo || !pfreeaddrinfo)
     {
         win_skip("getaddrinfo and/or freeaddrinfo not present\n");
         return;
     }
+    ret = gethostname(computername, sizeof(computername));
+    ok(!ret, "Expected gethostname to work\n");
     memset(&hint, 0, sizeof(ADDRINFOA));
 
     result = (ADDRINFOA *)0xdeadbeef;
@@ -6019,6 +6046,26 @@ static void test_getaddrinfo(void)
     pfreeaddrinfo(result);
 
     result = NULL;
+    ret = pgetaddrinfo(computername, NULL, NULL, &result);
+    ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError());
+    pfreeaddrinfo(result);
+
+    result = NULL;
+    ret = pgetaddrinfo(computername, "", NULL, &result);
+    ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError());
+    pfreeaddrinfo(result);
+
+    result = NULL;
+    ret = pgetaddrinfo(computername, "0", NULL, &result);
+    ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError());
+    pfreeaddrinfo(result);
+
+    result = NULL;
+    ret = pgetaddrinfo(computername, "80", NULL, &result);
+    ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError());
+    pfreeaddrinfo(result);
+
+    result = NULL;
     ret = pgetaddrinfo("localhost", NULL, &hint, &result);
     ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError());
     pfreeaddrinfo(result);


More information about the wine-patches mailing list