From: Bruno Jesus <00cpxxx@gmail.com> Subject: ws2_32: Try harder to get the host name address in getaddrinfo (try 2) Message-Id: Date: Mon, 3 Aug 2015 13:17:44 -0300 try 2: Tests now prove that resolving with the host name is the same as resolving with empty name. Fixes bug https://bugs.winehq.org/show_bug.cgi?id=29609 original: When the host name is not resolvable getaddrinfo/GetAddrInfoW will fail, this is not expected for some applications like League of Legends. 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. diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index b06d7e7..2d06a87 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -5973,7 +5973,7 @@ 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; @@ -5983,13 +5983,13 @@ int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const struct WS_addr 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; @@ -6033,6 +6033,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. 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 2d14496..03e1627 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -6313,6 +6313,8 @@ static void test_GetAddrInfoW(void) static const WCHAR zero[] = {'0',0}; int i, ret; ADDRINFOW *result, *result2, *p, hint; + WCHAR name[256]; + DWORD size = sizeof(name); if (!pGetAddrInfoW || !pFreeAddrInfoW) { @@ -6320,6 +6322,8 @@ static void test_GetAddrInfoW(void) return; } memset(&hint, 0, sizeof(ADDRINFOW)); + name[0] = 0; + GetComputerNameExW( ComputerNamePhysicalDnsHostname, name, &size ); result = (ADDRINFOW *)0xdeadbeef; WSASetLastError(0xdeadbeef); @@ -6395,6 +6399,30 @@ static void test_GetAddrInfoW(void) ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); pFreeAddrInfoW(result); + /* try to get information from the computer name, result is the same + * as if requesting with an empty host name. */ + ret = pGetAddrInfoW(name, NULL, NULL, &result); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + + ret = pGetAddrInfoW(empty, NULL, NULL, &result2); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + compare_addrinfow(result, result2); + pFreeAddrInfoW(result); + pFreeAddrInfoW(result2); + + ret = pGetAddrInfoW(name, empty, NULL, &result); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + + ret = pGetAddrInfoW(empty, empty, NULL, &result2); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + compare_addrinfow(result, result2); + pFreeAddrInfoW(result); + pFreeAddrInfoW(result2); + result = (ADDRINFOW *)0xdeadbeef; WSASetLastError(0xdeadbeef); ret = pGetAddrInfoW(NULL, NULL, NULL, &result); @@ -6475,6 +6503,8 @@ static void test_getaddrinfo(void) { int i, ret; ADDRINFOA *result, *result2, *p, hint; + CHAR name[256]; + DWORD size = sizeof(name); if (!pgetaddrinfo || !pfreeaddrinfo) { @@ -6482,6 +6512,7 @@ static void test_getaddrinfo(void) return; } memset(&hint, 0, sizeof(ADDRINFOA)); + GetComputerNameExA( ComputerNamePhysicalDnsHostname, name, &size ); result = (ADDRINFOA *)0xdeadbeef; WSASetLastError(0xdeadbeef); @@ -6558,6 +6589,30 @@ static void test_getaddrinfo(void) ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); pfreeaddrinfo(result); + /* try to get information from the computer name, result is the same + * as if requesting with an empty host name. */ + ret = pgetaddrinfo(name, NULL, NULL, &result); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + + ret = pgetaddrinfo("", NULL, NULL, &result2); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + compare_addrinfo(result, result2); + pfreeaddrinfo(result); + pfreeaddrinfo(result2); + + ret = pgetaddrinfo(name, "", NULL, &result); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + + ret = pgetaddrinfo("", "", NULL, &result2); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + compare_addrinfo(result, result2); + pfreeaddrinfo(result); + pfreeaddrinfo(result2); + result = (ADDRINFOA *)0xdeadbeef; WSASetLastError(0xdeadbeef); ret = pgetaddrinfo("nxdomain.codeweavers.com", NULL, NULL, &result);