Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/netio.sys/netio.c | 88 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+)
diff --git a/dlls/netio.sys/netio.c b/dlls/netio.sys/netio.c index 2b8848a275e..408d75856c6 100644 --- a/dlls/netio.sys/netio.c +++ b/dlls/netio.sys/netio.c @@ -181,6 +181,90 @@ static const WSK_PROVIDER_LISTEN_DISPATCH wsk_provider_listen_dispatch = wsk_get_local_address, };
+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); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_get_remote_address(WSK_SOCKET *socket, SOCKADDR *remote_address, IRP *irp) +{ + FIXME("socket %p, remote_address %p, irp %p stub.\n", socket, remote_address, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_send(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp) +{ + FIXME("socket %p, buffer %p, flags %#x, irp %p stub.\n", socket, buffer, flags, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_receive(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp) +{ + FIXME("socket %p, buffer %p, flags %#x, irp %p stub.\n", socket, buffer, flags, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_disconnect(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp) +{ + FIXME("socket %p, buffer %p, flags %#x, irp %p stub.\n", socket, buffer, flags, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_release(WSK_SOCKET *socket, WSK_DATA_INDICATION *data_indication) +{ + FIXME("socket %p, data_indication %p stub.\n", socket, data_indication); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_connext_ex(WSK_SOCKET *socket, SOCKADDR *remote_address, WSK_BUF *buffer, + ULONG flags, IRP *irp) +{ + FIXME("socket %p, remote_address %p, buffer %p, flags %#x, irp %p stub.\n", + socket, remote_address, buffer, flags, irp); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_send_ex(void) +{ + FIXME("stub (no prototype, will crash).\n"); + + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS WINAPI wsk_receive_ex(void) +{ + FIXME("stub (no prototype, will crash).\n"); + + return STATUS_NOT_IMPLEMENTED; +} + +static const WSK_PROVIDER_CONNECTION_DISPATCH wsk_provider_connection_dispatch = +{ + { + wsk_control_socket, + wsk_close_socket, + }, + wsk_bind, + wsk_connect, + wsk_get_local_address, + wsk_get_remote_address, + wsk_send, + wsk_receive, + wsk_disconnect, + wsk_release, + wsk_connext_ex, + wsk_send_ex, + wsk_receive_ex, +}; + static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_family, USHORT socket_type, ULONG protocol, ULONG flags, void *socket_context, const void *dispatch, PEPROCESS owning_process, PETHREAD owning_thread, SECURITY_DESCRIPTOR *security_descriptor, IRP *irp) @@ -225,6 +309,10 @@ static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_fam socket->wsk_socket.Dispatch = &wsk_provider_listen_dispatch; break;
+ case WSK_FLAG_CONNECTION_SOCKET: + socket->wsk_socket.Dispatch = &wsk_provider_connection_dispatch; + break; + default: FIXME("Flags %#x not implemented.\n", flags); closesocket(s);
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/netio.sys/netio.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/dlls/netio.sys/netio.c b/dlls/netio.sys/netio.c index 408d75856c6..36a6a41b994 100644 --- a/dlls/netio.sys/netio.c +++ b/dlls/netio.sys/netio.c @@ -135,10 +135,24 @@ static NTSTATUS WINAPI wsk_close_socket(WSK_SOCKET *socket, IRP *irp)
static NTSTATUS WINAPI wsk_bind(WSK_SOCKET *socket, SOCKADDR *local_address, ULONG flags, IRP *irp) { - FIXME("socket %p, local_address %p, flags %#x, irp %p stub.\n", + struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket); + NTSTATUS status; + + TRACE("socket %p, local_address %p, flags %#x, irp %p.\n", socket, local_address, flags, irp);
- return STATUS_NOT_IMPLEMENTED; + if (!irp) + return STATUS_INVALID_PARAMETER; + + if (bind(s->s, local_address, sizeof(*local_address))) + status = sock_error_to_ntstatus(WSAGetLastError()); + else + status = STATUS_SUCCESS; + + TRACE("status %#x.\n", status); + irp->IoStatus.Information = 0; + dispatch_irp(irp, status); + return STATUS_PENDING; }
static NTSTATUS WINAPI wsk_accept(WSK_SOCKET *listen_socket, ULONG flags, void *accept_socket_context,
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/netio.sys/netio.c | 223 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 217 insertions(+), 6 deletions(-)
diff --git a/dlls/netio.sys/netio.c b/dlls/netio.sys/netio.c index 36a6a41b994..1d3f08603c7 100644 --- a/dlls/netio.sys/netio.c +++ b/dlls/netio.sys/netio.c @@ -44,14 +44,41 @@ struct _WSK_CLIENT WSK_CLIENT_NPI *client_npi; };
+struct listen_socket_callback_context +{ + SOCKADDR *remote_address; + const void *client_dispatch; + void *client_context; + char addr_buffer[2 * (sizeof(SOCKADDR) + 16)]; + SOCKET acceptor; +}; + struct wsk_socket_internal { WSK_SOCKET wsk_socket; SOCKET s; const void *client_dispatch; void *client_context; + ULONG flags; + ADDRESS_FAMILY address_family; + USHORT socket_type; + ULONG protocol; + OVERLAPPED ovr; + TP_WAIT *tp_wait; + IRP *pending_irp; + + CRITICAL_SECTION cs_socket; + + union + { + struct listen_socket_callback_context listen_socket_callback_context; + } + callback_context; };
+static LPFN_ACCEPTEX pAcceptEx; +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) { return CONTAINING_RECORD(wsk_socket, struct wsk_socket_internal, wsk_socket); @@ -79,7 +106,7 @@ static NTSTATUS sock_error_to_ntstatus(DWORD err) case WSAEAFNOSUPPORT: case WSAEPROTOTYPE: return STATUS_NOT_SUPPORTED; case WSAENOPROTOOPT: return STATUS_INVALID_PARAMETER; - case WSAEOPNOTSUPP: return STATUS_NOT_SUPPORTED; + case WSAEOPNOTSUPP: return STATUS_NOT_IMPLEMENTED; case WSAEADDRINUSE: return STATUS_ADDRESS_ALREADY_ASSOCIATED; case WSAEADDRNOTAVAIL: return STATUS_INVALID_PARAMETER; case WSAECONNREFUSED: return STATUS_CONNECTION_REFUSED; @@ -97,6 +124,27 @@ static NTSTATUS sock_error_to_ntstatus(DWORD err) } }
+static inline void lock_socket(struct wsk_socket_internal *socket) +{ + EnterCriticalSection(&socket->cs_socket); +} + +static inline void unlock_socket(struct wsk_socket_internal *socket) +{ + LeaveCriticalSection(&socket->cs_socket); +} + +static void socket_init(struct wsk_socket_internal *socket, PTP_WAIT_CALLBACK socket_async_callback) +{ + InitializeCriticalSection(&socket->cs_socket); + if (socket_async_callback) + { + socket->ovr.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + socket->tp_wait = CreateThreadpoolWait(socket_async_callback, socket, NULL); + SetThreadpoolWait(socket->tp_wait, socket->ovr.hEvent, NULL); + } +} + static void dispatch_irp(IRP *irp, NTSTATUS status) { irp->IoStatus.u.Status = status; @@ -124,7 +172,33 @@ static NTSTATUS WINAPI wsk_close_socket(WSK_SOCKET *socket, IRP *irp)
TRACE("socket %p, irp %p.\n", socket, irp);
+ lock_socket(s); + + if (s->tp_wait) + { + CancelIoEx((HANDLE)s->s, &s->ovr); + unlock_socket(s); + WaitForThreadpoolWaitCallbacks(s->tp_wait, FALSE); + lock_socket(s); + CloseThreadpoolWait(s->tp_wait); + } + + if (s->flags & WSK_FLAG_LISTEN_SOCKET && s->callback_context.listen_socket_callback_context.acceptor) + closesocket(s->callback_context.listen_socket_callback_context.acceptor); + status = closesocket(s->s) ? sock_error_to_ntstatus(WSAGetLastError()) : STATUS_SUCCESS; + + if (s->ovr.hEvent) + CloseHandle(s->ovr.hEvent); + + if (s->pending_irp) + { + s->pending_irp->IoStatus.Information = 0; + dispatch_irp(s->pending_irp, STATUS_CANCELLED); + } + + unlock_socket(s); + DeleteCriticalSection(&s->cs_socket); heap_free(socket);
irp->IoStatus.Information = 0; @@ -146,6 +220,8 @@ static NTSTATUS WINAPI wsk_bind(WSK_SOCKET *socket, SOCKADDR *local_address, ULO
if (bind(s->s, local_address, sizeof(*local_address))) status = sock_error_to_ntstatus(WSAGetLastError()); + else if (s->flags & WSK_FLAG_LISTEN_SOCKET && listen(s->s, SOMAXCONN)) + status = sock_error_to_ntstatus(WSAGetLastError()); else status = STATUS_SUCCESS;
@@ -155,16 +231,143 @@ static NTSTATUS WINAPI wsk_bind(WSK_SOCKET *socket, SOCKADDR *local_address, ULO return STATUS_PENDING; }
+static void create_accept_socket(struct wsk_socket_internal *socket) +{ + struct listen_socket_callback_context *context + = &socket->callback_context.listen_socket_callback_context; + struct wsk_socket_internal *accept_socket; + NTSTATUS status; + + if (!(accept_socket = heap_alloc_zero(sizeof(*accept_socket)))) + { + ERR("No memory.\n"); + status = STATUS_NO_MEMORY; + socket->pending_irp->IoStatus.Information = 0; + } + else + { + TRACE("accept_socket %p.\n", accept_socket); + accept_socket->wsk_socket.Dispatch = &wsk_provider_connection_dispatch; + accept_socket->s = context->acceptor; + accept_socket->client_dispatch = context->client_dispatch; + accept_socket->client_context = context->client_context; + accept_socket->socket_type = socket->socket_type; + accept_socket->address_family = socket->address_family; + accept_socket->protocol = socket->protocol; + accept_socket->flags = WSK_FLAG_CONNECTION_SOCKET; + socket_init(accept_socket, NULL); + /* TODO: fill local and remote addresses. */ + + socket->pending_irp->IoStatus.Information = (ULONG_PTR)&accept_socket->wsk_socket; + status = STATUS_SUCCESS; + } + TRACE("status %#x.\n", status); + dispatch_irp(socket->pending_irp, status); + socket->pending_irp = NULL; +} + +static void WINAPI accept_callback(TP_CALLBACK_INSTANCE *instance, void *socket_, TP_WAIT *wait, + TP_WAIT_RESULT wait_result) +{ + struct listen_socket_callback_context *context; + struct wsk_socket_internal *socket = socket_; + DWORD size; + + TRACE("instance %p, socket %p, wait %p, wait_result %#x.\n", instance, socket, wait, wait_result); + + lock_socket(socket); + context = &socket->callback_context.listen_socket_callback_context; + + if (GetOverlappedResult((HANDLE)socket->s, &socket->ovr, &size, FALSE)) + { + create_accept_socket(socket); + } + else + { + closesocket(context->acceptor); + context->acceptor = 0; + socket->pending_irp->IoStatus.Information = 0; + dispatch_irp(socket->pending_irp, socket->ovr.Internal); + socket->pending_irp = NULL; + } + unlock_socket(socket); +} + +static BOOL WINAPI init_accept_functions(INIT_ONCE *once, void *param, void **context) +{ + GUID acceptex_guid = WSAID_ACCEPTEX; + SOCKET s = (SOCKET)param; + DWORD size; + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &acceptex_guid, sizeof(acceptex_guid), + &pAcceptEx, sizeof(pAcceptEx), &size, NULL, NULL)) + { + ERR("Could not get AcceptEx address, error %u.\n", WSAGetLastError()); + return FALSE; + } + return TRUE; +} + static NTSTATUS WINAPI wsk_accept(WSK_SOCKET *listen_socket, ULONG flags, void *accept_socket_context, const WSK_CLIENT_CONNECTION_DISPATCH *accept_socket_dispatch, SOCKADDR *local_address, SOCKADDR *remote_address, IRP *irp) { - FIXME("listen_socket %p, flags %#x, accept_socket_context %p, accept_socket_dispatch %p, " - "local_address %p, remote_address %p, irp %p stub.\n", + struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(listen_socket); + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + struct listen_socket_callback_context *context; + SOCKET acceptor; + NTSTATUS status; + DWORD size; + int error; + + TRACE("listen_socket %p, flags %#x, accept_socket_context %p, accept_socket_dispatch %p, " + "local_address %p, remote_address %p, irp %p.\n", listen_socket, flags, accept_socket_context, accept_socket_dispatch, local_address, remote_address, irp);
- return STATUS_NOT_IMPLEMENTED; + if (!irp) + return STATUS_INVALID_PARAMETER; + + if (!InitOnceExecuteOnce(&init_once, init_accept_functions, (void *)s->s, NULL)) + { + status = STATUS_UNSUCCESSFUL; + dispatch_irp(irp, status); + return status; + } + + lock_socket(s); + context = &s->callback_context.listen_socket_callback_context; + if ((acceptor = WSASocketW(s->address_family, s->socket_type, s->protocol, NULL, 0, WSA_FLAG_OVERLAPPED)) + == INVALID_SOCKET) + { + status = sock_error_to_ntstatus(WSAGetLastError());; + dispatch_irp(irp, status); + unlock_socket(s); + return status; + } + + s->pending_irp = irp; + context->remote_address = remote_address; + context->client_dispatch = accept_socket_dispatch; + context->client_context = accept_socket_context; + context->acceptor = acceptor; + + if (pAcceptEx(s->s, acceptor, context->addr_buffer, 0, + sizeof(SOCKADDR) + 16, sizeof(SOCKADDR) + 16, &size, &s->ovr)) + { + create_accept_socket(s); + } + else if ((error = WSAGetLastError()) != ERROR_IO_PENDING) + { + closesocket(acceptor); + context->acceptor = 0; + irp->IoStatus.Information = 0; + dispatch_irp(irp, sock_error_to_ntstatus(error)); + s->pending_irp = NULL; + } + unlock_socket(s); + + return STATUS_PENDING; }
static NTSTATUS WINAPI wsk_inspect_complete(WSK_SOCKET *listen_socket, WSK_INSPECT_ID *inspect_id, @@ -284,6 +487,7 @@ static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_fam PETHREAD owning_thread, SECURITY_DESCRIPTOR *security_descriptor, IRP *irp) { struct wsk_socket_internal *socket; + PTP_WAIT_CALLBACK async_callback; NTSTATUS status; SOCKET s;
@@ -300,13 +504,13 @@ static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_fam
irp->IoStatus.Information = 0;
- if ((s = WSASocketW(address_family, socket_type, protocol, NULL, 0, 0)) == INVALID_SOCKET) + if ((s = WSASocketW(address_family, socket_type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) { status = sock_error_to_ntstatus(WSAGetLastError()); goto done; }
- if (!(socket = heap_alloc(sizeof(*socket)))) + if (!(socket = heap_alloc_zero(sizeof(*socket)))) { status = STATUS_NO_MEMORY; closesocket(s); @@ -316,11 +520,16 @@ static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_fam socket->s = s; socket->client_dispatch = dispatch; socket->client_context = socket_context; + socket->socket_type = socket_type; + socket->flags = flags; + socket->address_family = address_family; + socket->protocol = protocol;
switch (flags) { case WSK_FLAG_LISTEN_SOCKET: socket->wsk_socket.Dispatch = &wsk_provider_listen_dispatch; + async_callback = accept_callback; break;
case WSK_FLAG_CONNECTION_SOCKET: @@ -335,6 +544,8 @@ static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_fam goto done; }
+ socket_init(socket, async_callback); + irp->IoStatus.Information = (ULONG_PTR)&socket->wsk_socket; status = STATUS_SUCCESS;
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntoskrnl.exe/tests/Makefile.in | 2 +- dlls/ntoskrnl.exe/tests/driver4.c | 116 ++++++++++++++++++++++++++-- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 37 ++++++++- 3 files changed, 148 insertions(+), 7 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in index 06c06671ca1..779d4b28e6d 100644 --- a/dlls/ntoskrnl.exe/tests/Makefile.in +++ b/dlls/ntoskrnl.exe/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = ntoskrnl.exe -IMPORTS = advapi32 +IMPORTS = advapi32 ws2_32
driver_IMPORTS = winecrt0 ntoskrnl driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native diff --git a/dlls/ntoskrnl.exe/tests/driver4.c b/dlls/ntoskrnl.exe/tests/driver4.c index 4336fdb21a4..fd495a26e45 100644 --- a/dlls/ntoskrnl.exe/tests/driver4.c +++ b/dlls/ntoskrnl.exe/tests/driver4.c @@ -169,11 +169,19 @@ struct socket_context
static void test_wsk_listen_socket(void) { + const WSK_PROVIDER_LISTEN_DISPATCH *tcp_dispatch, *udp_dispatch; static const WSK_CLIENT_LISTEN_DISPATCH client_listen_dispatch; - const WSK_PROVIDER_LISTEN_DISPATCH *dispatch; + const WSK_PROVIDER_CONNECTION_DISPATCH *accept_dispatch; + WSK_SOCKET *tcp_socket, *udp_socket, *accept_socket; struct socket_context context; + struct sockaddr_in addr; + LARGE_INTEGER timeout; NTSTATUS status; - WSK_SOCKET *s; + KEVENT event; + IRP *irp; + + irp = IoAllocateIrp(1, FALSE); + KeInitializeEvent(&event, SynchronizationEvent, FALSE);
status = provider_npi.Dispatch->WskSocket(NULL, AF_INET, SOCK_STREAM, IPPROTO_TCP, WSK_FLAG_LISTEN_SOCKET, &context, &client_listen_dispatch, NULL, NULL, NULL, NULL); @@ -197,20 +205,118 @@ static void test_wsk_listen_socket(void) 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");
- s = (WSK_SOCKET *)wsk_irp->IoStatus.Information; - dispatch = s->Dispatch; + tcp_socket = (WSK_SOCKET *)wsk_irp->IoStatus.Information; + tcp_dispatch = tcp_socket->Dispatch; + + IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); + status = provider_npi.Dispatch->WskSocket(provider_npi.Client, AF_INET, SOCK_DGRAM, IPPROTO_UDP, + WSK_FLAG_LISTEN_SOCKET, &context, &client_listen_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"); + + udp_socket = (WSK_SOCKET *)wsk_irp->IoStatus.Information; + udp_dispatch = udp_socket->Dispatch; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(12345); + + 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 = udp_dispatch->WskBind(udp_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_NOT_IMPLEMENTED, "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); + status = udp_dispatch->Basic.WskCloseSocket(udp_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);
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 = dispatch->Basic.WskCloseSocket(s, wsk_irp); + status = tcp_dispatch->WskBind(tcp_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); + + timeout.QuadPart = -1000 * 10000; + + IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); + status = tcp_dispatch->WskAccept(tcp_socket, 0, NULL, NULL, NULL, NULL, wsk_irp); + ok(status == STATUS_PENDING, "Got unexpected status %#x.\n", status); + + if (0) + { + /* Queuing another WskAccept in parallel with different irp results in Windows hang. */ + IoReuseIrp(irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(irp, irp_completion_routine, &event, TRUE, TRUE, TRUE); + status = tcp_dispatch->WskAccept(tcp_socket, 0, NULL, NULL, NULL, NULL, 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 zero Information.\n"); + + if (status == STATUS_SUCCESS && wsk_irp->IoStatus.Status == STATUS_SUCCESS) + { + accept_socket = (WSK_SOCKET *)wsk_irp->IoStatus.Information; + accept_dispatch = accept_socket->Dispatch; + + IoReuseIrp(wsk_irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(wsk_irp, irp_completion_routine, &irp_complete_event, TRUE, TRUE, TRUE); + status = accept_dispatch->Basic.WskCloseSocket(accept_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); + } + + /* WskAccept to be aborted by WskCloseSocket(). */ + IoReuseIrp(irp, STATUS_UNSUCCESSFUL); + IoSetCompletionRoutine(irp, irp_completion_routine, &event, TRUE, TRUE, TRUE); + status = tcp_dispatch->WskAccept(tcp_socket, 0, NULL, NULL, NULL, NULL, irp); + ok(status == STATUS_PENDING, "Got unexpected status %#x.\n", status); + + 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 = tcp_dispatch->Basic.WskCloseSocket(tcp_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); + + status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#x.\n", status); + ok(irp->IoStatus.Status == STATUS_CANCELLED, "Got unexpected status %#x.\n", irp->IoStatus.Status); + ok(!irp->IoStatus.Information, "Got unexpected Information %#lx.\n", irp->IoStatus.Information); + IoFreeIrp(irp); }
static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack) diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index c2afee3dfe9..4cdcda7d3ea 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -27,6 +27,7 @@ #include "winsvc.h" #include "winioctl.h" #include "winternl.h" +#include "winsock2.h" #include "wine/test.h" #include "wine/heap.h"
@@ -513,10 +514,42 @@ static void test_driver3(void) DeleteFileA(filename); }
-void test_driver4(void) +static DWORD WINAPI wsk_test_thread(void *parameter) +{ + static const WORD version = MAKEWORD(2, 2); + struct sockaddr_in addr; + 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()); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(12345); + addr.sin_addr.s_addr = htonl(0x7f000001); + + ret = connect(s, (struct sockaddr *)&addr, sizeof(addr)); + while (ret && ((err = WSAGetLastError()) == WSAECONNREFUSED || err == WSAECONNABORTED)) + { + SwitchToThread(); + ret = connect(s, (struct sockaddr *)&addr, sizeof(addr)); + } + ok(!ret, "Error connecting, WSAGetLastError() %u.\n", WSAGetLastError()); + + closesocket(s); + return TRUE; +} + +static void test_driver4(void) { char filename[MAX_PATH]; SC_HANDLE service; + HANDLE hthread; DWORD written; BOOL ret;
@@ -532,7 +565,9 @@ void test_driver4(void) device = CreateFileA("\\.\WineTestDriver4", 0, 0, NULL, OPEN_EXISTING, 0, NULL); ok(device != INVALID_HANDLE_VALUE, "failed to open device: %u\n", GetLastError());
+ hthread = CreateThread(NULL, 0, wsk_test_thread, NULL, 0, NULL); main_test(); + WaitForSingleObject(hthread, INFINITE);
ret = DeviceIoControl(device, IOCTL_WINETEST_DETACH, NULL, 0, NULL, 0, &written, NULL); ok(ret, "DeviceIoControl failed: %u\n", GetLastError());