/* * Unit test suite for protocol functions * * Copyright 2004 Hans Leidekker * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #define WIN32_NO_STATUS #include #include #include #include #include #include #include #include "wine/test.h" static void (WINAPI *pFreeAddrInfoExW)(ADDRINFOEXW *ai); static int (WINAPI *pGetAddrInfoExW)(const WCHAR *name, const WCHAR *servname, DWORD namespace, GUID *namespace_id, const ADDRINFOEXW *hints, ADDRINFOEXW **result, struct timeval *timeout, OVERLAPPED *overlapped, LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine, HANDLE *handle); static int (WINAPI *pGetAddrInfoExOverlappedResult)(OVERLAPPED *overlapped); static int (WINAPI *pGetHostNameW)(WCHAR *name, int len); static const char *(WINAPI *p_inet_ntop)(int family, void *addr, char *string, ULONG size); static const WCHAR *(WINAPI *pInetNtopW)(int family, void *addr, WCHAR *string, ULONG size); static int (WINAPI *p_inet_pton)(int family, const char *string, void *addr); static int (WINAPI *pInetPtonW)(int family, WCHAR *string, void *addr); static int (WINAPI *pWSCGetProviderInfo)(GUID *provider, WSC_PROVIDER_INFO_TYPE type, BYTE *info, size_t *size, DWORD flags, INT *err); /* TCP and UDP over IP fixed set of service flags */ #define TCPIP_SERVICE_FLAGS (XP1_GUARANTEED_DELIVERY \ | XP1_GUARANTEED_ORDER \ | XP1_GRACEFUL_CLOSE \ | XP1_EXPEDITED_DATA \ | XP1_IFS_HANDLES) #define UDPIP_SERVICE_FLAGS (XP1_CONNECTIONLESS \ | XP1_MESSAGE_ORIENTED \ | XP1_SUPPORT_BROADCAST \ | XP1_SUPPORT_MULTIPOINT \ | XP1_IFS_HANDLES) static void test_service_flags(int family, int version, int socktype, int protocol, DWORD testflags) { DWORD expectedflags = 0; if (socktype == SOCK_STREAM && protocol == IPPROTO_TCP) expectedflags = TCPIP_SERVICE_FLAGS; if (socktype == SOCK_DGRAM && protocol == IPPROTO_UDP) expectedflags = UDPIP_SERVICE_FLAGS; /* check if standard TCP and UDP protocols are offering the correct service flags */ if ((family == AF_INET || family == AF_INET6) && version == 2 && expectedflags) { /* QOS may or may not be installed */ testflags &= ~XP1_QOS_SUPPORTED; ok(expectedflags == testflags, "Incorrect flags, expected 0x%x, received 0x%x\n", expectedflags, testflags); } } static void test_WSAEnumProtocolsA(void) { INT ret, i, j, found; DWORD len = 0, error; WSAPROTOCOL_INFOA info, *buffer; INT ptest[] = {0xdead, IPPROTO_TCP, 0xcafe, IPPROTO_UDP, 0xbeef, 0}; ret = WSAEnumProtocolsA( NULL, NULL, &len ); ok( ret == SOCKET_ERROR, "WSAEnumProtocolsA() succeeded unexpectedly\n"); error = WSAGetLastError(); ok( error == WSAENOBUFS, "Expected 10055, received %d\n", error); len = 0; ret = WSAEnumProtocolsA( NULL, &info, &len ); ok( ret == SOCKET_ERROR, "WSAEnumProtocolsA() succeeded unexpectedly\n"); error = WSAGetLastError(); ok( error == WSAENOBUFS, "Expected 10055, received %d\n", error); buffer = HeapAlloc( GetProcessHeap(), 0, len ); if (buffer) { ret = WSAEnumProtocolsA( NULL, buffer, &len ); ok( ret != SOCKET_ERROR, "WSAEnumProtocolsA() failed unexpectedly: %d\n", WSAGetLastError() ); for (i = 0; i < ret; i++) { ok( strlen( buffer[i].szProtocol ), "No protocol name found\n" ); test_service_flags( buffer[i].iAddressFamily, buffer[i].iVersion, buffer[i].iSocketType, buffer[i].iProtocol, buffer[i].dwServiceFlags1); } HeapFree( GetProcessHeap(), 0, buffer ); } /* Test invalid protocols in the list */ ret = WSAEnumProtocolsA( ptest, NULL, &len ); ok( ret == SOCKET_ERROR, "WSAEnumProtocolsA() succeeded unexpectedly\n"); error = WSAGetLastError(); ok( error == WSAENOBUFS || broken(error == WSAEFAULT) /* NT4 */, "Expected 10055, received %d\n", error); buffer = HeapAlloc( GetProcessHeap(), 0, len ); if (buffer) { ret = WSAEnumProtocolsA( ptest, buffer, &len ); ok( ret != SOCKET_ERROR, "WSAEnumProtocolsA() failed unexpectedly: %d\n", WSAGetLastError() ); ok( ret >= 2, "Expected at least 2 items, received %d\n", ret); for (i = found = 0; i < ret; i++) for (j = 0; j < ARRAY_SIZE(ptest); j++) if (buffer[i].iProtocol == ptest[j]) { found |= 1 << j; break; } ok(found == 0x0A, "Expected 2 bits represented as 0xA, received 0x%x\n", found); HeapFree( GetProcessHeap(), 0, buffer ); } } static void test_WSAEnumProtocolsW(void) { INT ret, i, j, found; DWORD len = 0, error; WSAPROTOCOL_INFOW info, *buffer; INT ptest[] = {0xdead, IPPROTO_TCP, 0xcafe, IPPROTO_UDP, 0xbeef, 0}; ret = WSAEnumProtocolsW( NULL, NULL, &len ); ok( ret == SOCKET_ERROR, "WSAEnumProtocolsW() succeeded unexpectedly\n"); error = WSAGetLastError(); ok( error == WSAENOBUFS, "Expected 10055, received %d\n", error); len = 0; ret = WSAEnumProtocolsW( NULL, &info, &len ); ok( ret == SOCKET_ERROR, "WSAEnumProtocolsW() succeeded unexpectedly\n"); error = WSAGetLastError(); ok( error == WSAENOBUFS, "Expected 10055, received %d\n", error); buffer = HeapAlloc( GetProcessHeap(), 0, len ); if (buffer) { ret = WSAEnumProtocolsW( NULL, buffer, &len ); ok( ret != SOCKET_ERROR, "WSAEnumProtocolsW() failed unexpectedly: %d\n", WSAGetLastError() ); for (i = 0; i < ret; i++) { ok( lstrlenW( buffer[i].szProtocol ), "No protocol name found\n" ); test_service_flags( buffer[i].iAddressFamily, buffer[i].iVersion, buffer[i].iSocketType, buffer[i].iProtocol, buffer[i].dwServiceFlags1); } HeapFree( GetProcessHeap(), 0, buffer ); } /* Test invalid protocols in the list */ ret = WSAEnumProtocolsW( ptest, NULL, &len ); ok( ret == SOCKET_ERROR, "WSAEnumProtocolsW() succeeded unexpectedly\n"); error = WSAGetLastError(); ok( error == WSAENOBUFS || broken(error == WSAEFAULT) /* NT4 */, "Expected 10055, received %d\n", error); buffer = HeapAlloc( GetProcessHeap(), 0, len ); if (buffer) { ret = WSAEnumProtocolsW( ptest, buffer, &len ); ok( ret != SOCKET_ERROR, "WSAEnumProtocolsW() failed unexpectedly: %d\n", WSAGetLastError() ); ok( ret >= 2, "Expected at least 2 items, received %d\n", ret); for (i = found = 0; i < ret; i++) for (j = 0; j < ARRAY_SIZE(ptest); j++) if (buffer[i].iProtocol == ptest[j]) { found |= 1 << j; break; } ok(found == 0x0A, "Expected 2 bits represented as 0xA, received 0x%x\n", found); HeapFree( GetProcessHeap(), 0, buffer ); } } struct protocol { int prot; const char *names[2]; BOOL missing_from_xp; }; static const struct protocol protocols[] = { { 0, { "ip", "IP" }}, { 1, { "icmp", "ICMP" }}, { 3, { "ggp", "GGP" }}, { 6, { "tcp", "TCP" }}, { 8, { "egp", "EGP" }}, { 12, { "pup", "PUP" }}, { 17, { "udp", "UDP" }}, { 20, { "hmp", "HMP" }}, { 22, { "xns-idp", "XNS-IDP" }}, { 27, { "rdp", "RDP" }}, { 41, { "ipv6", "IPv6" }, TRUE}, { 43, { "ipv6-route", "IPv6-Route" }, TRUE}, { 44, { "ipv6-frag", "IPv6-Frag" }, TRUE}, { 50, { "esp", "ESP" }, TRUE}, { 51, { "ah", "AH" }, TRUE}, { 58, { "ipv6-icmp", "IPv6-ICMP" }, TRUE}, { 59, { "ipv6-nonxt", "IPv6-NoNxt" }, TRUE}, { 60, { "ipv6-opts", "IPv6-Opts" }, TRUE}, { 66, { "rvd", "RVD" }}, }; static const struct protocol *find_protocol(int number) { int i; for (i = 0; i < ARRAY_SIZE(protocols); i++) { if (protocols[i].prot == number) return &protocols[i]; } return NULL; } static void test_getprotobyname(void) { struct protoent *ent; char all_caps_name[16]; int i, j; for (i = 0; i < ARRAY_SIZE(protocols); i++) { for (j = 0; j < ARRAY_SIZE(protocols[0].names); j++) { ent = getprotobyname(protocols[i].names[j]); ok((ent && ent->p_proto == protocols[i].prot) || broken(!ent && protocols[i].missing_from_xp), "Expected %s to be protocol number %d, got %d\n", wine_dbgstr_a(protocols[i].names[j]), protocols[i].prot, ent ? ent->p_proto : -1); } for (j = 0; protocols[i].names[0][j]; j++) all_caps_name[j] = toupper(protocols[i].names[0][j]); all_caps_name[j] = 0; ent = getprotobyname(all_caps_name); ok((ent && ent->p_proto == protocols[i].prot) || broken(!ent && protocols[i].missing_from_xp), "Expected %s to be protocol number %d, got %d\n", wine_dbgstr_a(all_caps_name), protocols[i].prot, ent ? ent->p_proto : -1); } } static void test_getprotobynumber(void) { struct protoent *ent; const struct protocol *ref; int i; for (i = -1; i <= 256; i++) { ent = getprotobynumber(i); ref = find_protocol(i); if (!ref) { ok(!ent, "Expected protocol number %d to be undefined, got %s\n", i, wine_dbgstr_a(ent ? ent->p_name : NULL)); continue; } ok((ent && ent->p_name && !strcmp(ent->p_name, ref->names[0])) || broken(!ent && ref->missing_from_xp), "Expected protocol number %d to be %s, got %s\n", i, ref->names[0], wine_dbgstr_a(ent ? ent->p_name : NULL)); ok((ent && ent->p_aliases && ent->p_aliases[0] && !strcmp(ent->p_aliases[0], ref->names[1])) || broken(!ent && ref->missing_from_xp), "Expected protocol number %d alias 0 to be %s, got %s\n", i, ref->names[0], wine_dbgstr_a(ent && ent->p_aliases ? ent->p_aliases[0] : NULL)); } } #define NUM_THREADS 3 /* Number of threads to run getservbyname */ #define NUM_QUERIES 250 /* Number of getservbyname queries per thread */ static DWORD WINAPI do_getservbyname( void *param ) { struct { const char *name; const char *proto; int port; } serv[2] = { {"domain", "udp", 53}, {"telnet", "tcp", 23}, }; HANDLE *starttest = param; int i, j; struct servent *pserv[2]; ok( WaitForSingleObject( *starttest, 30 * 1000 ) != WAIT_TIMEOUT, "test_getservbyname: timeout waiting for start signal\n" ); /* ensure that necessary buffer resizes are completed */ for (j = 0; j < 2; j++) pserv[j] = getservbyname( serv[j].name, serv[j].proto ); for (i = 0; i < NUM_QUERIES / 2; i++) { for (j = 0; j < 2; j++) { pserv[j] = getservbyname( serv[j].name, serv[j].proto ); ok( pserv[j] != NULL || broken(pserv[j] == NULL) /* win8, fixed in win81 */, "getservbyname could not retrieve information for %s: %d\n", serv[j].name, WSAGetLastError() ); if ( !pserv[j] ) continue; ok( pserv[j]->s_port == htons(serv[j].port), "getservbyname returned the wrong port for %s: %d\n", serv[j].name, ntohs(pserv[j]->s_port) ); ok( !strcmp( pserv[j]->s_proto, serv[j].proto ), "getservbyname returned the wrong protocol for %s: %s\n", serv[j].name, pserv[j]->s_proto ); ok( !strcmp( pserv[j]->s_name, serv[j].name ), "getservbyname returned the wrong name for %s: %s\n", serv[j].name, pserv[j]->s_name ); } ok( pserv[0] == pserv[1] || broken(pserv[0] != pserv[1]) /* win8, fixed in win81 */, "getservbyname: winsock resized servent buffer when not necessary\n" ); } return 0; } static void test_getservbyname(void) { int i; HANDLE starttest, thread[NUM_THREADS]; starttest = CreateEventA( NULL, 1, 0, "test_getservbyname_starttest" ); /* create threads */ for (i = 0; i < NUM_THREADS; i++) thread[i] = CreateThread( NULL, 0, do_getservbyname, &starttest, 0, NULL ); /* signal threads to start */ SetEvent( starttest ); for (i = 0; i < NUM_THREADS; i++) WaitForSingleObject( thread[i], 30 * 1000 ); } static void test_WSALookupService(void) { char buffer[4096], strbuff[128]; WSAQUERYSETW *qs = NULL; HANDLE handle; PNLA_BLOB netdata; int ret; DWORD error, offset, size; qs = (WSAQUERYSETW *)buffer; memset(qs, 0, sizeof(*qs)); /* invalid parameter tests */ ret = WSALookupServiceBeginW(NULL, 0, &handle); error = WSAGetLastError(); ok(ret == SOCKET_ERROR, "WSALookupServiceBeginW should have failed\n"); todo_wine ok(error == WSAEFAULT, "expected 10014, got %d\n", error); ret = WSALookupServiceBeginW(qs, 0, NULL); error = WSAGetLastError(); ok(ret == SOCKET_ERROR, "WSALookupServiceBeginW should have failed\n"); todo_wine ok(error == WSAEFAULT, "expected 10014, got %d\n", error); ret = WSALookupServiceBeginW(qs, 0, &handle); ok(ret == SOCKET_ERROR, "WSALookupServiceBeginW should have failed\n"); todo_wine ok(WSAGetLastError() == ERROR_INVALID_PARAMETER || broken(WSAGetLastError() == WSASERVICE_NOT_FOUND) /* win10 1809 */, "got error %u\n", WSAGetLastError()); ret = WSALookupServiceEnd(NULL); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "WSALookupServiceEnd should have failed\n"); todo_wine ok(error == ERROR_INVALID_HANDLE, "expected 6, got %d\n", error); /* standard network list query */ qs->dwSize = sizeof(*qs); handle = (HANDLE)0xdeadbeef; ret = WSALookupServiceBeginW(qs, LUP_RETURN_ALL | LUP_DEEP, &handle); error = WSAGetLastError(); if (ret && error == ERROR_INVALID_PARAMETER) { win_skip("the current WSALookupServiceBeginW test is not supported in win <= 2000\n"); return; } todo_wine ok(!ret, "WSALookupServiceBeginW failed unexpectedly with error %d\n", error); todo_wine ok(handle != (HANDLE)0xdeadbeef, "Handle was not filled\n"); offset = 0; do { memset(qs, 0, sizeof(*qs)); size = sizeof(buffer); if (WSALookupServiceNextW(handle, 0, &size, qs) == SOCKET_ERROR) { ok(WSAGetLastError() == WSA_E_NO_MORE, "got error %u\n", WSAGetLastError()); break; } if (winetest_debug <= 1) continue; WideCharToMultiByte(CP_ACP, 0, qs->lpszServiceInstanceName, -1, strbuff, sizeof(strbuff), NULL, NULL); trace("Network Name: %s\n", strbuff); /* network data is written in the blob field */ if (qs->lpBlob) { /* each network may have multiple NLA_BLOB information structures */ do { netdata = (PNLA_BLOB) &qs->lpBlob->pBlobData[offset]; switch (netdata->header.type) { case NLA_RAW_DATA: trace("\tNLA Data Type: NLA_RAW_DATA\n"); break; case NLA_INTERFACE: trace("\tNLA Data Type: NLA_INTERFACE\n"); trace("\t\tType: %d\n", netdata->data.interfaceData.dwType); trace("\t\tSpeed: %d\n", netdata->data.interfaceData.dwSpeed); trace("\t\tAdapter Name: %s\n", netdata->data.interfaceData.adapterName); break; case NLA_802_1X_LOCATION: trace("\tNLA Data Type: NLA_802_1X_LOCATION\n"); trace("\t\tInformation: %s\n", netdata->data.locationData.information); break; case NLA_CONNECTIVITY: switch (netdata->data.connectivity.type) { case NLA_NETWORK_AD_HOC: trace("\t\tNetwork Type: AD HOC\n"); break; case NLA_NETWORK_MANAGED: trace("\t\tNetwork Type: Managed\n"); break; case NLA_NETWORK_UNMANAGED: trace("\t\tNetwork Type: Unmanaged\n"); break; case NLA_NETWORK_UNKNOWN: trace("\t\tNetwork Type: Unknown\n"); } switch (netdata->data.connectivity.internet) { case NLA_INTERNET_NO: trace("\t\tInternet connectivity: No\n"); break; case NLA_INTERNET_YES: trace("\t\tInternet connectivity: Yes\n"); break; case NLA_INTERNET_UNKNOWN: trace("\t\tInternet connectivity: Unknown\n"); break; } break; case NLA_ICS: trace("\tNLA Data Type: NLA_ICS\n"); trace("\t\tSpeed: %d\n", netdata->data.ICS.remote.speed); trace("\t\tType: %d\n", netdata->data.ICS.remote.type); trace("\t\tState: %d\n", netdata->data.ICS.remote.state); WideCharToMultiByte(CP_ACP, 0, netdata->data.ICS.remote.machineName, -1, strbuff, sizeof(strbuff), NULL, NULL); trace("\t\tMachine Name: %s\n", strbuff); WideCharToMultiByte(CP_ACP, 0, netdata->data.ICS.remote.sharedAdapterName, -1, strbuff, sizeof(strbuff), NULL, NULL); trace("\t\tShared Adapter Name: %s\n", strbuff); break; default: trace("\tNLA Data Type: Unknown\n"); break; } } while (offset); } } while (1); ret = WSALookupServiceEnd(handle); ok(!ret, "WSALookupServiceEnd failed unexpectedly\n"); } #define WM_ASYNCCOMPLETE (WM_USER + 100) static HWND create_async_message_window(void) { static const char class_name[] = "ws2_32 async message window class"; WNDCLASSEXA wndclass; HWND hWnd; wndclass.cbSize = sizeof(wndclass); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = DefWindowProcA; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = GetModuleHandleA(NULL); wndclass.hIcon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION); wndclass.hIconSm = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION); wndclass.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wndclass.lpszClassName = class_name; wndclass.lpszMenuName = NULL; RegisterClassExA(&wndclass); hWnd = CreateWindowA(class_name, "ws2_32 async message window", WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, GetModuleHandleA(NULL), NULL); ok(!!hWnd, "failed to create window\n"); return hWnd; } static void wait_for_async_message(HWND hwnd, HANDLE handle) { BOOL ret; MSG msg; while ((ret = GetMessageA(&msg, 0, 0, 0)) && !(msg.hwnd == hwnd && msg.message == WM_ASYNCCOMPLETE)) { TranslateMessage(&msg); DispatchMessageA(&msg); } ok(ret, "did not expect WM_QUIT message\n"); ok(msg.wParam == (WPARAM)handle, "expected wParam = %p, got %lx\n", handle, msg.wParam); } static void test_WSAAsyncGetServByPort(void) { HWND hwnd = create_async_message_window(); HANDLE ret; char buffer[MAXGETHOSTSTRUCT]; /* FIXME: The asynchronous window messages should be tested. */ /* Parameters are not checked when initiating the asynchronous operation. */ ret = WSAAsyncGetServByPort(NULL, 0, 0, NULL, NULL, 0); ok(ret != NULL, "WSAAsyncGetServByPort returned NULL\n"); ret = WSAAsyncGetServByPort(hwnd, WM_ASYNCCOMPLETE, 0, NULL, NULL, 0); ok(ret != NULL, "WSAAsyncGetServByPort returned NULL\n"); wait_for_async_message(hwnd, ret); ret = WSAAsyncGetServByPort(hwnd, WM_ASYNCCOMPLETE, htons(80), NULL, NULL, 0); ok(ret != NULL, "WSAAsyncGetServByPort returned NULL\n"); wait_for_async_message(hwnd, ret); ret = WSAAsyncGetServByPort(hwnd, WM_ASYNCCOMPLETE, htons(80), NULL, buffer, MAXGETHOSTSTRUCT); ok(ret != NULL, "WSAAsyncGetServByPort returned NULL\n"); wait_for_async_message(hwnd, ret); DestroyWindow(hwnd); } static void test_WSAAsyncGetServByName(void) { HWND hwnd = create_async_message_window(); HANDLE ret; char buffer[MAXGETHOSTSTRUCT]; /* FIXME: The asynchronous window messages should be tested. */ /* Parameters are not checked when initiating the asynchronous operation. */ ret = WSAAsyncGetServByName(hwnd, WM_ASYNCCOMPLETE, "", NULL, NULL, 0); ok(ret != NULL, "WSAAsyncGetServByName returned NULL\n"); wait_for_async_message(hwnd, ret); ret = WSAAsyncGetServByName(hwnd, WM_ASYNCCOMPLETE, "", "", buffer, MAXGETHOSTSTRUCT); ok(ret != NULL, "WSAAsyncGetServByName returned NULL\n"); wait_for_async_message(hwnd, ret); ret = WSAAsyncGetServByName(hwnd, WM_ASYNCCOMPLETE, "http", NULL, NULL, 0); ok(ret != NULL, "WSAAsyncGetServByName returned NULL\n"); wait_for_async_message(hwnd, ret); ret = WSAAsyncGetServByName(hwnd, WM_ASYNCCOMPLETE, "http", "tcp", buffer, MAXGETHOSTSTRUCT); ok(ret != NULL, "WSAAsyncGetServByName returned NULL\n"); wait_for_async_message(hwnd, ret); DestroyWindow(hwnd); } static DWORD WINAPI inet_ntoa_thread_proc(void *param) { ULONG addr; const char *str; HANDLE *event = param; addr = inet_addr("4.3.2.1"); ok(addr == htonl(0x04030201), "expected 0x04030201, got %08x\n", addr); str = inet_ntoa(*(struct in_addr *)&addr); ok(!strcmp(str, "4.3.2.1"), "expected 4.3.2.1, got %s\n", str); SetEvent(event[0]); WaitForSingleObject(event[1], 3000); return 0; } static void test_inet_ntoa(void) { ULONG addr; const char *str; HANDLE thread, event[2]; DWORD tid; addr = inet_addr("1.2.3.4"); ok(addr == htonl(0x01020304), "expected 0x01020304, got %08x\n", addr); str = inet_ntoa(*(struct in_addr *)&addr); ok(!strcmp(str, "1.2.3.4"), "expected 1.2.3.4, got %s\n", str); event[0] = CreateEventW(NULL, TRUE, FALSE, NULL); event[1] = CreateEventW(NULL, TRUE, FALSE, NULL); thread = CreateThread(NULL, 0, inet_ntoa_thread_proc, event, 0, &tid); WaitForSingleObject(event[0], 3000); ok(!strcmp(str, "1.2.3.4"), "expected 1.2.3.4, got %s\n", str); SetEvent(event[1]); WaitForSingleObject(thread, 3000); CloseHandle(event[0]); CloseHandle(event[1]); CloseHandle(thread); } static void test_inet_pton(void) { static const struct { char input[32]; int ret; DWORD addr; } ipv4_tests[] = { {"", 0, 0xdeadbeef}, {" ", 0, 0xdeadbeef}, {"1.1.1.1", 1, 0x01010101}, {"0.0.0.0", 1, 0x00000000}, {"127.127.127.255", 1, 0xff7f7f7f}, {"127.127.127.255:123", 0, 0xff7f7f7f}, {"127.127.127.256", 0, 0xdeadbeef}, {"a", 0, 0xdeadbeef}, {"1.1.1.0xaA", 0, 0xdeadbeef}, {"1.1.1.0x", 0, 0xdeadbeef}, {"1.1.1.010", 0, 0xdeadbeef}, {"1.1.1.00", 0, 0xdeadbeef}, {"1.1.1.0a", 0, 0x00010101}, {"1.1.1.0o10", 0, 0x00010101}, {"1.1.1.0b10", 0, 0x00010101}, {"1.1.1.-2", 0, 0xdeadbeef}, {"1", 0, 0xdeadbeef}, {"1.2", 0, 0xdeadbeef}, {"1.2.3", 0, 0xdeadbeef}, {"203569230", 0, 0xdeadbeef}, {"3.4.5.6.7", 0, 0xdeadbeef}, {" 3.4.5.6", 0, 0xdeadbeef}, {"\t3.4.5.6", 0, 0xdeadbeef}, {"3.4.5.6 ", 0, 0x06050403}, {"3. 4.5.6", 0, 0xdeadbeef}, {"[0.1.2.3]", 0, 0xdeadbeef}, {"0x00010203", 0, 0xdeadbeef}, {"0x2134", 0, 0xdeadbeef}, {"1234BEEF", 0, 0xdeadbeef}, {"017700000001", 0, 0xdeadbeef}, {"0777", 0, 0xdeadbeef}, {"2607:f0d0:1002:51::4", 0, 0xdeadbeef}, {"::177.32.45.20", 0, 0xdeadbeef}, {"::1/128", 0, 0xdeadbeef}, {"::1", 0, 0xdeadbeef}, {":1", 0, 0xdeadbeef}, }; static const struct { char input[64]; int ret; unsigned short addr[8]; } ipv6_tests[] = { {"0000:0000:0000:0000:0000:0000:0000:0000", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"0000:0000:0000:0000:0000:0000:0000:0001", 1, {0, 0, 0, 0, 0, 0, 0, 0x100}}, {"0:0:0:0:0:0:0:0", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"0:0:0:0:0:0:0:1", 1, {0, 0, 0, 0, 0, 0, 0, 0x100}}, {"0:0:0:0:0:0:0::", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"0:0:0:0:0:0:13.1.68.3", 1, {0, 0, 0, 0, 0, 0, 0x10d, 0x344}}, {"0:0:0:0:0:0::", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"0:0:0:0:0::", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"0:0:0:0:0:FFFF:129.144.52.38", 1, {0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634}}, {"0::", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"0:1:2:3:4:5:6:7", 1, {0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700}}, {"1080:0:0:0:8:800:200c:417a", 1, {0x8010, 0, 0, 0, 0x800, 0x8, 0x0c20, 0x7a41}}, {"0:a:b:c:d:e:f::", 1, {0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0}}, {"1111:2222:3333:4444:5555:6666:123.123.123.123", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b}}, {"1111:2222:3333:4444:5555:6666:7777:8888", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888}}, {"1111:2222:3333:4444:0x5555:6666:7777:8888", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444:x555:6666:7777:8888", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444:0r5555:6666:7777:8888", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444:r5555:6666:7777:8888", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444:5555:6666:7777::", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0}}, {"1111:2222:3333:4444:5555:6666::", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0}}, {"1111:2222:3333:4444:5555:6666::8888", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x8888}}, {"1111:2222:3333:4444:5555:6666::7777:8888", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x7777}}, {"1111:2222:3333:4444:5555:6666:7777::8888", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0}}, {"1111:2222:3333:4444:5555::", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0}}, {"1111:2222:3333:4444:5555::123.123.123.123", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7b7b, 0x7b7b}}, {"1111:2222:3333:4444:5555::0x1.123.123.123", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x100}}, {"1111:2222:3333:4444:5555::0x88", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800}}, {"1111:2222:3333:4444:5555::0X88", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800}}, {"1111:2222:3333:4444:5555::0X", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0}}, {"1111:2222:3333:4444:5555::0X88:7777", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800}}, {"1111:2222:3333:4444:5555::0x8888", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888}}, {"1111:2222:3333:4444:5555::0x80000000", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0xffff}}, {"1111:2222:3333:4444::5555:0x012345678", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0, 0, 0x5555, 0x7856}}, {"1111:2222:3333:4444::5555:0x123456789", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0, 0, 0x5555, 0xffff}}, {"1111:2222:3333:4444:5555:6666:0x12345678", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0xabab, 0xabab}}, {"1111:2222:3333:4444:5555:6666:7777:0x80000000", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0xffff}}, {"1111:2222:3333:4444:5555:6666:7777:0x012345678", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x7856}}, {"1111:2222:3333:4444:5555:6666:7777:0x123456789", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0xffff}}, {"111:222:333:444:555:666:777:0x123456789abcdef0", 0, {0x1101, 0x2202, 0x3303, 0x4404, 0x5505, 0x6606, 0x7707, 0xffff}}, {"1111:2222:3333:4444:5555::08888", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444:5555::08888::", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444:5555:6666:7777:fffff:", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0xabab}}, {"1111:2222:3333:4444:5555:6666::fffff:", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0xabab, 0xabab}}, {"1111:2222:3333:4444:5555::fffff", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444::fffff", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333::fffff", 0, {0x1111, 0x2222, 0x3333, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444:5555::7777:8888", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7777, 0x8888}}, {"1111:2222:3333:4444:5555::8888", 1, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888}}, {"1111::", 1, {0x1111, 0, 0, 0, 0, 0, 0, 0}}, {"1111::123.123.123.123", 1, {0x1111, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b}}, {"1111::3333:4444:5555:6666:123.123.123.123", 1, {0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b}}, {"1111::3333:4444:5555:6666:7777:8888", 1, {0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888}}, {"1111::4444:5555:6666:123.123.123.123", 1, {0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b}}, {"1111::4444:5555:6666:7777:8888", 1, {0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888}}, {"1111::5555:6666:123.123.123.123", 1, {0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7b7b, 0x7b7b}}, {"1111::5555:6666:7777:8888", 1, {0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7777, 0x8888}}, {"1111::6666:123.123.123.123", 1, {0x1111, 0, 0, 0, 0, 0x6666, 0x7b7b, 0x7b7b}}, {"1111::6666:7777:8888", 1, {0x1111, 0, 0, 0, 0, 0x6666, 0x7777, 0x8888}}, {"1111::7777:8888", 1, {0x1111, 0, 0, 0, 0, 0, 0x7777, 0x8888}}, {"1111::8888", 1, {0x1111, 0, 0, 0, 0, 0, 0, 0x8888}}, {"1:2:3:4:5:6:1.2.3.4", 1, {0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x201, 0x403}}, {"1:2:3:4:5:6:7:8", 1, {0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800}}, {"1:2:3:4:5:6::", 1, {0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0}}, {"1:2:3:4:5:6::8", 1, {0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0x800}}, {"2001:0000:1234:0000:0000:C1C0:ABCD:0876", 1, {0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608}}, {"2001:0000:4136:e378:8000:63bf:3fff:fdd2", 1, {0x120, 0, 0x3641, 0x78e3, 0x80, 0xbf63, 0xff3f, 0xd2fd}}, {"2001:0db8:0:0:0:0:1428:57ab", 1, {0x120, 0xb80d, 0, 0, 0, 0, 0x2814, 0xab57}}, {"2001:0db8:1234:ffff:ffff:ffff:ffff:ffff", 1, {0x120, 0xb80d, 0x3412, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}}, {"2001::CE49:7601:2CAD:DFFF:7C94:FFFE", 1, {0x120, 0, 0x49ce, 0x176, 0xad2c, 0xffdf, 0x947c, 0xfeff}}, {"2001:db8:85a3::8a2e:370:7334", 1, {0x120, 0xb80d, 0xa385, 0, 0, 0x2e8a, 0x7003, 0x3473}}, {"3ffe:0b00:0000:0000:0001:0000:0000:000a", 1, {0xfe3f, 0xb, 0, 0, 0x100, 0, 0, 0xa00}}, {"::", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::%16", 0, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::/16", 0, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::01234", 0, {0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"::0", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::0:0", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::0:0:0", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::0:0:0:0", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::0:0:0:0:0", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::0:0:0:0:0:0", 1, {0, 0, 0, 0, 0, 0, 0, 0}}, /* this one and the next one are incorrectly parsed by windows, it adds one zero too many in front, cutting off the last digit. */ {"::0:0:0:0:0:0:0", 0, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::0:a:b:c:d:e:f", 0, {0, 0, 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00}}, {"::123.123.123.123", 1, {0, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b}}, {"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 1, {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}}, {"':10.0.0.1", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"-1", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"02001:0000:1234:0000:0000:C1C0:ABCD:0876", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"2001:00000:1234:0000:0000:C1C0:ABCD:0876", 0, {0x120, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"2001:0000:01234:0000:0000:C1C0:ABCD:0876", 0, {0x120, 0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"2001:0000::01234.0", 0, {0x120, 0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"2001:0::b.0", 0, {0x120, 0, 0, 0, 0, 0, 0, 0xb00}}, {"2001::0:b.0", 0, {0x120, 0, 0, 0, 0, 0, 0, 0xb00}}, {"1.2.3.4", 0, {0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1.2.3.4:1111::5555", 0, {0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1.2.3.4::5555", 0, {0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"11112222:3333:4444:5555:6666:1.2.3.4", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"11112222:3333:4444:5555:6666:7777:8888", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"0x1111", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:22223333:4444:5555:6666:1.2.3.4", 0, {0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:22223333:4444:5555:6666:7777:8888", 0, {0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:123456789:4444:5555:6666:7777:8888", 0, {0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:1234567890abcdef0:4444:5555:6666:7777:888", 0, {0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:", 0, {0x1111, 0x2222, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:1.2.3.4", 0, {0x1111, 0x2222, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333", 0, {0x1111, 0x2222, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111:2222:3333:4444:5555:6666::1.2.3.4", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x100}}, {"1111:2222:3333:4444:5555:6666:7777:1.2.3.4", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x100}}, {"1111:2222:3333:4444:5555:6666:7777:8888:", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888}}, {"1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4",0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888}}, {"1111:2222:3333:4444:5555:6666:7777:8888:9999", 0, {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888}}, {"1111:2222:::", 0, {0x1111, 0x2222, 0, 0, 0, 0, 0, 0}}, {"1111::5555:", 0, {0x1111, 0x5555, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1111::3333:4444:5555:6666:7777::", 0, {0x1111, 0, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777}}, {"1111:2222:::4444:5555:6666:1.2.3.4", 0, {0x1111, 0x2222, 0, 0, 0, 0, 0, 0}}, {"1111::3333::5555:6666:1.2.3.4", 0, {0x1111, 0, 0, 0, 0, 0, 0, 0x3333}}, {"12345::6:7:8", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::001.2.3.4", 1, {0x100, 0, 0, 0, 0, 0, 0x201, 0x403}}, {"1::1.002.3.4", 1, {0x100, 0, 0, 0, 0, 0, 0x201, 0x403}}, {"1::0001.2.3.4", 0, {0x100, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.0002.3.4", 0, {0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.256.4", 0, {0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.4294967296.4", 0, {0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.18446744073709551616.4", 0, {0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3.256", 0, {0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3.4294967296", 0, {0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3.18446744073709551616", 0, {0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3.300", 0, {0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3.300.", 0, {0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2::1", 0, {0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3.4::1", 0, {0x100, 0, 0, 0, 0, 0, 0x201, 0x403}}, {"1::1.", 0, {0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2", 0, {0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.", 0, {0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3", 0, {0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3.", 0, {0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.3.4", 1, {0x100, 0, 0, 0, 0, 0, 0x201, 0x403}}, {"1::1.2.3.900", 0, {0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2.300.4", 0, {0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.256.3.4", 0, {0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.256:3.4", 0, {0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1.2a.3.4", 0, {0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::256.2.3.4", 0, {0x100, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"1::1a.2.3.4", 0, {0x100, 0, 0, 0, 0, 0, 0, 0x1a00}}, {"1::2::3", 0, {0x100, 0, 0, 0, 0, 0, 0, 0x200}}, {"2001:0000:1234: 0000:0000:C1C0:ABCD:0876", 0, {0x120, 0, 0x3412, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"2001:0000:1234:0000:0000:C1C0:ABCD:0876 0", 0, {0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608}}, {"2001:1:1:1:1:1:255Z255X255Y255", 0, {0x120, 0x100, 0x100, 0x100, 0x100, 0x100, 0xabab, 0xabab}}, {"2001::FFD3::57ab", 0, {0x120, 0, 0, 0, 0, 0, 0, 0xd3ff}}, {":", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {":1111:2222:3333:4444:5555:6666:1.2.3.4", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {":1111:2222:3333:4444:5555:6666:7777:8888", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {":1111::", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"::-1", 0, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::12345678", 0, {0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"::123456789", 0, {0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"::1234567890abcdef0", 0, {0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"::0x80000000", 0, {0, 0, 0, 0, 0, 0, 0, 0xffff}}, {"::0x012345678", 0, {0, 0, 0, 0, 0, 0, 0, 0x7856}}, {"::0x123456789", 0, {0, 0, 0, 0, 0, 0, 0, 0xffff}}, {"::0x1234567890abcdef0", 0, {0, 0, 0, 0, 0, 0, 0, 0xffff}}, {"::.", 0, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::..", 0, {0, 0, 0, 0, 0, 0, 0, 0}}, {"::...", 0, {0, 0, 0, 0, 0, 0, 0, 0}}, {"XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, {"[::]", 0, {0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab}}, }; BYTE buffer[32]; int i, ret; /* inet_ntop and inet_pton became available in Vista and Win2008 */ if (!p_inet_ntop) { win_skip("inet_ntop is not available\n"); return; } WSASetLastError(0xdeadbeef); ret = p_inet_pton(AF_UNSPEC, NULL, buffer); ok(ret == -1, "got %d\n", ret); ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); WSASetLastError(0xdeadbeef); ret = p_inet_pton(AF_INET, NULL, buffer); ok(ret == -1, "got %d\n", ret); ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); WSASetLastError(0xdeadbeef); ret = pInetPtonW(AF_UNSPEC, NULL, buffer); ok(ret == -1, "got %d\n", ret); ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); WSASetLastError(0xdeadbeef); ret = pInetPtonW(AF_INET, NULL, buffer); ok(ret == -1, "got %d\n", ret); ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); WSASetLastError(0xdeadbeef); ret = p_inet_pton(AF_UNSPEC, "127.0.0.1", buffer); ok(ret == -1, "got %d\n", ret); ok(WSAGetLastError() == WSAEAFNOSUPPORT, "got error %u\n", WSAGetLastError()); WSASetLastError(0xdeadbeef); ret = p_inet_pton(AF_UNSPEC, "2607:f0d0:1002:51::4", buffer); ok(ret == -1, "got %d\n", ret); ok(WSAGetLastError() == WSAEAFNOSUPPORT, "got error %u\n", WSAGetLastError()); WSASetLastError(0xdeadbeef); ret = inet_addr(NULL); ok(ret == INADDR_NONE, "got %#x\n", ret); ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); for (i = 0; i < ARRAY_SIZE(ipv4_tests); ++i) { WCHAR inputW[32]; DWORD addr; WSASetLastError(0xdeadbeef); addr = 0xdeadbeef; ret = p_inet_pton(AF_INET, ipv4_tests[i].input, &addr); ok(ret == ipv4_tests[i].ret, "%s: got %d\n", debugstr_a(ipv4_tests[i].input), ret); ok(WSAGetLastError() == 0xdeadbeef, "%s: got error %u\n", debugstr_a(ipv4_tests[i].input), WSAGetLastError()); ok(addr == ipv4_tests[i].addr, "%s: got addr %#08x\n", debugstr_a(ipv4_tests[i].input), addr); MultiByteToWideChar(CP_ACP, 0, ipv4_tests[i].input, -1, inputW, ARRAY_SIZE(inputW)); WSASetLastError(0xdeadbeef); addr = 0xdeadbeef; ret = pInetPtonW(AF_INET, inputW, &addr); ok(ret == ipv4_tests[i].ret, "%s: got %d\n", debugstr_a(ipv4_tests[i].input), ret); ok(WSAGetLastError() == (ret ? 0xdeadbeef : WSAEINVAL), "%s: got error %u\n", debugstr_a(ipv4_tests[i].input), WSAGetLastError()); ok(addr == ipv4_tests[i].addr, "%s: got addr %#08x\n", debugstr_a(ipv4_tests[i].input), addr); WSASetLastError(0xdeadbeef); addr = inet_addr(ipv4_tests[i].input); ok(addr == ipv4_tests[i].ret ? ipv4_tests[i].addr : INADDR_NONE, "%s: got addr %#08x\n", debugstr_a(ipv4_tests[i].input), addr); ok(WSAGetLastError() == 0xdeadbeef, "%s: got error %u\n", debugstr_a(ipv4_tests[i].input), WSAGetLastError()); } for (i = 0; i < ARRAY_SIZE(ipv6_tests); ++i) { unsigned short addr[8]; WCHAR inputW[64]; WSASetLastError(0xdeadbeef); memset(addr, 0xab, sizeof(addr)); ret = p_inet_pton(AF_INET6, ipv6_tests[i].input, addr); ok(ret == ipv6_tests[i].ret, "%s: got %d\n", debugstr_a(ipv6_tests[i].input), ret); ok(WSAGetLastError() == 0xdeadbeef, "%s: got error %u\n", debugstr_a(ipv6_tests[i].input), WSAGetLastError()); ok(!memcmp(addr, ipv6_tests[i].addr, sizeof(addr)), "%s: address didn't match\n", debugstr_a(ipv6_tests[i].input)); MultiByteToWideChar(CP_ACP, 0, ipv6_tests[i].input, -1, inputW, ARRAY_SIZE(inputW)); WSASetLastError(0xdeadbeef); memset(addr, 0xab, sizeof(addr)); ret = pInetPtonW(AF_INET6, inputW, addr); ok(ret == ipv6_tests[i].ret, "%s: got %d\n", debugstr_a(ipv6_tests[i].input), ret); ok(WSAGetLastError() == (ret ? 0xdeadbeef : WSAEINVAL), "%s: got error %u\n", debugstr_a(ipv6_tests[i].input), WSAGetLastError()); ok(!memcmp(addr, ipv6_tests[i].addr, sizeof(addr)), "%s: address didn't match\n", debugstr_a(ipv6_tests[i].input)); } } static void test_addr_to_print(void) { char dst[16]; char dst6[64]; const char *pdst; struct in_addr in; struct in6_addr in6; u_long addr0_Num = 0x00000000; const char *addr0_Str = "0.0.0.0"; u_long addr1_Num = 0x20201015; const char *addr1_Str = "21.16.32.32"; u_char addr2_Num[16] = {0,0,0,0,0,0,0,0,0,0,0xff,0xfe,0xcC,0x98,0xbd,0x74}; const char *addr2_Str = "::fffe:cc98:bd74"; u_char addr3_Num[16] = {0x20,0x30,0xa4,0xb1}; const char *addr3_Str = "2030:a4b1::"; u_char addr4_Num[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0xcC,0x98,0xbd,0x74}; const char *addr4_Str = "::204.152.189.116"; /* Test IPv4 addresses */ in.s_addr = addr0_Num; pdst = inet_ntoa(*((struct in_addr *)&in.s_addr)); ok(pdst != NULL, "inet_ntoa failed %s\n", dst); ok(!strcmp(pdst, addr0_Str),"Address %s != %s\n", pdst, addr0_Str); /* Test that inet_ntoa and inet_ntop return the same value */ in.S_un.S_addr = addr1_Num; pdst = inet_ntoa(*((struct in_addr *)&in.s_addr)); ok(pdst != NULL, "inet_ntoa failed %s\n", dst); ok(!strcmp(pdst, addr1_Str),"Address %s != %s\n", pdst, addr1_Str); /* inet_ntop became available in Vista and Win2008 */ if (!p_inet_ntop) { win_skip("InetNtop not present, not executing tests\n"); return; } /* Second part of test */ pdst = p_inet_ntop(AF_INET, &in.s_addr, dst, sizeof(dst)); ok(pdst != NULL, "InetNtop failed %s\n", dst); ok(!strcmp(pdst, addr1_Str),"Address %s != %s\n", pdst, addr1_Str); /* Test invalid parm conditions */ pdst = p_inet_ntop(1, (void *)&in.s_addr, dst, sizeof(dst)); ok(pdst == NULL, "The pointer should not be returned (%p)\n", pdst); ok(WSAGetLastError() == WSAEAFNOSUPPORT, "Should be WSAEAFNOSUPPORT\n"); /* Test Null destination */ pdst = NULL; pdst = p_inet_ntop(AF_INET, &in.s_addr, NULL, sizeof(dst)); ok(pdst == NULL, "The pointer should not be returned (%p)\n", pdst); ok(WSAGetLastError() == STATUS_INVALID_PARAMETER || WSAGetLastError() == WSAEINVAL /* Win7 */, "Should be STATUS_INVALID_PARAMETER or WSAEINVAL not 0x%x\n", WSAGetLastError()); /* Test zero length passed */ WSASetLastError(0); pdst = NULL; pdst = p_inet_ntop(AF_INET, &in.s_addr, dst, 0); ok(pdst == NULL, "The pointer should not be returned (%p)\n", pdst); ok(WSAGetLastError() == STATUS_INVALID_PARAMETER || WSAGetLastError() == WSAEINVAL /* Win7 */, "Should be STATUS_INVALID_PARAMETER or WSAEINVAL not 0x%x\n", WSAGetLastError()); /* Test length one shorter than the address length */ WSASetLastError(0); pdst = NULL; pdst = p_inet_ntop(AF_INET, &in.s_addr, dst, 6); ok(pdst == NULL, "The pointer should not be returned (%p)\n", pdst); ok(WSAGetLastError() == STATUS_INVALID_PARAMETER || WSAGetLastError() == WSAEINVAL /* Win7 */, "Should be STATUS_INVALID_PARAMETER or WSAEINVAL not 0x%x\n", WSAGetLastError()); /* Test longer length is ok */ WSASetLastError(0); pdst = NULL; pdst = p_inet_ntop(AF_INET, &in.s_addr, dst, sizeof(dst)+1); ok(pdst != NULL, "The pointer should be returned (%p)\n", pdst); ok(!strcmp(pdst, addr1_Str),"Address %s != %s\n", pdst, addr1_Str); /* Test the IPv6 addresses */ /* Test an zero prefixed IPV6 address */ memcpy(in6.u.Byte, addr2_Num, sizeof(addr2_Num)); pdst = p_inet_ntop(AF_INET6, &in6.s6_addr, dst6, sizeof(dst6)); ok(pdst != NULL, "InetNtop failed %s\n", dst6); ok(!strcmp(pdst, addr2_Str),"Address %s != %s\n", pdst, addr2_Str); /* Test an zero suffixed IPV6 address */ memcpy(in6.s6_addr, addr3_Num, sizeof(addr3_Num)); pdst = p_inet_ntop(AF_INET6, &in6.s6_addr, dst6, sizeof(dst6)); ok(pdst != NULL, "InetNtop failed %s\n", dst6); ok(!strcmp(pdst, addr3_Str),"Address %s != %s\n", pdst, addr3_Str); /* Test the IPv6 address contains the IPv4 address in IPv4 notation */ memcpy(in6.s6_addr, addr4_Num, sizeof(addr4_Num)); pdst = p_inet_ntop(AF_INET6, &in6.s6_addr, dst6, sizeof(dst6)); ok(pdst != NULL, "InetNtop failed %s\n", dst6); ok(!strcmp(pdst, addr4_Str),"Address %s != %s\n", pdst, addr4_Str); /* Test invalid parm conditions */ memcpy(in6.u.Byte, addr2_Num, sizeof(addr2_Num)); /* Test Null destination */ pdst = NULL; pdst = p_inet_ntop(AF_INET6, &in6.s6_addr, NULL, sizeof(dst6)); ok(pdst == NULL, "The pointer should not be returned (%p)\n", pdst); ok(WSAGetLastError() == STATUS_INVALID_PARAMETER || WSAGetLastError() == WSAEINVAL /* Win7 */, "Should be STATUS_INVALID_PARAMETER or WSAEINVAL not 0x%x\n", WSAGetLastError()); /* Test zero length passed */ WSASetLastError(0); pdst = NULL; pdst = p_inet_ntop(AF_INET6, &in6.s6_addr, dst6, 0); ok(pdst == NULL, "The pointer should not be returned (%p)\n", pdst); ok(WSAGetLastError() == STATUS_INVALID_PARAMETER || WSAGetLastError() == WSAEINVAL /* Win7 */, "Should be STATUS_INVALID_PARAMETER or WSAEINVAL not 0x%x\n", WSAGetLastError()); /* Test length one shorter than the address length */ WSASetLastError(0); pdst = NULL; pdst = p_inet_ntop(AF_INET6, &in6.s6_addr, dst6, 16); ok(pdst == NULL, "The pointer should not be returned (%p)\n", pdst); ok(WSAGetLastError() == STATUS_INVALID_PARAMETER || WSAGetLastError() == WSAEINVAL /* Win7 */, "Should be STATUS_INVALID_PARAMETER or WSAEINVAL not 0x%x\n", WSAGetLastError()); /* Test longer length is ok */ WSASetLastError(0); pdst = NULL; pdst = p_inet_ntop(AF_INET6, &in6.s6_addr, dst6, 18); ok(pdst != NULL, "The pointer should be returned (%p)\n", pdst); } static void test_WSAAddressToString(void) { static struct { ULONG address; USHORT port; char output[32]; } ipv4_tests[] = { { 0, 0, "0.0.0.0" }, { 0xffffffff, 0, "255.255.255.255" }, { 0, 0xffff, "0.0.0.0:65535" }, { 0xffffffff, 0xffff, "255.255.255.255:65535" }, }; static struct { USHORT address[8]; ULONG scope; USHORT port; char output[64]; } ipv6_tests[] = { { { 0, 0, 0, 0, 0, 0, 0, 0x100 }, 0, 0, "::1" }, { { 0xab20, 0, 0, 0, 0, 0, 0, 0x100 }, 0, 0, "20ab::1" }, { { 0xab20, 0, 0, 0, 0, 0, 0, 0x120 }, 0, 0xfa81, "[20ab::2001]:33274" }, { { 0xab20, 0, 0, 0, 0, 0, 0, 0x120 }, 0x1234, 0xfa81, "[20ab::2001%4660]:33274" }, { { 0xab20, 0, 0, 0, 0, 0, 0, 0x120 }, 0x1234, 0, "20ab::2001%4660" }, }; SOCKADDR_IN sockaddr; SOCKADDR_IN6 sockaddr6; char output[64]; WCHAR outputW[64], expected_outputW[64]; SOCKET v6; INT ret; DWORD len; int i, j; len = 0; sockaddr.sin_family = AF_INET; sockaddr.sin_addr.s_addr = 0; sockaddr.sin_port = 0; WSASetLastError( 0xdeadbeef ); ret = WSAAddressToStringA( (SOCKADDR *)&sockaddr, sizeof(sockaddr), NULL, output, &len ); ok( ret == SOCKET_ERROR, "WSAAddressToStringA() returned %d, expected SOCKET_ERROR\n", ret ); ok( WSAGetLastError() == WSAEFAULT, "WSAAddressToStringA() gave error %d, expected WSAEFAULT\n", WSAGetLastError() ); ok( len == 8, "WSAAddressToStringA() gave length %d, expected 8\n", len ); len = 0; sockaddr.sin_family = AF_INET; sockaddr.sin_addr.s_addr = 0; sockaddr.sin_port = 0; WSASetLastError( 0xdeadbeef ); ret = WSAAddressToStringW( (SOCKADDR *)&sockaddr, sizeof(sockaddr), NULL, NULL, &len ); ok( ret == SOCKET_ERROR, "got %d\n", ret ); ok( WSAGetLastError() == WSAEFAULT, "got %08x\n", WSAGetLastError() ); ok( len == 8, "got %u\n", len ); len = ARRAY_SIZE(outputW); memset( outputW, 0, sizeof(outputW) ); ret = WSAAddressToStringW( (SOCKADDR *)&sockaddr, sizeof(sockaddr), NULL, outputW, &len ); ok( !ret, "WSAAddressToStringW() returned %d\n", ret ); ok( len == 8, "got %u\n", len ); ok( !wcscmp(outputW, L"0.0.0.0"), "got %s\n", wine_dbgstr_w(outputW) ); for (i = 0; i < 2; i++) { for (j = 0; j < ARRAY_SIZE(ipv4_tests); j++) { sockaddr.sin_family = AF_INET; sockaddr.sin_addr.s_addr = ipv4_tests[j].address; sockaddr.sin_port = ipv4_tests[j].port; if (i == 0) { len = sizeof(output); memset(output, 0, len); ret = WSAAddressToStringA( (SOCKADDR *)&sockaddr, sizeof(sockaddr), NULL, output, &len ); ok( !ret, "ipv4_tests[%d] failed unexpectedly: %d\n", j, WSAGetLastError() ); ok( !strcmp( output, ipv4_tests[j].output ), "ipv4_tests[%d]: got address %s, expected %s\n", j, wine_dbgstr_a(output), wine_dbgstr_a(ipv4_tests[j].output) ); ok( len == strlen(ipv4_tests[j].output) + 1, "ipv4_tests[%d]: got length %d, expected %d\n", j, len, strlen(ipv4_tests[j].output) + 1 ); } else { len = sizeof(outputW); memset(outputW, 0, len); ret = WSAAddressToStringW( (SOCKADDR *)&sockaddr, sizeof(sockaddr), NULL, outputW, &len ); MultiByteToWideChar( CP_ACP, 0, ipv4_tests[j].output, -1, expected_outputW, ARRAY_SIZE(expected_outputW) ); ok( !ret, "ipv4_tests[%d] failed unexpectedly: %d\n", j, WSAGetLastError() ); ok( !wcscmp( outputW, expected_outputW ), "ipv4_tests[%d]: got address %s, expected %s\n", j, wine_dbgstr_w(outputW), wine_dbgstr_w(expected_outputW) ); ok( len == wcslen(expected_outputW) + 1, "ipv4_tests[%d]: got length %d, expected %d\n", j, len, wcslen(expected_outputW) + 1 ); } } /* check to see if IPv6 is available */ v6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if (v6 == INVALID_SOCKET) { skip("Could not create IPv6 socket (LastError: %d; %d expected if IPv6 not available).\n", WSAGetLastError(), WSAEAFNOSUPPORT); continue; } closesocket(v6); for (j = 0; j < ARRAY_SIZE(ipv6_tests); j++) { sockaddr6.sin6_family = AF_INET6; sockaddr6.sin6_scope_id = ipv6_tests[j].scope; sockaddr6.sin6_port = ipv6_tests[j].port; memcpy( sockaddr6.sin6_addr.s6_addr, ipv6_tests[j].address, sizeof(ipv6_tests[j].address) ); if (i == 0) { len = sizeof(output); ret = WSAAddressToStringA( (SOCKADDR *)&sockaddr6, sizeof(sockaddr6), NULL, output, &len ); ok( !ret, "ipv6_tests[%d] failed unexpectedly: %d\n", j, WSAGetLastError() ); ok( !strcmp( output, ipv6_tests[j].output ), "ipv6_tests[%d]: gave address %s, expected %s\n", j, wine_dbgstr_a(output), wine_dbgstr_a(ipv6_tests[j].output) ); ok( len == strlen(ipv6_tests[j].output) + 1, "ipv6_tests[%d]: got length %d, expected %d\n", j, len, strlen(ipv6_tests[j].output) + 1 ); } else { len = sizeof(outputW); ret = WSAAddressToStringW( (SOCKADDR *)&sockaddr6, sizeof(sockaddr6), NULL, outputW, &len ); MultiByteToWideChar( CP_ACP, 0, ipv6_tests[j].output, -1, expected_outputW, ARRAY_SIZE(expected_outputW) ); ok( !ret, "ipv6_tests[%d] failed unexpectedly: %d\n", j, WSAGetLastError() ); ok( !wcscmp( outputW, expected_outputW ), "ipv6_tests[%d]: got address %s, expected %s\n", j, wine_dbgstr_w(outputW), wine_dbgstr_w(expected_outputW) ); ok( len == wcslen(expected_outputW) + 1, "ipv6_tests[%d]: got length %d, expected %d\n", j, len, wcslen(expected_outputW) + 1 ); } } } } static void test_WSAStringToAddress(void) { static struct { char input[32]; ULONG address; USHORT port; int error; } ipv4_tests[] = { { "", 0, 0, WSAEINVAL }, { " ", 0, 0, WSAEINVAL }, { "1.1.1.1", 0x01010101 }, { "0.0.0.0", 0 }, { "127.127.127.127", 0x7f7f7f7f }, { "127.127.127.127:", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:0", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:123", 0x7f7f7f7f, 123 }, { "127.127.127.127:65535", 0x7f7f7f7f, 65535 }, { "127.127.127.127:65537", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127::1", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:0xAbCd", 0x7f7f7f7f, 43981 }, { "127.127.127.127:0XaBcD", 0x7f7f7f7f, 43981 }, { "127.127.127.127:0x", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:0x10000",0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:010", 0x7f7f7f7f, 8 }, { "127.127.127.127:007", 0x7f7f7f7f, 7 }, { "127.127.127.127:08", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:008", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:0a", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:0o10", 0x7f7f7f7f, 0, WSAEINVAL }, { "127.127.127.127:0b10", 0x7f7f7f7f, 0, WSAEINVAL }, { "255.255.255.255", 0xffffffff }, { "255.255.255.255:123", 0xffffffff, 123 }, { "255.255.255.255:65535", 0xffffffff, 65535 }, { "255.255.255.256", 0, 0, WSAEINVAL }, { "a", 0, 0, WSAEINVAL }, { "1.1.1.0xaA", 0x010101aa }, { "1.1.1.0XaA", 0x010101aa }, { "1.1.1.0x", 0, 0, WSAEINVAL }, { "1.1.1.0xff", 0x010101ff }, { "1.1.1.0x100", 0, 0, WSAEINVAL }, { "1.1.1.010", 0x01010108 }, { "1.1.1.00", 0x01010100 }, { "1.1.1.007", 0x01010107 }, { "1.1.1.08", 0, 0, WSAEINVAL }, { "1.1.1.008", 0x01010100, 0, WSAEINVAL }, { "1.1.1.0a", 0x01010100, 0, WSAEINVAL }, { "1.1.1.0o10", 0x01010100, 0, WSAEINVAL }, { "1.1.1.0b10", 0x01010100, 0, WSAEINVAL }, { "1.1.1.-2", 0, 0, WSAEINVAL }, { "1", 0x00000001 }, { "-1", 0, 0, WSAEINVAL }, { "1:1", 0x00000001, 1 }, { "1.2", 0x01000002 }, { "1.2:1", 0x01000002, 1 }, { "1000.2000", 0, 0, WSAEINVAL }, { "1.2.", 0, 0, WSAEINVAL }, { "1..2", 0, 0, WSAEINVAL }, { "1...2", 0, 0, WSAEINVAL }, { "1.2.3", 0x01020003 }, { "1.2.3.", 0, 0, WSAEINVAL }, { "1.2.3:1", 0x01020003, 1 }, { "203569230", 0x0c22384e }, { "203569230:123", 0x0c22384e, 123 }, { "2001::1", 0x000007d1, 0, WSAEINVAL }, { "1.223756", 0x01036a0c }, { "3.4.756", 0x030402f4 }, { "756.3.4", 0, 0, WSAEINVAL }, { "3.756.4", 0, 0, WSAEINVAL }, { "3.4.756.1", 0, 0, WSAEINVAL }, { "3.4.65536", 0, 0, WSAEINVAL }, { "3.4.5.6.7", 0, 0, WSAEINVAL }, { "3.4.5.+6", 0, 0, WSAEINVAL }, { " 3.4.5.6", 0, 0, WSAEINVAL }, { "\t3.4.5.6", 0, 0, WSAEINVAL }, { "3.4.5.6 ", 0x03040506, 0, WSAEINVAL }, { "3.4.5.6:7 ", 0x03040506, 0, WSAEINVAL }, { "3.4.5.6: 7", 0x03040506, 0, WSAEINVAL }, { "3. 4.5.6", 0, 0, WSAEINVAL }, { ".", 0, 0, WSAEINVAL }, { "[0.1.2.3]", 0, 0, WSAEINVAL }, { "0x00010203", 0x00010203 }, { "0X00010203", 0x00010203 }, { "0x00010203:10", 0x00010203, 10 }, { "0x1234", 0x00001234 }, { "0x123456789", 0x23456789 }, { "0x00010Q03", 0x00000010, 0, WSAEINVAL }, { "x00010203", 0, 0, WSAEINVAL }, { "1234BEEF", 0x000004d2, 0, WSAEINVAL }, { "017700000001", 0x7f000001 }, { "0777", 0x000001ff }, { "0777:10", 0x000001ff, 10 }, { "::1", 0, 0, WSAEINVAL }, { ":1", 0, 0, WSAEINVAL }, }; static struct { char input[64]; USHORT address[8]; USHORT port; int error; } ipv6_tests[] = { { "::1", { 0, 0, 0, 0, 0, 0, 0, 0x100 } }, { "[::1]", { 0, 0, 0, 0, 0, 0, 0, 0x100 } }, { "[::1]:65535", { 0, 0, 0, 0, 0, 0, 0, 0x100 }, 0xffff }, { "2001::1", { 0x120, 0, 0, 0, 0, 0, 0, 0x100 } }, { "::1]:65535", { 0, 0, 0, 0, 0, 0, 0, 0x100 }, 0, WSAEINVAL }, { "001::1", { 0x100, 0, 0, 0, 0, 0, 0, 0x100 } }, { "::1:2:3:4:5:6:7", { 0, 0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600 }, 0, WSAEINVAL }, /* Windows bug */ { "1.2.3.4", { 0x201, 0x3, 0, 0, 0, 0, 0, 0 }, 0, WSAEINVAL }, { "1:2:3:", { 0x100, 0x200, 0x300, 0, 0, 0, 0 }, 0, WSAEINVAL }, { "", { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, WSAEINVAL }, }; WCHAR inputW[64]; INT len, ret, expected_len, expected_ret; short expected_family; SOCKADDR_IN sockaddr; SOCKADDR_IN6 sockaddr6; int i, j; len = 0; WSASetLastError( 0 ); ret = WSAStringToAddressA( ipv4_tests[0].input, AF_INET, NULL, (SOCKADDR *)&sockaddr, &len ); ok( ret == SOCKET_ERROR, "WSAStringToAddressA() returned %d, expected SOCKET_ERROR\n", ret ); ok( WSAGetLastError() == WSAEFAULT, "WSAStringToAddress() gave error %d, expected WSAEFAULT\n", WSAGetLastError() ); ok( len >= sizeof(sockaddr) || broken(len == 0) /* xp */, "WSAStringToAddress() gave length %d, expected at least %d\n", len, sizeof(sockaddr) ); for (i = 0; i < 2; i++) { for (j = 0; j < ARRAY_SIZE(ipv4_tests); j++) { len = sizeof(sockaddr) + 10; expected_len = ipv4_tests[j].error ? len : sizeof(sockaddr); memset( &sockaddr, 0xab, sizeof(sockaddr) ); WSASetLastError( 0 ); if (i == 0) { ret = WSAStringToAddressA( ipv4_tests[j].input, AF_INET, NULL, (SOCKADDR *)&sockaddr, &len ); } else { MultiByteToWideChar( CP_ACP, 0, ipv4_tests[j].input, -1, inputW, ARRAY_SIZE(inputW) ); ret = WSAStringToAddressW( inputW, AF_INET, NULL, (SOCKADDR *)&sockaddr, &len ); } expected_ret = ipv4_tests[j].error ? SOCKET_ERROR : 0; expected_family = ipv4_tests[j].error ? 0 : AF_INET; ok( ret == expected_ret, "WSAStringToAddress(%s) returned %d, expected %d\n", wine_dbgstr_a( ipv4_tests[j].input ), ret, expected_ret ); ok( WSAGetLastError() == ipv4_tests[j].error, "WSAStringToAddress(%s) gave error %d, expected %d\n", wine_dbgstr_a( ipv4_tests[j].input ), WSAGetLastError(), ipv4_tests[j].error ); ok( sockaddr.sin_family == expected_family, "WSAStringToAddress(%s) gave family %d, expected %d\n", wine_dbgstr_a( ipv4_tests[j].input ), sockaddr.sin_family, expected_family ); ok( sockaddr.sin_addr.s_addr == htonl( ipv4_tests[j].address ), "WSAStringToAddress(%s) gave address %08x, expected %08x\n", wine_dbgstr_a( ipv4_tests[j].input ), sockaddr.sin_addr.s_addr, htonl( ipv4_tests[j].address) ); ok( sockaddr.sin_port == htons( ipv4_tests[j].port ), "WSAStringToAddress(%s) gave port %04x, expected %04x\n", wine_dbgstr_a( ipv4_tests[j].input ), sockaddr.sin_port, htons( ipv4_tests[j].port ) ); ok( len == expected_len, "WSAStringToAddress(%s) gave length %d, expected %d\n", wine_dbgstr_a( ipv4_tests[j].input ), len, expected_len ); } for (j = 0; j < ARRAY_SIZE(ipv6_tests); j++) { len = sizeof(sockaddr6) + 10; expected_len = ipv6_tests[j].error ? len : sizeof(sockaddr6); memset( &sockaddr6, 0xab, sizeof(sockaddr6) ); WSASetLastError( 0 ); if (i == 0) { ret = WSAStringToAddressA( ipv6_tests[j].input, AF_INET6, NULL, (SOCKADDR *)&sockaddr6, &len ); } else { MultiByteToWideChar( CP_ACP, 0, ipv6_tests[j].input, -1, inputW, ARRAY_SIZE(inputW) ); ret = WSAStringToAddressW( inputW, AF_INET6, NULL, (SOCKADDR *)&sockaddr6, &len ); } if (j == 0 && ret == SOCKET_ERROR) { win_skip("IPv6 not supported\n"); break; } expected_ret = ipv6_tests[j].error ? SOCKET_ERROR : 0; expected_family = ipv6_tests[j].error ? 0 : AF_INET6; ok( ret == expected_ret, "WSAStringToAddress(%s) returned %d, expected %d\n", wine_dbgstr_a( ipv6_tests[j].input ), ret, expected_ret ); ok( WSAGetLastError() == ipv6_tests[j].error, "WSAStringToAddress(%s) gave error %d, expected %d\n", wine_dbgstr_a( ipv6_tests[j].input ), WSAGetLastError(), ipv6_tests[j].error ); ok( sockaddr6.sin6_family == expected_family, "WSAStringToAddress(%s) gave family %d, expected %d\n", wine_dbgstr_a( ipv4_tests[j].input ), sockaddr6.sin6_family, expected_family ); ok( memcmp(&sockaddr6.sin6_addr, ipv6_tests[j].address, sizeof(sockaddr6.sin6_addr)) == 0, "WSAStringToAddress(%s) gave address %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n", wine_dbgstr_a( ipv6_tests[j].input ), sockaddr6.sin6_addr.s6_words[0], sockaddr6.sin6_addr.s6_words[1], sockaddr6.sin6_addr.s6_words[2], sockaddr6.sin6_addr.s6_words[3], sockaddr6.sin6_addr.s6_words[4], sockaddr6.sin6_addr.s6_words[5], sockaddr6.sin6_addr.s6_words[6], sockaddr6.sin6_addr.s6_words[7], ipv6_tests[j].address[0], ipv6_tests[j].address[1], ipv6_tests[j].address[2], ipv6_tests[j].address[3], ipv6_tests[j].address[4], ipv6_tests[j].address[5], ipv6_tests[j].address[6], ipv6_tests[j].address[7] ); ok( sockaddr6.sin6_scope_id == 0, "WSAStringToAddress(%s) gave scope %d, expected 0\n", wine_dbgstr_a( ipv6_tests[j].input ), sockaddr6.sin6_scope_id ); ok( sockaddr6.sin6_port == ipv6_tests[j].port, "WSAStringToAddress(%s) gave port %04x, expected %04x\n", wine_dbgstr_a( ipv6_tests[j].input ), sockaddr6.sin6_port, ipv6_tests[j].port ); ok( sockaddr6.sin6_flowinfo == 0, "WSAStringToAddress(%s) gave flowinfo %d, expected 0\n", wine_dbgstr_a( ipv6_tests[j].input ), sockaddr6.sin6_flowinfo ); ok( len == expected_len, "WSAStringToAddress(%s) gave length %d, expected %d\n", wine_dbgstr_a( ipv6_tests[j].input ), len, expected_len ); } } } /* Tests used in both getaddrinfo and GetAddrInfoW */ static const struct addr_hint_tests { int family, socktype, protocol; DWORD error; } hinttests[] = { {AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0}, {AF_UNSPEC, SOCK_STREAM, IPPROTO_UDP, 0}, {AF_UNSPEC, SOCK_STREAM, IPPROTO_IPV6,0}, {AF_UNSPEC, SOCK_DGRAM, IPPROTO_TCP, 0}, {AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, 0}, {AF_UNSPEC, SOCK_DGRAM, IPPROTO_IPV6,0}, {AF_INET, SOCK_STREAM, IPPROTO_TCP, 0}, {AF_INET, SOCK_STREAM, IPPROTO_UDP, 0}, {AF_INET, SOCK_STREAM, IPPROTO_IPV6,0}, {AF_INET, SOCK_DGRAM, IPPROTO_TCP, 0}, {AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0}, {AF_INET, SOCK_DGRAM, IPPROTO_IPV6,0}, {AF_UNSPEC, 0, IPPROTO_TCP, 0}, {AF_UNSPEC, 0, IPPROTO_UDP, 0}, {AF_UNSPEC, 0, IPPROTO_IPV6,0}, {AF_UNSPEC, SOCK_STREAM, 0, 0}, {AF_UNSPEC, SOCK_DGRAM, 0, 0}, {AF_INET, 0, IPPROTO_TCP, 0}, {AF_INET, 0, IPPROTO_UDP, 0}, {AF_INET, 0, IPPROTO_IPV6,0}, {AF_INET, SOCK_STREAM, 0, 0}, {AF_INET, SOCK_DGRAM, 0, 0}, {AF_UNSPEC, 999, IPPROTO_TCP, WSAESOCKTNOSUPPORT}, {AF_UNSPEC, 999, IPPROTO_UDP, WSAESOCKTNOSUPPORT}, {AF_UNSPEC, 999, IPPROTO_IPV6,WSAESOCKTNOSUPPORT}, {AF_INET, 999, IPPROTO_TCP, WSAESOCKTNOSUPPORT}, {AF_INET, 999, IPPROTO_UDP, WSAESOCKTNOSUPPORT}, {AF_INET, 999, IPPROTO_IPV6,WSAESOCKTNOSUPPORT}, {AF_UNSPEC, SOCK_STREAM, 999, 0}, {AF_UNSPEC, SOCK_STREAM, 999, 0}, {AF_INET, SOCK_DGRAM, 999, 0}, {AF_INET, SOCK_DGRAM, 999, 0}, }; static void compare_addrinfow(ADDRINFOW *a, ADDRINFOW *b) { for (; a && b; a = a->ai_next, b = b->ai_next) { ok(a->ai_flags == b->ai_flags, "Wrong flags %d != %d\n", a->ai_flags, b->ai_flags); ok(a->ai_family == b->ai_family, "Wrong family %d != %d\n", a->ai_family, b->ai_family); ok(a->ai_socktype == b->ai_socktype, "Wrong socktype %d != %d\n", a->ai_socktype, b->ai_socktype); ok(a->ai_protocol == b->ai_protocol, "Wrong protocol %d != %d\n", a->ai_protocol, b->ai_protocol); ok(a->ai_addrlen == b->ai_addrlen, "Wrong addrlen %lu != %lu\n", a->ai_addrlen, b->ai_addrlen); ok(!memcmp(a->ai_addr, b->ai_addr, min(a->ai_addrlen, b->ai_addrlen)), "Wrong address data\n"); if (a->ai_canonname && b->ai_canonname) { ok(!lstrcmpW(a->ai_canonname, b->ai_canonname), "Wrong canonical name '%s' != '%s'\n", wine_dbgstr_w(a->ai_canonname), wine_dbgstr_w(b->ai_canonname)); } else ok(!a->ai_canonname && !b->ai_canonname, "Expected both names absent (%p != %p)\n", a->ai_canonname, b->ai_canonname); } ok(!a && !b, "Expected both addresses null (%p != %p)\n", a, b); } static void test_GetAddrInfoW(void) { static const WCHAR port[] = {'8','0',0}; static const WCHAR empty[] = {0}; static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0}; static const WCHAR nxdomain[] = {'n','x','d','o','m','a','i','n','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0}; static const WCHAR zero[] = {'0',0}; int i, ret; ADDRINFOW *result, *result2, *p, hint; WCHAR name[256]; DWORD size = ARRAY_SIZE(name); /* te su to.winehq.org written in katakana */ static const WCHAR idn_domain[] = {0x30C6,0x30B9,0x30C8,'.','w','i','n','e','h','q','.','o','r','g',0}; static const WCHAR idn_punycode[] = {'x','n','-','-','z','c','k','z','a','h','.','w','i','n','e','h','q','.','o','r','g',0}; memset(&hint, 0, sizeof(ADDRINFOW)); name[0] = 0; GetComputerNameExW( ComputerNamePhysicalDnsHostname, name, &size ); result = (ADDRINFOW *)0xdeadbeef; WSASetLastError(0xdeadbeef); ret = GetAddrInfoW(NULL, NULL, NULL, &result); ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); result = NULL; WSASetLastError(0xdeadbeef); ret = GetAddrInfoW(empty, NULL, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); FreeAddrInfoW(result); result = NULL; ret = GetAddrInfoW(NULL, zero, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); result2 = NULL; ret = GetAddrInfoW(NULL, empty, NULL, &result2); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result2 != NULL, "GetAddrInfoW failed\n"); compare_addrinfow(result, result2); FreeAddrInfoW(result); FreeAddrInfoW(result2); result = NULL; ret = GetAddrInfoW(empty, zero, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); result2 = NULL; ret = GetAddrInfoW(empty, empty, NULL, &result2); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result2 != NULL, "GetAddrInfoW failed\n"); compare_addrinfow(result, result2); FreeAddrInfoW(result); FreeAddrInfoW(result2); result = NULL; ret = GetAddrInfoW(localhost, NULL, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); FreeAddrInfoW(result); result = NULL; ret = GetAddrInfoW(localhost, empty, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); FreeAddrInfoW(result); result = NULL; ret = GetAddrInfoW(localhost, zero, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); FreeAddrInfoW(result); result = NULL; ret = GetAddrInfoW(localhost, port, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); FreeAddrInfoW(result); result = NULL; ret = GetAddrInfoW(localhost, NULL, &hint, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); FreeAddrInfoW(result); result = NULL; SetLastError(0xdeadbeef); ret = GetAddrInfoW(localhost, port, &hint, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); FreeAddrInfoW(result); /* try to get information from the computer name, result is the same * as if requesting with an empty host name. */ ret = GetAddrInfoW(name, NULL, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); ret = GetAddrInfoW(empty, NULL, NULL, &result2); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); compare_addrinfow(result, result2); FreeAddrInfoW(result); FreeAddrInfoW(result2); ret = GetAddrInfoW(name, empty, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); ret = GetAddrInfoW(empty, empty, NULL, &result2); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); compare_addrinfow(result, result2); FreeAddrInfoW(result); FreeAddrInfoW(result2); result = (ADDRINFOW *)0xdeadbeef; WSASetLastError(0xdeadbeef); ret = GetAddrInfoW(NULL, NULL, NULL, &result); if (ret == 0) { skip("nxdomain returned success. Broken ISP redirects?\n"); return; } ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); result = (ADDRINFOW *)0xdeadbeef; WSASetLastError(0xdeadbeef); ret = GetAddrInfoW(nxdomain, NULL, NULL, &result); if (ret == 0) { skip("nxdomain returned success. Broken ISP redirects?\n"); return; } ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); for (i = 0; i < ARRAY_SIZE(hinttests); i++) { hint.ai_family = hinttests[i].family; hint.ai_socktype = hinttests[i].socktype; hint.ai_protocol = hinttests[i].protocol; result = NULL; SetLastError(0xdeadbeef); ret = GetAddrInfoW(localhost, NULL, &hint, &result); ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret); if (!ret) { for (p = result; p; p = p->ai_next) { /* when AF_UNSPEC is used the return will be either AF_INET or AF_INET6 */ if (hinttests[i].family == AF_UNSPEC) ok(p->ai_family == AF_INET || p->ai_family == AF_INET6, "test %d: expected AF_INET or AF_INET6, got %d\n", i, p->ai_family); else ok(p->ai_family == hinttests[i].family, "test %d: expected family %d, got %d\n", i, hinttests[i].family, p->ai_family); ok(p->ai_socktype == hinttests[i].socktype, "test %d: expected type %d, got %d\n", i, hinttests[i].socktype, p->ai_socktype); ok(p->ai_protocol == hinttests[i].protocol, "test %d: expected protocol %d, got %d\n", i, hinttests[i].protocol, p->ai_protocol); } FreeAddrInfoW(result); } else { ok(WSAGetLastError() == hinttests[i].error, "test %d: wrong error %d\n", i, WSAGetLastError()); } } /* Test IDN resolution (Internationalized Domain Names) present since Windows 8 */ result = NULL; ret = GetAddrInfoW(idn_punycode, NULL, NULL, &result); ok(!ret, "got %d expected success\n", ret); ok(result != NULL, "got %p\n", result); FreeAddrInfoW(result); hint.ai_family = AF_INET; hint.ai_socktype = 0; hint.ai_protocol = 0; hint.ai_flags = 0; result = NULL; ret = GetAddrInfoW(idn_punycode, NULL, &hint, &result); ok(!ret, "got %d expected success\n", ret); ok(result != NULL, "got %p\n", result); result2 = NULL; ret = GetAddrInfoW(idn_domain, NULL, NULL, &result2); if (broken(ret == WSAHOST_NOT_FOUND)) { FreeAddrInfoW(result); win_skip("IDN resolution not supported in Win <= 7\n"); return; } ok(!ret, "got %d expected success\n", ret); ok(result2 != NULL, "got %p\n", result2); FreeAddrInfoW(result2); hint.ai_family = AF_INET; hint.ai_socktype = 0; hint.ai_protocol = 0; hint.ai_flags = 0; result2 = NULL; ret = GetAddrInfoW(idn_domain, NULL, &hint, &result2); ok(!ret, "got %d expected success\n", ret); ok(result2 != NULL, "got %p\n", result2); /* ensure manually resolved punycode and unicode hosts result in same data */ compare_addrinfow(result, result2); FreeAddrInfoW(result); FreeAddrInfoW(result2); hint.ai_family = AF_INET; hint.ai_socktype = 0; hint.ai_protocol = 0; hint.ai_flags = 0; result2 = NULL; ret = GetAddrInfoW(idn_domain, NULL, &hint, &result2); ok(!ret, "got %d expected success\n", ret); ok(result2 != NULL, "got %p\n", result2); FreeAddrInfoW(result2); /* Disable IDN resolution and test again*/ hint.ai_family = AF_INET; hint.ai_socktype = 0; hint.ai_protocol = 0; hint.ai_flags = AI_DISABLE_IDN_ENCODING; SetLastError(0xdeadbeef); result2 = NULL; ret = GetAddrInfoW(idn_domain, NULL, &hint, &result2); ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result2 == NULL, "got %p\n", result2); } static struct completion_routine_test { WSAOVERLAPPED *overlapped; DWORD error; ADDRINFOEXW **result; HANDLE event; DWORD called; } completion_routine_test; static void CALLBACK completion_routine(DWORD error, DWORD byte_count, WSAOVERLAPPED *overlapped) { struct completion_routine_test *test = &completion_routine_test; ok(error == test->error, "got %u\n", error); ok(!byte_count, "got %u\n", byte_count); ok(overlapped == test->overlapped, "got %p\n", overlapped); ok(overlapped->Internal == test->error, "got %lu\n", overlapped->Internal); ok(overlapped->Pointer == test->result, "got %p\n", overlapped->Pointer); ok(overlapped->hEvent == NULL, "got %p\n", overlapped->hEvent); test->called++; SetEvent(test->event); } static void test_GetAddrInfoExW(void) { static const WCHAR empty[] = {0}; static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0}; static const WCHAR winehq[] = {'t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',0}; static const WCHAR nxdomain[] = {'n','x','d','o','m','a','i','n','.','w','i','n','e','h','q','.','o','r','g',0}; ADDRINFOEXW *result, hints; OVERLAPPED overlapped; HANDLE event; int ret; if (!pGetAddrInfoExW || !pGetAddrInfoExOverlappedResult) { win_skip("GetAddrInfoExW and/or GetAddrInfoExOverlappedResult not present\n"); return; } event = WSACreateEvent(); result = (ADDRINFOEXW *)0xdeadbeef; WSASetLastError(0xdeadbeef); ret = pGetAddrInfoExW(NULL, NULL, NS_DNS, NULL, NULL, &result, NULL, NULL, NULL, NULL); ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); result = NULL; WSASetLastError(0xdeadbeef); ret = pGetAddrInfoExW(empty, NULL, NS_DNS, NULL, NULL, &result, NULL, NULL, NULL, NULL); ok(!ret, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); pFreeAddrInfoExW(result); result = NULL; ret = pGetAddrInfoExW(localhost, NULL, NS_DNS, NULL, NULL, &result, NULL, NULL, NULL, NULL); ok(!ret, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); pFreeAddrInfoExW(result); ret = pGetAddrInfoExOverlappedResult(NULL); ok(ret == WSAEINVAL, "overlapped result is %d\n", ret); result = (void *)0xdeadbeef; memset(&overlapped, 0xcc, sizeof(overlapped)); overlapped.hEvent = event; ResetEvent(event); ret = pGetAddrInfoExW(localhost, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, NULL, NULL); ok(ret == ERROR_IO_PENDING, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); /* result pointer is cleared by GetAddrInfoExW(), but may be set to the * actual addrinfo before we can verify that */ ok(result != (void *)0xdeadbeef, "result was not changed\n"); ok(WaitForSingleObject(event, 1000) == WAIT_OBJECT_0, "wait failed\n"); ret = pGetAddrInfoExOverlappedResult(&overlapped); ok(!ret, "overlapped result is %d\n", ret); pFreeAddrInfoExW(result); result = (void *)0xdeadbeef; memset(&overlapped, 0xcc, sizeof(overlapped)); ResetEvent(event); overlapped.hEvent = event; WSASetLastError(0xdeadbeef); ret = pGetAddrInfoExW(winehq, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, NULL, NULL); ok(ret == ERROR_IO_PENDING, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); ok(WSAGetLastError() == ERROR_IO_PENDING, "expected 11001, got %d\n", WSAGetLastError()); ret = overlapped.Internal; ok(ret == WSAEINPROGRESS || ret == ERROR_SUCCESS, "overlapped.Internal = %u\n", ret); ok(WaitForSingleObject(event, 1000) == WAIT_OBJECT_0, "wait failed\n"); ret = pGetAddrInfoExOverlappedResult(&overlapped); ok(!ret, "overlapped result is %d\n", ret); ok(overlapped.hEvent == event, "hEvent changed %p\n", overlapped.hEvent); ok(overlapped.Internal == ERROR_SUCCESS, "overlapped.Internal = %lx\n", overlapped.Internal); ok(overlapped.Pointer == &result, "overlapped.Pointer != &result\n"); ok(result != NULL, "result == NULL\n"); ok(!result->ai_blob, "ai_blob != NULL\n"); ok(!result->ai_bloblen, "ai_bloblen != 0\n"); ok(!result->ai_provider, "ai_provider = %s\n", wine_dbgstr_guid(result->ai_provider)); pFreeAddrInfoExW(result); /* hints */ result = (void *)0xdeadbeef; memset(&overlapped, 0xcc, sizeof(overlapped)); ResetEvent(event); overlapped.hEvent = event; WSASetLastError(0xdeadbeef); memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ALL | AI_V4MAPPED; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; ret = pGetAddrInfoExW(winehq, NULL, NS_ALL, NULL, &hints, &result, NULL, &overlapped, NULL, NULL); ok(ret == ERROR_IO_PENDING, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); ok(WSAGetLastError() == ERROR_IO_PENDING, "expected 11001, got %d\n", WSAGetLastError()); ret = overlapped.Internal; ok(ret == WSAEINPROGRESS || ret == ERROR_SUCCESS, "overlapped.Internal = %u\n", ret); ok(WaitForSingleObject(event, 1000) == WAIT_OBJECT_0, "wait failed\n"); ret = pGetAddrInfoExOverlappedResult(&overlapped); ok(!ret, "overlapped result is %d\n", ret); ok(result != NULL, "result == NULL\n"); pFreeAddrInfoExW(result); result = (void *)0xdeadbeef; memset(&overlapped, 0xcc, sizeof(overlapped)); ResetEvent(event); overlapped.hEvent = event; ret = pGetAddrInfoExW(NULL, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, NULL, NULL); todo_wine ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); todo_wine ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); ret = WaitForSingleObject(event, 0); todo_wine_if(ret != WAIT_TIMEOUT) /* Remove when abowe todo_wines are fixed */ ok(ret == WAIT_TIMEOUT, "wait failed\n"); /* event + completion routine */ result = (void *)0xdeadbeef; memset(&overlapped, 0xcc, sizeof(overlapped)); overlapped.hEvent = event; ResetEvent(event); ret = pGetAddrInfoExW(localhost, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, completion_routine, NULL); ok(ret == WSAEINVAL, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); /* completion routine, existing domain */ result = (void *)0xdeadbeef; overlapped.hEvent = NULL; completion_routine_test.overlapped = &overlapped; completion_routine_test.error = ERROR_SUCCESS; completion_routine_test.result = &result; completion_routine_test.event = event; completion_routine_test.called = 0; ResetEvent(event); ret = pGetAddrInfoExW(winehq, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, completion_routine, NULL); ok(ret == ERROR_IO_PENDING, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); ok(!result, "result != NULL\n"); ok(WaitForSingleObject(event, 1000) == WAIT_OBJECT_0, "wait failed\n"); ret = pGetAddrInfoExOverlappedResult(&overlapped); ok(!ret, "overlapped result is %d\n", ret); ok(overlapped.hEvent == NULL, "hEvent changed %p\n", overlapped.hEvent); ok(overlapped.Internal == ERROR_SUCCESS, "overlapped.Internal = %lx\n", overlapped.Internal); ok(overlapped.Pointer == &result, "overlapped.Pointer != &result\n"); ok(completion_routine_test.called == 1, "got %u\n", completion_routine_test.called); pFreeAddrInfoExW(result); /* completion routine, non-existing domain */ result = (void *)0xdeadbeef; completion_routine_test.overlapped = &overlapped; completion_routine_test.error = WSAHOST_NOT_FOUND; completion_routine_test.called = 0; ResetEvent(event); ret = pGetAddrInfoExW(nxdomain, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, completion_routine, NULL); ok(ret == ERROR_IO_PENDING, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); ok(!result, "result != NULL\n"); ok(WaitForSingleObject(event, 1000) == WAIT_OBJECT_0, "wait failed\n"); ret = pGetAddrInfoExOverlappedResult(&overlapped); ok(ret == WSAHOST_NOT_FOUND, "overlapped result is %d\n", ret); ok(overlapped.hEvent == NULL, "hEvent changed %p\n", overlapped.hEvent); ok(overlapped.Internal == WSAHOST_NOT_FOUND, "overlapped.Internal = %lx\n", overlapped.Internal); ok(overlapped.Pointer == &result, "overlapped.Pointer != &result\n"); ok(completion_routine_test.called == 1, "got %u\n", completion_routine_test.called); ok(result == NULL, "got %p\n", result); WSACloseEvent(event); } static void verify_ipv6_addrinfo(ADDRINFOA *result, const char *expect) { SOCKADDR_IN6 *sockaddr6; char buffer[256]; const char *ret; ok(result->ai_family == AF_INET6, "ai_family == %d\n", result->ai_family); ok(result->ai_addrlen >= sizeof(struct sockaddr_in6), "ai_addrlen == %d\n", (int)result->ai_addrlen); ok(result->ai_addr != NULL, "ai_addr == NULL\n"); sockaddr6 = (SOCKADDR_IN6 *)result->ai_addr; ok(sockaddr6->sin6_family == AF_INET6, "ai_addr->sin6_family == %d\n", sockaddr6->sin6_family); ok(sockaddr6->sin6_port == 0, "ai_addr->sin6_port == %d\n", sockaddr6->sin6_port); memset(buffer, 0, sizeof(buffer)); ret = p_inet_ntop(AF_INET6, &sockaddr6->sin6_addr, buffer, sizeof(buffer)); ok(ret != NULL, "inet_ntop failed (%d)\n", WSAGetLastError()); ok(!strcmp(buffer, expect), "ai_addr->sin6_addr == '%s' (expected '%s')\n", buffer, expect); } static void compare_addrinfo(ADDRINFO *a, ADDRINFO *b) { for (; a && b ; a = a->ai_next, b = b->ai_next) { ok(a->ai_flags == b->ai_flags, "Wrong flags %d != %d\n", a->ai_flags, b->ai_flags); ok(a->ai_family == b->ai_family, "Wrong family %d != %d\n", a->ai_family, b->ai_family); ok(a->ai_socktype == b->ai_socktype, "Wrong socktype %d != %d\n", a->ai_socktype, b->ai_socktype); ok(a->ai_protocol == b->ai_protocol, "Wrong protocol %d != %d\n", a->ai_protocol, b->ai_protocol); ok(a->ai_addrlen == b->ai_addrlen, "Wrong addrlen %lu != %lu\n", a->ai_addrlen, b->ai_addrlen); ok(!memcmp(a->ai_addr, b->ai_addr, min(a->ai_addrlen, b->ai_addrlen)), "Wrong address data\n"); if (a->ai_canonname && b->ai_canonname) { ok(!strcmp(a->ai_canonname, b->ai_canonname), "Wrong canonical name '%s' != '%s'\n", a->ai_canonname, b->ai_canonname); } else ok(!a->ai_canonname && !b->ai_canonname, "Expected both names absent (%p != %p)\n", a->ai_canonname, b->ai_canonname); } ok(!a && !b, "Expected both addresses null (%p != %p)\n", a, b); } static void test_getaddrinfo(void) { int i, ret; ADDRINFOA *result, *result2, *p, hint; SOCKADDR_IN *sockaddr; CHAR name[256], *ip; DWORD size = sizeof(name); memset(&hint, 0, sizeof(ADDRINFOA)); GetComputerNameExA( ComputerNamePhysicalDnsHostname, name, &size ); result = (ADDRINFOA *)0xdeadbeef; WSASetLastError(0xdeadbeef); ret = getaddrinfo(NULL, NULL, NULL, &result); ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); result = NULL; WSASetLastError(0xdeadbeef); ret = getaddrinfo("", NULL, NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result != NULL, "getaddrinfo failed\n"); ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); freeaddrinfo(result); result = NULL; ret = getaddrinfo(NULL, "0", NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result != NULL, "getaddrinfo failed\n"); result2 = NULL; ret = getaddrinfo(NULL, "", NULL, &result2); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result2 != NULL, "getaddrinfo failed\n"); compare_addrinfo(result, result2); freeaddrinfo(result); freeaddrinfo(result2); result = NULL; WSASetLastError(0xdeadbeef); ret = getaddrinfo("", "0", NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); ok(result != NULL, "getaddrinfo failed\n"); result2 = NULL; ret = getaddrinfo("", "", NULL, &result2); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result2 != NULL, "getaddrinfo failed\n"); compare_addrinfo(result, result2); freeaddrinfo(result); freeaddrinfo(result2); result = NULL; ret = getaddrinfo("localhost", NULL, NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); freeaddrinfo(result); result = NULL; ret = getaddrinfo("localhost", "", NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); freeaddrinfo(result); result = NULL; ret = getaddrinfo("localhost", "0", NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); freeaddrinfo(result); result = NULL; ret = getaddrinfo("localhost", "80", NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); freeaddrinfo(result); result = NULL; ret = getaddrinfo("localhost", NULL, &hint, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); freeaddrinfo(result); result = NULL; WSASetLastError(0xdeadbeef); ret = getaddrinfo("localhost", "80", &hint, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); freeaddrinfo(result); hint.ai_flags = AI_NUMERICHOST; result = (void *)0xdeadbeef; ret = getaddrinfo("localhost", "80", &hint, &result); ok(ret == WSAHOST_NOT_FOUND, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected WSAHOST_NOT_FOUND, got %d\n", WSAGetLastError()); ok(!result, "result = %p\n", result); hint.ai_flags = 0; /* try to get information from the computer name, result is the same * as if requesting with an empty host name. */ ret = getaddrinfo(name, NULL, NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); ret = getaddrinfo("", NULL, NULL, &result2); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); compare_addrinfo(result, result2); freeaddrinfo(result); freeaddrinfo(result2); ret = getaddrinfo(name, "", NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); ret = getaddrinfo("", "", NULL, &result2); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); compare_addrinfo(result, result2); freeaddrinfo(result); freeaddrinfo(result2); result = (ADDRINFOA *)0xdeadbeef; WSASetLastError(0xdeadbeef); ret = getaddrinfo("nxdomain.codeweavers.com", NULL, NULL, &result); if (ret == 0) { skip("nxdomain returned success. Broken ISP redirects?\n"); return; } ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); /* Test IPv4 address conversion */ result = NULL; ret = getaddrinfo("192.168.1.253", NULL, NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", ret); ok(result->ai_family == AF_INET, "ai_family == %d\n", result->ai_family); ok(result->ai_addrlen >= sizeof(struct sockaddr_in), "ai_addrlen == %d\n", (int)result->ai_addrlen); ok(result->ai_addr != NULL, "ai_addr == NULL\n"); sockaddr = (SOCKADDR_IN *)result->ai_addr; ok(sockaddr->sin_family == AF_INET, "ai_addr->sin_family == %d\n", sockaddr->sin_family); ok(sockaddr->sin_port == 0, "ai_addr->sin_port == %d\n", sockaddr->sin_port); ip = inet_ntoa(sockaddr->sin_addr); ok(strcmp(ip, "192.168.1.253") == 0, "sockaddr->ai_addr == '%s'\n", ip); freeaddrinfo(result); /* Test IPv4 address conversion with port */ result = NULL; hint.ai_flags = AI_NUMERICHOST; ret = getaddrinfo("192.168.1.253:1024", NULL, &hint, &result); hint.ai_flags = 0; ok(ret == WSAHOST_NOT_FOUND, "getaddrinfo returned unexpected result: %d\n", ret); ok(result == NULL, "expected NULL, got %p\n", result); /* Test IPv6 address conversion */ result = NULL; SetLastError(0xdeadbeef); ret = getaddrinfo("2a00:2039:dead:beef:cafe::6666", NULL, NULL, &result); if (result != NULL) { ok(!ret, "getaddrinfo failed with %d\n", ret); verify_ipv6_addrinfo(result, "2a00:2039:dead:beef:cafe::6666"); freeaddrinfo(result); /* Test IPv6 address conversion with brackets */ result = NULL; ret = getaddrinfo("[beef::cafe]", NULL, NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", ret); verify_ipv6_addrinfo(result, "beef::cafe"); freeaddrinfo(result); /* Test IPv6 address conversion with brackets and hints */ memset(&hint, 0, sizeof(ADDRINFOA)); hint.ai_flags = AI_NUMERICHOST; hint.ai_family = AF_INET6; result = NULL; ret = getaddrinfo("[beef::cafe]", NULL, &hint, &result); ok(!ret, "getaddrinfo failed with %d\n", ret); verify_ipv6_addrinfo(result, "beef::cafe"); freeaddrinfo(result); memset(&hint, 0, sizeof(ADDRINFOA)); hint.ai_flags = AI_NUMERICHOST; hint.ai_family = AF_INET; result = NULL; ret = getaddrinfo("[beef::cafe]", NULL, &hint, &result); ok(ret == WSAHOST_NOT_FOUND, "getaddrinfo failed with %d\n", ret); /* Test IPv6 address conversion with brackets and port */ result = NULL; ret = getaddrinfo("[beef::cafe]:10239", NULL, NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", ret); verify_ipv6_addrinfo(result, "beef::cafe"); freeaddrinfo(result); /* Test IPv6 address conversion with unmatched brackets */ result = NULL; hint.ai_flags = AI_NUMERICHOST; ret = getaddrinfo("[beef::cafe", NULL, &hint, &result); ok(ret == WSAHOST_NOT_FOUND, "getaddrinfo failed with %d\n", ret); ret = getaddrinfo("beef::cafe]", NULL, &hint, &result); ok(ret == WSAHOST_NOT_FOUND, "getaddrinfo failed with %d\n", ret); } else { ok(ret == WSAHOST_NOT_FOUND, "getaddrinfo failed with %d\n", ret); win_skip("getaddrinfo does not support IPV6\n"); } hint.ai_flags = 0; for (i = 0; i < ARRAY_SIZE(hinttests); i++) { hint.ai_family = hinttests[i].family; hint.ai_socktype = hinttests[i].socktype; hint.ai_protocol = hinttests[i].protocol; result = NULL; SetLastError(0xdeadbeef); ret = getaddrinfo("localhost", NULL, &hint, &result); ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret); if (!ret) { for (p = result; p; p = p->ai_next) { /* when AF_UNSPEC is used the return will be either AF_INET or AF_INET6 */ if (hinttests[i].family == AF_UNSPEC) ok(p->ai_family == AF_INET || p->ai_family == AF_INET6, "test %d: expected AF_INET or AF_INET6, got %d\n", i, p->ai_family); else ok(p->ai_family == hinttests[i].family, "test %d: expected family %d, got %d\n", i, hinttests[i].family, p->ai_family); ok(p->ai_socktype == hinttests[i].socktype, "test %d: expected type %d, got %d\n", i, hinttests[i].socktype, p->ai_socktype); ok(p->ai_protocol == hinttests[i].protocol, "test %d: expected protocol %d, got %d\n", i, hinttests[i].protocol, p->ai_protocol); } freeaddrinfo(result); } else { ok(WSAGetLastError() == hinttests[i].error, "test %d: wrong error %d\n", i, WSAGetLastError()); } } memset(&hint, 0, sizeof(hint)); ret = getaddrinfo(NULL, "nonexistentservice", &hint, &result); ok(ret == WSATYPE_NOT_FOUND, "got %d\n", ret); result = NULL; memset(&hint, 0, sizeof(hint)); hint.ai_flags = AI_ALL | AI_DNS_ONLY; hint.ai_family = AF_UNSPEC; hint.ai_socktype = SOCK_STREAM; hint.ai_protocol = IPPROTO_TCP; ret = getaddrinfo("winehq.org", NULL, &hint, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(!result->ai_flags, "ai_flags == %08x\n", result->ai_flags); ok(result->ai_family == AF_INET, "ai_family == %d\n", result->ai_family); ok(result->ai_socktype == SOCK_STREAM, "ai_socktype == %d\n", result->ai_socktype); ok(result->ai_protocol == IPPROTO_TCP, "ai_protocol == %d\n", result->ai_protocol); ok(!result->ai_canonname, "ai_canonname == %s\n", result->ai_canonname); ok(result->ai_addrlen == sizeof(struct sockaddr_in), "ai_addrlen == %d\n", (int)result->ai_addrlen); ok(result->ai_addr != NULL, "ai_addr == NULL\n"); sockaddr = (SOCKADDR_IN *)result->ai_addr; ok(sockaddr->sin_family == AF_INET, "ai_addr->sin_family == %d\n", sockaddr->sin_family); ok(sockaddr->sin_port == 0, "ai_addr->sin_port == %d\n", sockaddr->sin_port); freeaddrinfo(result); } static void test_dns(void) { struct hostent *h; union { char *chr; void *mem; } addr; char **ptr; int count; h = gethostbyname(""); ok(h != NULL, "gethostbyname(\"\") failed with %d\n", h_errno); /* Use an address with valid alias names if possible */ h = gethostbyname("source.winehq.org"); if (!h) { skip("Can't test the hostent structure because gethostbyname failed\n"); return; } /* The returned struct must be allocated in a very strict way. First we need to * count how many aliases there are because they must be located right after * the struct hostent size. Knowing the amount of aliases we know the exact * location of the first IP returned. Rule valid for >= XP, for older OS's * it's somewhat the opposite. */ addr.mem = h + 1; if (h->h_addr_list == addr.mem) /* <= W2K */ { win_skip("Skipping hostent tests since this OS is unsupported\n"); return; } ok(h->h_aliases == addr.mem, "hostent->h_aliases should be in %p, it is in %p\n", addr.mem, h->h_aliases); for (ptr = h->h_aliases, count = 1; *ptr; ptr++) count++; addr.chr += sizeof(*ptr) * count; ok(h->h_addr_list == addr.mem, "hostent->h_addr_list should be in %p, it is in %p\n", addr.mem, h->h_addr_list); for (ptr = h->h_addr_list, count = 1; *ptr; ptr++) count++; addr.chr += sizeof(*ptr) * count; ok(h->h_addr_list[0] == addr.mem, "hostent->h_addr_list[0] should be in %p, it is in %p\n", addr.mem, h->h_addr_list[0]); } static void test_gethostbyname(void) { struct hostent *he; struct in_addr **addr_list; char name[256], first_ip[16]; int ret, i, count; MIB_IPFORWARDTABLE *routes = NULL; IP_ADAPTER_INFO *adapters = NULL, *k; DWORD adap_size = 0, route_size = 0; BOOL found_default = FALSE; BOOL local_ip = FALSE; ret = gethostname(name, sizeof(name)); ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); he = gethostbyname(name); ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, WSAGetLastError()); addr_list = (struct in_addr **)he->h_addr_list; strcpy(first_ip, inet_ntoa(*addr_list[0])); if (winetest_debug > 1) trace("List of local IPs:\n"); for (count = 0; addr_list[count] != NULL; count++) { char *ip = inet_ntoa(*addr_list[count]); if (!strcmp(ip, "127.0.0.1")) local_ip = TRUE; if (winetest_debug > 1) trace("%s\n", ip); } if (local_ip) { ok(count == 1, "expected 127.0.0.1 to be the only IP returned\n"); skip("Only the loopback address is present, skipping tests\n"); return; } ret = GetAdaptersInfo(NULL, &adap_size); ok(ret == ERROR_BUFFER_OVERFLOW, "GetAdaptersInfo failed with a different error: %d\n", ret); ret = GetIpForwardTable(NULL, &route_size, FALSE); ok(ret == ERROR_INSUFFICIENT_BUFFER, "GetIpForwardTable failed with a different error: %d\n", ret); adapters = HeapAlloc(GetProcessHeap(), 0, adap_size); routes = HeapAlloc(GetProcessHeap(), 0, route_size); ret = GetAdaptersInfo(adapters, &adap_size); ok(ret == NO_ERROR, "GetAdaptersInfo failed, error: %d\n", ret); ret = GetIpForwardTable(routes, &route_size, FALSE); ok(ret == NO_ERROR, "GetIpForwardTable failed, error: %d\n", ret); /* This test only has meaning if there is more than one IP configured */ if (adapters->Next == NULL && count == 1) { skip("Only one IP is present, skipping tests\n"); goto cleanup; } for (i = 0; !found_default && i < routes->dwNumEntries; i++) { /* default route (ip 0.0.0.0) ? */ if (routes->table[i].dwForwardDest) continue; for (k = adapters; k != NULL; k = k->Next) { char *ip; if (k->Index != routes->table[i].dwForwardIfIndex) continue; /* the first IP returned from gethostbyname must be a default route */ ip = k->IpAddressList.IpAddress.String; if (!strcmp(first_ip, ip)) { found_default = TRUE; break; } } } ok(found_default, "failed to find the first IP from gethostbyname!\n"); cleanup: HeapFree(GetProcessHeap(), 0, adapters); HeapFree(GetProcessHeap(), 0, routes); } static void test_gethostbyname_hack(void) { struct hostent *he; char name[256]; static BYTE loopback[] = {127, 0, 0, 1}; static BYTE magic_loopback[] = {127, 12, 34, 56}; int ret; ret = gethostname(name, 256); ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); he = gethostbyname("localhost"); ok(he != NULL, "gethostbyname(\"localhost\") failed: %d\n", h_errno); if (he->h_length != 4) { skip("h_length is %d, not IPv4, skipping test.\n", he->h_length); return; } ok(!memcmp(he->h_addr_list[0], loopback, he->h_length), "gethostbyname(\"localhost\") returned %u.%u.%u.%u\n", he->h_addr_list[0][0], he->h_addr_list[0][1], he->h_addr_list[0][2], he->h_addr_list[0][3]); if (!strcmp(name, "localhost")) { skip("hostname seems to be \"localhost\", skipping test.\n"); return; } he = gethostbyname(name); ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, h_errno); if (he->h_length != 4) { skip("h_length is %d, not IPv4, skipping test.\n", he->h_length); return; } if (he->h_addr_list[0][0] == 127) { ok(memcmp(he->h_addr_list[0], magic_loopback, he->h_length) == 0, "gethostbyname(\"%s\") returned %u.%u.%u.%u not 127.12.34.56\n", name, he->h_addr_list[0][0], he->h_addr_list[0][1], he->h_addr_list[0][2], he->h_addr_list[0][3]); } gethostbyname("nonexistent.winehq.org"); /* Don't check for the return value, as some braindead ISPs will kindly * resolve nonexistent host names to addresses of the ISP's spam pages. */ } static void test_gethostname(void) { struct hostent *he; char name[256]; int ret, len; WSASetLastError(0xdeadbeef); ret = gethostname(NULL, 256); ok(ret == -1, "gethostname() returned %d\n", ret); ok(WSAGetLastError() == WSAEFAULT, "gethostname with null buffer " "failed with %d, expected %d\n", WSAGetLastError(), WSAEFAULT); ret = gethostname(name, sizeof(name)); ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); he = gethostbyname(name); ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, WSAGetLastError()); len = strlen(name); WSASetLastError(0xdeadbeef); strcpy(name, "deadbeef"); ret = gethostname(name, len); ok(ret == -1, "gethostname() returned %d\n", ret); ok(!strcmp(name, "deadbeef"), "name changed unexpected!\n"); ok(WSAGetLastError() == WSAEFAULT, "gethostname with insufficient length " "failed with %d, expected %d\n", WSAGetLastError(), WSAEFAULT); len++; ret = gethostname(name, len); ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); he = gethostbyname(name); ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, WSAGetLastError()); } static void test_GetHostNameW(void) { WCHAR name[256]; int ret, len; if (!pGetHostNameW) { win_skip("GetHostNameW() not present\n"); return; } WSASetLastError(0xdeadbeef); ret = pGetHostNameW(NULL, 256); ok(ret == -1, "GetHostNameW() returned %d\n", ret); ok(WSAGetLastError() == WSAEFAULT, "GetHostNameW with null buffer " "failed with %d, expected %d\n", WSAGetLastError(), WSAEFAULT); ret = pGetHostNameW(name, sizeof(name)); ok(ret == 0, "GetHostNameW() call failed: %d\n", WSAGetLastError()); len = wcslen(name); WSASetLastError(0xdeadbeef); wcscpy(name, L"deadbeef"); ret = pGetHostNameW(name, len); ok(ret == -1, "GetHostNameW() returned %d\n", ret); ok(!wcscmp(name, L"deadbeef"), "name changed unexpected!\n"); ok(WSAGetLastError() == WSAEFAULT, "GetHostNameW with insufficient length " "failed with %d, expected %d\n", WSAGetLastError(), WSAEFAULT); len++; ret = pGetHostNameW(name, len); ok(ret == 0, "GetHostNameW() call failed: %d\n", WSAGetLastError()); } static void test_WSAEnumNameSpaceProvidersA(void) { WSANAMESPACE_INFOA *name = NULL; DWORD ret, error, len = 0; SetLastError(0xdeadbeef); ret = WSAEnumNameSpaceProvidersA(&len, name); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); todo_wine ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); /* Invalid parameter tests */ SetLastError(0xdeadbeef); ret = WSAEnumNameSpaceProvidersA(NULL, name); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); todo_wine ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); SetLastError(0xdeadbeef); ret = WSAEnumNameSpaceProvidersA(NULL, NULL); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); todo_wine ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); SetLastError(0xdeadbeef); ret = WSAEnumNameSpaceProvidersA(&len, NULL); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); todo_wine ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); name = HeapAlloc(GetProcessHeap(), 0, len); ret = WSAEnumNameSpaceProvidersA(&len, name); todo_wine ok(ret > 0, "Expected more than zero name space providers\n"); HeapFree(GetProcessHeap(), 0, name); } static void test_WSAEnumNameSpaceProvidersW(void) { WSANAMESPACE_INFOW *name = NULL; DWORD ret, error, len = 0, i; SetLastError(0xdeadbeef); ret = WSAEnumNameSpaceProvidersW(&len, name); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); todo_wine ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); /* Invalid parameter tests */ SetLastError(0xdeadbeef); ret = WSAEnumNameSpaceProvidersW(NULL, name); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); todo_wine ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); SetLastError(0xdeadbeef); ret = WSAEnumNameSpaceProvidersW(NULL, NULL); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); todo_wine ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); SetLastError(0xdeadbeef); ret = WSAEnumNameSpaceProvidersW(&len, NULL); error = WSAGetLastError(); todo_wine ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); todo_wine ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); name = HeapAlloc(GetProcessHeap(), 0, len); ret = WSAEnumNameSpaceProvidersW(&len, name); todo_wine ok(ret > 0, "Expected more than zero name space providers\n"); if (winetest_debug > 1) { for (i = 0; i < ret; i++) { trace("Name space Identifier (%p): %s\n", name[i].lpszIdentifier, wine_dbgstr_w(name[i].lpszIdentifier)); switch (name[i].dwNameSpace) { case NS_DNS: trace("\tName space ID: NS_DNS (%u)\n", name[i].dwNameSpace); break; case NS_NLA: trace("\tName space ID: NS_NLA (%u)\n", name[i].dwNameSpace); break; default: trace("\tName space ID: Unknown (%u)\n", name[i].dwNameSpace); break; } trace("\tActive: %d\n", name[i].fActive); trace("\tVersion: %d\n", name[i].dwVersion); } } HeapFree(GetProcessHeap(), 0, name); } static void test_WSCGetProviderInfo(void) { int ret; int errcode; GUID provider = {0}; BYTE info[1]; size_t len = 0; if (!pWSCGetProviderInfo) { skip("WSCGetProviderInfo is not available.\n"); return; } ret = pWSCGetProviderInfo(NULL, -1, NULL, NULL, 0, NULL); ok(ret == SOCKET_ERROR, "got %d, expected SOCKET_ERROR\n", ret); errcode = 0xdeadbeef; ret = pWSCGetProviderInfo(NULL, ProviderInfoLspCategories, info, &len, 0, &errcode); ok(ret == SOCKET_ERROR, "got %d, expected SOCKET_ERROR\n", ret); ok(errcode == WSAEFAULT, "got %d, expected WSAEFAULT\n", errcode); errcode = 0xdeadbeef; ret = pWSCGetProviderInfo(&provider, -1, info, &len, 0, &errcode); ok(ret == SOCKET_ERROR, "got %d, expected SOCKET_ERROR\n", ret); ok(errcode == WSANO_RECOVERY, "got %d, expected WSANO_RECOVERY\n", errcode); errcode = 0xdeadbeef; ret = pWSCGetProviderInfo(&provider, ProviderInfoLspCategories, NULL, &len, 0, &errcode); ok(ret == SOCKET_ERROR, "got %d, expected SOCKET_ERROR\n", ret); ok(errcode == WSANO_RECOVERY, "got %d, expected WSANO_RECOVERY\n", errcode); errcode = 0xdeadbeef; ret = pWSCGetProviderInfo(&provider, ProviderInfoLspCategories, info, NULL, 0, &errcode); ok(ret == SOCKET_ERROR, "got %d, expected SOCKET_ERROR\n", ret); ok(errcode == WSANO_RECOVERY, "got %d, expected WSANO_RECOVERY\n", errcode); errcode = 0xdeadbeef; ret = pWSCGetProviderInfo(&provider, ProviderInfoLspCategories, info, &len, 0, &errcode); ok(ret == SOCKET_ERROR, "got %d, expected SOCKET_ERROR\n", ret); ok(errcode == WSANO_RECOVERY, "got %d, expected WSANO_RECOVERY\n", errcode); } static void test_WSCGetProviderPath(void) { GUID provider = {0}; WCHAR buffer[256]; INT ret, err, len; ret = WSCGetProviderPath(NULL, NULL, NULL, NULL); ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); ret = WSCGetProviderPath(&provider, NULL, NULL, NULL); ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); ret = WSCGetProviderPath(NULL, buffer, NULL, NULL); ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); len = -1; ret = WSCGetProviderPath(NULL, NULL, &len, NULL); ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); ok(len == -1, "Got unexpected len %d.\n", len); err = 0; ret = WSCGetProviderPath(NULL, NULL, NULL, &err); ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); ok(err == WSAEFAULT, "Got unexpected error %d.\n", err); err = 0; ret = WSCGetProviderPath(&provider, NULL, NULL, &err); ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); ok(err == WSAEFAULT, "Got unexpected error %d.\n", err); err = 0; len = -1; ret = WSCGetProviderPath(&provider, NULL, &len, &err); ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); ok(err == WSAEINVAL, "Got unexpected error %d.\n", err); ok(len == -1, "Got unexpected len %d.\n", len); err = 0; len = 256; ret = WSCGetProviderPath(&provider, NULL, &len, &err); todo_wine ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); todo_wine ok(err == WSAEINVAL, "Got unexpected error %d.\n", err); ok(len == 256, "Got unexpected len %d.\n", len); /* Valid pointers and length but invalid GUID */ err = 0; len = 256; ret = WSCGetProviderPath(&provider, buffer, &len, &err); todo_wine ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); todo_wine ok(err == WSAEINVAL, "Got unexpected error %d.\n", err); ok(len == 256, "Got unexpected len %d.\n", len); } static void test_startup(void) { unsigned int i; WSADATA data; int ret; static const struct { WORD version; WORD ret_version; } tests[] = { {MAKEWORD(0, 0), MAKEWORD(2, 2)}, {MAKEWORD(0, 1), MAKEWORD(2, 2)}, {MAKEWORD(1, 0), MAKEWORD(1, 0)}, {MAKEWORD(1, 1), MAKEWORD(1, 1)}, {MAKEWORD(1, 2), MAKEWORD(1, 1)}, {MAKEWORD(1, 0xff), MAKEWORD(1, 1)}, {MAKEWORD(2, 0), MAKEWORD(2, 0)}, {MAKEWORD(2, 1), MAKEWORD(2, 1)}, {MAKEWORD(2, 2), MAKEWORD(2, 2)}, {MAKEWORD(2, 3), MAKEWORD(2, 2)}, {MAKEWORD(2, 0xff), MAKEWORD(2, 2)}, {MAKEWORD(3, 0), MAKEWORD(2, 2)}, {MAKEWORD(0xff, 0), MAKEWORD(2, 2)}, }; for (i = 0; i < ARRAY_SIZE(tests); ++i) { winetest_push_context("Version %#x", tests[i].version); memset(&data, 0xcc, sizeof(data)); data.lpVendorInfo = (void *)0xdeadbeef; ret = WSAStartup(tests[i].version, &data); ok(ret == (LOBYTE(tests[i].version) ? 0 : WSAVERNOTSUPPORTED), "got %d\n", ret); ok(data.wVersion == tests[i].ret_version, "got version %#x\n", data.wVersion); if (!ret) { ret = WSAStartup(tests[i].version, &data); ok(!ret, "got %d\n", ret); WSASetLastError(0xdeadbeef); ret = WSACleanup(); ok(!ret, "got %d\n", ret); todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); WSASetLastError(0xdeadbeef); ret = WSACleanup(); ok(!ret, "got %d\n", ret); todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); } ok(data.lpVendorInfo == (void *)0xdeadbeef, "got vendor info %p\n", data.lpVendorInfo); ok(data.wHighVersion == 0x202, "got maximum version %#x\n", data.wHighVersion); ok(!strcmp(data.szDescription, "WinSock 2.0"), "got description %s\n", debugstr_a(data.szDescription)); ok(!strcmp(data.szSystemStatus, "Running"), "got status %s\n", debugstr_a(data.szSystemStatus)); ok(data.iMaxSockets == (LOBYTE(tests[i].version) == 1 ? 32767 : 0), "got maximum sockets %u\n", data.iMaxSockets); ok(data.iMaxUdpDg == (LOBYTE(tests[i].version) == 1 ? 65467 : 0), "got maximum datagram size %u\n", data.iMaxUdpDg); WSASetLastError(0xdeadbeef); ret = WSACleanup(); ok(ret == -1, "got %d\n", ret); ok(WSAGetLastError() == WSANOTINITIALISED, "got error %u\n", WSAGetLastError()); ret = WSAStartup(tests[i].version, NULL); ok(ret == (LOBYTE(tests[i].version) ? WSAEFAULT : WSAVERNOTSUPPORTED), "got %d\n", ret); winetest_pop_context(); } } START_TEST( protocol ) { WSADATA data; int ret; pFreeAddrInfoExW = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "FreeAddrInfoExW"); pGetAddrInfoExOverlappedResult = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "GetAddrInfoExOverlappedResult"); pGetAddrInfoExW = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "GetAddrInfoExW"); pGetHostNameW = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "GetHostNameW"); p_inet_ntop = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "inet_ntop"); pInetNtopW = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "InetNtopW"); p_inet_pton = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "inet_pton"); pInetPtonW = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "InetPtonW"); pWSCGetProviderInfo = (void *)GetProcAddress(GetModuleHandleA("ws2_32"), "WSCGetProviderInfo"); ret = WSAStartup(0x202, &data); ok(!ret, "got %d\n", ret); test_WSAEnumProtocolsA(); test_WSAEnumProtocolsW(); test_getprotobyname(); test_getprotobynumber(); test_getservbyname(); test_WSALookupService(); test_inet_ntoa(); test_inet_pton(); test_addr_to_print(); test_WSAAddressToString(); test_WSAStringToAddress(); test_GetAddrInfoW(); test_GetAddrInfoExW(); test_getaddrinfo(); test_dns(); test_gethostbyname(); test_gethostbyname_hack(); test_gethostname(); test_GetHostNameW(); test_WSAEnumNameSpaceProvidersA(); test_WSAEnumNameSpaceProvidersW(); test_WSCGetProviderInfo(); test_WSCGetProviderPath(); WSACleanup(); /* These tests are finnicky. If WSAStartup() is ever called with a * version below 2.2, it causes getaddrinfo() to behave differently. */ test_startup(); /* And if WSAAsyncGetServBy*() is ever called, it somehow causes * WSAStartup() to succeed with 0.1 instead of failing. */ ret = WSAStartup(0x202, &data); ok(!ret, "got %d\n", ret); test_WSAAsyncGetServByPort(); test_WSAAsyncGetServByName(); }