From: Bruno Jesus <00cpxxx@gmail.com> Subject: ws2_32: Try harder to get the host name address in getaddrinfo() Message-Id: Date: Sat, 13 Dec 2014 17:36:40 -0200 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 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);