Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntoskrnl.exe/tests/driver.h | 2 ++ dlls/ntoskrnl.exe/tests/driver4.c | 2 +- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h index 4b70046b8e2..3bfc4bd80ac 100644 --- a/dlls/ntoskrnl.exe/tests/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.h @@ -55,3 +55,5 @@ static inline char *drv_strrchr( const char *str, char ch ) do { if (*str == ch) ret = (char *)(ULONG_PTR)str; } while (*str++); return ret; } + +#define SERVER_LISTEN_PORT 9374 diff --git a/dlls/ntoskrnl.exe/tests/driver4.c b/dlls/ntoskrnl.exe/tests/driver4.c index fedd5f25c2c..e11879e9e5b 100644 --- a/dlls/ntoskrnl.exe/tests/driver4.c +++ b/dlls/ntoskrnl.exe/tests/driver4.c @@ -243,7 +243,7 @@ static void test_wsk_listen_socket(void)
memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_port = htons(12345); + addr.sin_port = htons(SERVER_LISTEN_PORT);
IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index c53f97e9d19..5555095bd22 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -532,7 +532,7 @@ static DWORD WINAPI wsk_test_thread(void *parameter)
memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_port = htons(12345); + addr.sin_port = htons(SERVER_LISTEN_PORT); addr.sin_addr.s_addr = htonl(0x7f000001);
ret = connect(s, (struct sockaddr *)&addr, sizeof(addr));
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/netio.sys/netio.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/dlls/netio.sys/netio.c b/dlls/netio.sys/netio.c index b4f3b42ed04..cac5b8ceb51 100644 --- a/dlls/netio.sys/netio.c +++ b/dlls/netio.sys/netio.c @@ -59,6 +59,7 @@ struct wsk_pending_io { OVERLAPPED ovr; TP_WAIT *tp_wait; + void *callback; IRP *irp; };
@@ -159,27 +160,41 @@ static struct wsk_pending_io *allocate_pending_io(struct wsk_socket_internal *so PTP_WAIT_CALLBACK socket_async_callback, IRP *irp) { struct wsk_pending_io *io = socket->pending_io; - unsigned int i; + unsigned int i, io_index;
+ io_index = ~0u; for (i = 0; i < ARRAY_SIZE(socket->pending_io); ++i) + { if (!io[i].irp) - break; + { + if (io[i].callback == socket_async_callback) + { + io[i].irp = irp; + return &io[i]; + } + + if (io_index == ~0u) + io_index = i; + } + }
- if (i == ARRAY_SIZE(socket->pending_io)) + if (io_index == ~0u) { FIXME("Pending io requests count exceeds limit.\n"); return NULL; }
- io[i].irp = irp; + io[io_index].irp = irp;
- if (io[i].tp_wait) - return &io[i]; + if (io[io_index].tp_wait) + CloseThreadpoolWait(io[io_index].tp_wait); + else + io[io_index].ovr.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
- io[i].ovr.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - io[i].tp_wait = CreateThreadpoolWait(socket_async_callback, socket, NULL); + io[io_index].tp_wait = CreateThreadpoolWait(socket_async_callback, socket, NULL); + io[io_index].callback = socket_async_callback;
- return &io[i]; + return &io[io_index]; }
static struct wsk_pending_io *find_pending_io(struct wsk_socket_internal *socket, TP_WAIT *tp_wait)
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/netio.sys/netio.c | 92 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-)
diff --git a/dlls/netio.sys/netio.c b/dlls/netio.sys/netio.c index cac5b8ceb51..dd6d2f48140 100644 --- a/dlls/netio.sys/netio.c +++ b/dlls/netio.sys/netio.c @@ -53,6 +53,15 @@ struct listen_socket_callback_context SOCKET acceptor; };
+struct connect_socket_callback_context +{ + struct wsk_socket_internal *socket; + SOCKADDR *remote_address; + const void *client_dispatch; + void *client_context; + IRP *pending_irp; +}; + #define MAX_PENDING_IO 10
struct wsk_pending_io @@ -73,6 +82,7 @@ struct wsk_socket_internal ADDRESS_FAMILY address_family; USHORT socket_type; ULONG protocol; + BOOL bound;
CRITICAL_SECTION cs_socket;
@@ -86,6 +96,8 @@ struct wsk_socket_internal };
static LPFN_ACCEPTEX pAcceptEx; +static LPFN_CONNECTEX pConnectEx; + static const WSK_PROVIDER_CONNECTION_DISPATCH wsk_provider_connection_dispatch;
static inline struct wsk_socket_internal *wsk_socket_internal_from_wsk_socket(WSK_SOCKET *wsk_socket) @@ -294,6 +306,9 @@ static NTSTATUS WINAPI wsk_bind(WSK_SOCKET *socket, SOCKADDR *local_address, ULO else status = STATUS_SUCCESS;
+ if (status == STATUS_SUCCESS) + s->bound = TRUE; + TRACE("status %#x.\n", status); irp->IoStatus.Information = 0; dispatch_irp(irp, status); @@ -468,11 +483,84 @@ static const WSK_PROVIDER_LISTEN_DISPATCH wsk_provider_listen_dispatch = wsk_get_local_address, };
+static void WINAPI connect_callback(TP_CALLBACK_INSTANCE *instance, void *socket_, TP_WAIT *wait, + TP_WAIT_RESULT wait_result) +{ + struct wsk_socket_internal *socket = socket_; + struct wsk_pending_io *io; + DWORD size; + + TRACE("instance %p, socket %p, wait %p, wait_result %#x.\n", instance, socket, wait, wait_result); + + lock_socket(socket); + io = find_pending_io(socket, wait); + + GetOverlappedResult((HANDLE)socket->s, &io->ovr, &size, FALSE); + dispatch_pending_io(io, io->ovr.Internal, 0); + unlock_socket(socket); +} + +static BOOL WINAPI init_connect_functions(INIT_ONCE *once, void *param, void **context) +{ + GUID connectex_guid = WSAID_CONNECTEX; + SOCKET s = (SOCKET)param; + DWORD size; + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &connectex_guid, sizeof(connectex_guid), + &pConnectEx, sizeof(pConnectEx), &size, NULL, NULL)) + { + ERR("Could not get AcceptEx address, error %u.\n", WSAGetLastError()); + return FALSE; + } + return TRUE; +} + static NTSTATUS WINAPI wsk_connect(WSK_SOCKET *socket, SOCKADDR *remote_address, ULONG flags, IRP *irp) { - FIXME("socket %p, remote_address %p, flags %#x, irp %p stub.\n", socket, remote_address, flags, irp); + struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket); + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + struct wsk_pending_io *io; + int error;
- return STATUS_NOT_IMPLEMENTED; + TRACE("socket %p, remote_address %p, flags %#x, irp %p.\n", + socket, remote_address, flags, irp); + + if (!irp) + return STATUS_INVALID_PARAMETER; + + if (!InitOnceExecuteOnce(&init_once, init_connect_functions, (void *)s->s, NULL)) + { + dispatch_irp(irp, STATUS_UNSUCCESSFUL); + return STATUS_PENDING; + } + + lock_socket(s); + + if (!(io = allocate_pending_io(s, connect_callback, irp))) + { + irp->IoStatus.Information = 0; + dispatch_irp(irp, STATUS_UNSUCCESSFUL); + unlock_socket(s); + return STATUS_PENDING; + } + + if (!s->bound) + { + dispatch_pending_io(io, STATUS_INVALID_DEVICE_STATE, 0); + unlock_socket(s); + return STATUS_INVALID_DEVICE_STATE; + } + + if (pConnectEx(s->s, remote_address, sizeof(*remote_address), NULL, 0, NULL, &io->ovr)) + dispatch_pending_io(io, STATUS_SUCCESS, 0); + else if ((error = WSAGetLastError()) == ERROR_IO_PENDING) + SetThreadpoolWait(io->tp_wait, io->ovr.hEvent, NULL); + else + dispatch_pending_io(io, sock_error_to_ntstatus(error), 0); + + unlock_socket(s); + + return STATUS_PENDING; }
static NTSTATUS WINAPI wsk_get_remote_address(WSK_SOCKET *socket, SOCKADDR *remote_address, IRP *irp)
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntoskrnl.exe/tests/driver.h | 1 + dlls/ntoskrnl.exe/tests/driver4.c | 83 ++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 31 +++++++---- 3 files changed, 106 insertions(+), 9 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h index 3bfc4bd80ac..58a92d4838e 100644 --- a/dlls/ntoskrnl.exe/tests/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.h @@ -57,3 +57,4 @@ static inline char *drv_strrchr( const char *str, char ch ) }
#define SERVER_LISTEN_PORT 9374 +#define CLIENT_LISTEN_PORT 9375 diff --git a/dlls/ntoskrnl.exe/tests/driver4.c b/dlls/ntoskrnl.exe/tests/driver4.c index e11879e9e5b..32a200bbd18 100644 --- a/dlls/ntoskrnl.exe/tests/driver4.c +++ b/dlls/ntoskrnl.exe/tests/driver4.c @@ -370,6 +370,88 @@ static void test_wsk_listen_socket(void) ExFreePool(buffer2); }
+static void test_wsk_connect_socket(void) +{ + const WSK_PROVIDER_CONNECTION_DISPATCH *connect_dispatch; + struct socket_context context; + struct sockaddr_in addr; + LARGE_INTEGER timeout; + WSK_SOCKET *socket; + NTSTATUS status; + + timeout.QuadPart = -1000 * 10000; + + IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); + wsk_irp->IoStatus.Status = 0xdeadbeef; + wsk_irp->IoStatus.Information = 0xdeadbeef; + status = provider_npi.Dispatch->WskSocket(provider_npi.Client, AF_INET, SOCK_STREAM, IPPROTO_TCP, + WSK_FLAG_CONNECTION_SOCKET, &context, &connect_dispatch, NULL, NULL, NULL, wsk_irp); + ok(status == STATUS_PENDING, "Got unexpected status %#x.\n", status); + status = KeWaitForSingleObject(&irp_complete_event, Executive, KernelMode, FALSE, NULL); + ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + ok(wsk_irp->IoStatus.Status == STATUS_SUCCESS, "Got unexpected status %#x.\n", wsk_irp->IoStatus.Status); + ok(wsk_irp->IoStatus.Information, "Got zero Information.\n"); + + socket = (WSK_SOCKET *)wsk_irp->IoStatus.Information; + connect_dispatch = socket->Dispatch; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(CLIENT_LISTEN_PORT); + addr.sin_addr.s_addr = htonl(0x7f000001); + + IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); + status = connect_dispatch->WskConnect(socket, (SOCKADDR *)&addr, 0, wsk_irp); + ok(status == STATUS_INVALID_DEVICE_STATE, "Got unexpected status %#x.\n", status); + status = KeWaitForSingleObject(&irp_complete_event, Executive, KernelMode, FALSE, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + ok(wsk_irp->IoStatus.Status == STATUS_INVALID_DEVICE_STATE, "Got unexpected status %#x.\n", wsk_irp->IoStatus.Status); + ok(!wsk_irp->IoStatus.Information, "Got unexpected Information %#lx.\n", + wsk_irp->IoStatus.Information); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + + IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); + wsk_irp->IoStatus.Status = 0xdeadbeef; + wsk_irp->IoStatus.Information = 0xdeadbeef; + status = connect_dispatch->WskBind(socket, (SOCKADDR *)&addr, 0, wsk_irp); + ok(status == STATUS_PENDING, "Got unexpected status %#x.\n", status); + status = KeWaitForSingleObject(&irp_complete_event, Executive, KernelMode, FALSE, NULL); + ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + ok(wsk_irp->IoStatus.Status == STATUS_SUCCESS, "Got unexpected status %#x.\n", wsk_irp->IoStatus.Status); + ok(!wsk_irp->IoStatus.Information, "Got unexpected Information %#lx.\n", + wsk_irp->IoStatus.Information); + + addr.sin_port = htons(CLIENT_LISTEN_PORT); + addr.sin_addr.s_addr = htonl(0x7f000001); + + IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); + status = connect_dispatch->WskConnect(socket, (SOCKADDR *)&addr, 0, wsk_irp); + ok(status == STATUS_PENDING, "Got unexpected status %#x.\n", status); + status = KeWaitForSingleObject(&irp_complete_event, Executive, KernelMode, FALSE, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + ok(wsk_irp->IoStatus.Status == STATUS_SUCCESS, "Got unexpected status %#x.\n", wsk_irp->IoStatus.Status); + ok(!wsk_irp->IoStatus.Information, "Got unexpected Information %#lx.\n", + wsk_irp->IoStatus.Information); + + IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); + wsk_irp->IoStatus.Status = 0xdeadbeef; + wsk_irp->IoStatus.Information = 0xdeadbeef; + status = connect_dispatch->Basic.WskCloseSocket(socket, wsk_irp); + ok(status == STATUS_PENDING, "Got unexpected status %#x.\n", status); + status = KeWaitForSingleObject(&irp_complete_event, Executive, KernelMode, FALSE, NULL); + ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + ok(wsk_irp->IoStatus.Status == STATUS_SUCCESS, "Got unexpected status %#x.\n", wsk_irp->IoStatus.Status); + ok(!wsk_irp->IoStatus.Information, "Got unexpected Information %#lx.\n", + wsk_irp->IoStatus.Information); +} + static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack) { ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; @@ -396,6 +478,7 @@ static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *st netio_init(); test_wsk_get_address_info(); test_wsk_listen_socket(); + test_wsk_connect_socket();
if (winetest_debug) { diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 5555095bd22..be6f47161ba 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -518,39 +518,52 @@ static DWORD WINAPI wsk_test_thread(void *parameter) { static const char test_send_string[] = "Client test string 1."; static const WORD version = MAKEWORD(2, 2); + SOCKET s_listen, s_accept, s_connect; struct sockaddr_in addr; char buffer[256]; int ret, err; WSADATA data; - SOCKET s;
ret = WSAStartup(version, &data); ok(!ret, "WSAStartup() failed, ret %u.\n", ret);
- s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - ok(s != INVALID_SOCKET, "Error creating socket, WSAGetLastError() %u.\n", WSAGetLastError()); + s_connect = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(s_connect != INVALID_SOCKET, "Error creating socket, WSAGetLastError() %u.\n", WSAGetLastError()); + + s_listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(s_listen != INVALID_SOCKET, "Error creating socket, WSAGetLastError() %u.\n", WSAGetLastError());
memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_port = htons(SERVER_LISTEN_PORT); + addr.sin_port = htons(CLIENT_LISTEN_PORT); addr.sin_addr.s_addr = htonl(0x7f000001); + ret = bind(s_listen, (struct sockaddr *)&addr, sizeof(addr)); + ok(!ret, "Got unexpected ret %d, WSAGetLastError() %u.\n", ret, WSAGetLastError()); + ret = listen(s_listen, SOMAXCONN); + ok(!ret, "Got unexpected ret %d, WSAGetLastError() %u.\n", ret, WSAGetLastError());
- ret = connect(s, (struct sockaddr *)&addr, sizeof(addr)); + addr.sin_port = htons(SERVER_LISTEN_PORT); + + ret = connect(s_connect, (struct sockaddr *)&addr, sizeof(addr)); while (ret && ((err = WSAGetLastError()) == WSAECONNREFUSED || err == WSAECONNABORTED)) { SwitchToThread(); - ret = connect(s, (struct sockaddr *)&addr, sizeof(addr)); + ret = connect(s_connect, (struct sockaddr *)&addr, sizeof(addr)); } ok(!ret, "Error connecting, WSAGetLastError() %u.\n", WSAGetLastError());
- ret = send(s, test_send_string, sizeof(test_send_string), 0); + ret = send(s_connect, test_send_string, sizeof(test_send_string), 0); ok(ret == sizeof(test_send_string), "Got unexpected ret %d.\n", ret);
- ret = recv(s, buffer, sizeof(buffer), 0); + ret = recv(s_connect, buffer, sizeof(buffer), 0); ok(ret == sizeof(buffer), "Got unexpected ret %d.\n", ret); ok(!strcmp(buffer, "Server test string 1."), "Received unexpected data.\n");
- closesocket(s); + s_accept = accept(s_listen, NULL, NULL); + ok(s_accept != INVALID_SOCKET, "Error creating socket, WSAGetLastError() %u.\n", WSAGetLastError()); + + closesocket(s_connect); + closesocket(s_listen); return TRUE; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73897
Your paranoid android.
=== debiant (32 bit French report) ===
ntoskrnl.exe: driver4.c:276: Test failed: Got unexpected status 0xc0000238. driver4.c:298: Test failed: Got unexpected status 0xc00000b0. driver4.c:299: Test failed: Got zero Information. driver4.c:363: Test failed: Got unexpected status 0xc00000b0. ntoskrnl: Timeout
=== debiant (32 bit Chinese:China report) ===
ntoskrnl.exe: driver4.c:276: Test failed: Got unexpected status 0xc0000238. driver4.c:298: Test failed: Got unexpected status 0xc00000b0. driver4.c:299: Test failed: Got zero Information. driver4.c:363: Test failed: Got unexpected status 0xc00000b0. ntoskrnl: Timeout
=== debiant (64 bit WoW report) ===
ntoskrnl.exe: driver4.c:276: Test failed: Got unexpected status 0xc0000238. driver4.c:298: Test failed: Got unexpected status 0xc00000b0. driver4.c:299: Test failed: Got zero Information. driver4.c:363: Test failed: Got unexpected status 0xc00000b0. ntoskrnl: Timeout