diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 843ec5ba3ab..f4e3a6c9e43 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3463,6 +3463,28 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID return ret ? -1 : 0; } + case WS_SIO_BASE_HANDLE: + { + NTSTATUS status; + DWORD ret; + + if (overlapped) + { + status = STATUS_NOT_SUPPORTED; + } + else + { + status = STATUS_SUCCESS; + *(SOCKET *)out_buff = s; + } + ret = server_ioctl_sock( s, IOCTL_AFD_WINE_COMPLETE_ASYNC, &status, sizeof(status), + NULL, 0, ret_size, overlapped, completion ); + if (overlapped) ret = ERROR_IO_PENDING; + if (!ret) *ret_size = sizeof(SOCKET); + SetLastError( ret ); + return ret ? -1 : 0; + } + default: FIXME( "unimplemented ioctl %s\n", debugstr_wsaioctl( code ) ); /* fall through */ diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index d581b1df6c1..76d0a3f3b19 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -4275,6 +4275,97 @@ static void test_get_extension_func(void) closesocket(s); } +static void test_base_handle(void) +{ + OVERLAPPED overlapped = {0}, *overlapped_ptr; + unsigned int i; + SOCKET s, base; + ULONG_PTR key; + HANDLE port; + DWORD size; + int ret; + + static const struct + { + int family, type, protocol; + } + tests[] = + { + {AF_INET, SOCK_STREAM, IPPROTO_TCP}, + {AF_INET, SOCK_DGRAM, IPPROTO_UDP}, + {AF_INET6, SOCK_STREAM, IPPROTO_TCP}, + {AF_INET6, SOCK_DGRAM, IPPROTO_UDP}, + }; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + s = socket(tests[i].family, tests[i].type, tests[i].protocol); + if (s == INVALID_SOCKET) continue; + port = CreateIoCompletionPort((HANDLE)s, NULL, 123, 0); + + WSASetLastError(0xdeadbeef); + ret = WSAIoctl(s, SIO_BASE_HANDLE, NULL, 0, &base, sizeof(base), NULL, &overlapped, NULL); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + base = 0xdeadbeef; + ret = WSAIoctl(s, SIO_BASE_HANDLE, NULL, 0, &base, sizeof(base), &size, NULL, NULL); + ok(!ret, "expected success\n"); + ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + ok(size == sizeof(base), "got size %u\n", size); + ok(base == s, "expected %#Ix, got %#Ix\n", s, base); + + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + base = 0xdeadbeef; + overlapped.Internal = 0xdeadbeef; + overlapped.InternalHigh = 0xdeadbeef; + ret = WSAIoctl(s, SIO_BASE_HANDLE, NULL, 0, &base, sizeof(base), &size, &overlapped, NULL); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == ERROR_IO_PENDING, "got error %u\n", WSAGetLastError()); + ok(size == 0xdeadbeef, "got size %u\n", size); + + ret = GetQueuedCompletionStatus(port, &size, &key, &overlapped_ptr, 0); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_NOT_SUPPORTED, "got error %u\n", GetLastError()); + ok(!size, "got size %u\n", size); + ok(key == 123, "got key %Iu\n", key); + ok(overlapped_ptr == &overlapped, "got overlapped %p\n", overlapped_ptr); + ok((NTSTATUS)overlapped.Internal == STATUS_NOT_SUPPORTED, "got status %#x\n", (NTSTATUS)overlapped.Internal); + ok(!overlapped.InternalHigh, "got size %Iu\n", overlapped.InternalHigh); + ok(base == 0xdeadbeef, "expected %#Ix, got %#Ix\n", s, base); + + CloseHandle(port); + closesocket(s); + + s = socket(tests[i].family, tests[i].type, tests[i].protocol); + + ret = WSAIoctl(s, SIO_BASE_HANDLE, NULL, 0, &base, sizeof(base), NULL, &overlapped, socket_apc); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError()); + + apc_count = 0; + size = 0xdeadbeef; + base = 0xdeadbeef; + ret = WSAIoctl(s, SIO_BASE_HANDLE, NULL, 0, &base, sizeof(base), &size, &overlapped, socket_apc); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == ERROR_IO_PENDING, "got error %u\n", WSAGetLastError()); + ok(size == 0xdeadbeef, "got size %u\n", size); + + ret = SleepEx(0, TRUE); + ok(ret == WAIT_IO_COMPLETION, "got %d\n", ret); + ok(apc_count == 1, "APC was called %u times\n", apc_count); + ok(apc_error == WSAEOPNOTSUPP, "got APC error %u\n", apc_error); + ok(!apc_size, "got APC size %u\n", apc_size); + ok(apc_overlapped == &overlapped, "got APC overlapped %p\n", apc_overlapped); + ok(base == 0xdeadbeef, "expected %#Ix, got %#Ix\n", s, base); + + closesocket(s); + } +} + static BOOL drain_pause = FALSE; static DWORD WINAPI drain_socket_thread(LPVOID arg) { @@ -10837,6 +10928,7 @@ START_TEST( sock ) test_keepalive_vals(); test_sioRoutingInterfaceQuery(); test_sioAddressListChange(); + test_base_handle(); test_unsupported_ioctls(); test_WSASendMsg(); diff --git a/include/mswsock.h b/include/mswsock.h index e402f33ecf7..fa97d5bf04d 100644 --- a/include/mswsock.h +++ b/include/mswsock.h @@ -83,11 +83,13 @@ extern "C" { #endif #ifndef USE_WS_PREFIX -#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) -#define SIO_SET_COMPATIBILITY_MODE _WSAIOW(IOC_VENDOR,300) +#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12) +#define SIO_SET_COMPATIBILITY_MODE _WSAIOW(IOC_VENDOR, 300) +#define SIO_BASE_HANDLE _WSAIOR(IOC_WS2, 34) #else -#define WS_SIO_UDP_CONNRESET _WSAIOW(WS_IOC_VENDOR,12) -#define WS_SIO_SET_COMPATIBILITY_MODE _WSAIOW(WS_IOC_VENDOR,300) +#define WS_SIO_UDP_CONNRESET _WSAIOW(WS_IOC_VENDOR, 12) +#define WS_SIO_SET_COMPATIBILITY_MODE _WSAIOW(WS_IOC_VENDOR, 300) +#define WS_SIO_BASE_HANDLE _WSAIOR(WS_IOC_WS2, 34) #endif #define DE_REUSE_SOCKET TF_REUSE_SOCKET