From: Zebediah Figura zfigura@codeweavers.com
recv_socket does some extra bookkeeping that's currently missing from the register_async path. Instead of adding it to sock_queue_async(), let's just centralize all recv requests so that they go through recv_socket. --- dlls/ntdll/unix/file.c | 6 ++ dlls/ntdll/unix/socket.c | 129 ++++++++++++++++++++------------- dlls/ntdll/unix/unix_private.h | 2 + dlls/ws2_32/tests/afd.c | 2 +- 4 files changed, 89 insertions(+), 50 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index e09e8cafc82..f57532f55bf 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -5177,6 +5177,12 @@ NTSTATUS WINAPI NtReadFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, vo goto done; } } + else if (type == FD_TYPE_SOCKET) + { + status = sock_read( handle, unix_handle, event, apc, apc_user, io, buffer, length ); + if (needs_close) close( unix_handle ); + return status; + }
if (type == FD_TYPE_SERIAL && async_read && length) { diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 351028d4983..6abee680ee5 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -676,17 +676,67 @@ static BOOL async_recv_proc( void *user, ULONG_PTR *info, NTSTATUS *status ) }
static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, - int fd, const void *buffers_ptr, unsigned int count, WSABUF *control, - struct WS_sockaddr *addr, int *addr_len, DWORD *ret_flags, int unix_flags, int force_async ) + int fd, struct async_recv_ioctl *async, int force_async ) { - struct async_recv_ioctl *async; + BOOL nonblocking, alerted; ULONG_PTR information; HANDLE wait_handle; - DWORD async_size; NTSTATUS status; unsigned int i; ULONG options; - BOOL nonblocking, alerted; + + for (i = 0; i < async->count; ++i) + { + if (!virtual_check_buffer_for_write( async->iov[i].iov_base, async->iov[i].iov_len )) + { + release_fileio( &async->io ); + return STATUS_ACCESS_VIOLATION; + } + } + + SERVER_START_REQ( recv_socket ) + { + req->force_async = force_async; + req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) ); + req->oob = !!(async->unix_flags & MSG_OOB); + status = wine_server_call( req ); + wait_handle = wine_server_ptr_handle( reply->wait ); + options = reply->options; + nonblocking = reply->nonblocking; + } + SERVER_END_REQ; + + alerted = status == STATUS_ALERTED; + if (alerted) + { + status = try_recv( fd, async, &information ); + if (status == STATUS_DEVICE_NOT_READY && (force_async || !nonblocking)) + status = STATUS_PENDING; + } + + if (status != STATUS_PENDING) + { + if (!NT_ERROR(status) || (wait_handle && !alerted)) + { + io->Status = status; + io->Information = information; + } + release_fileio( &async->io ); + } + + if (alerted) set_async_direct_result( &wait_handle, status, information, FALSE ); + if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT ); + return status; +} + + +static NTSTATUS sock_ioctl_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, + int fd, const void *buffers_ptr, unsigned int count, WSABUF *control, + struct WS_sockaddr *addr, int *addr_len, DWORD *ret_flags, int unix_flags, int force_async ) +{ + struct async_recv_ioctl *async; + DWORD async_size; + unsigned int i;
if (unix_flags & MSG_OOB) { @@ -728,48 +778,29 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi async->addr_len = addr_len; async->ret_flags = ret_flags;
- for (i = 0; i < count; ++i) - { - if (!virtual_check_buffer_for_write( async->iov[i].iov_base, async->iov[i].iov_len )) - { - release_fileio( &async->io ); - return STATUS_ACCESS_VIOLATION; - } - } + return sock_recv( handle, event, apc, apc_user, io, fd, async, force_async ); +}
- SERVER_START_REQ( recv_socket ) - { - req->force_async = force_async; - req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) ); - req->oob = !!(unix_flags & MSG_OOB); - status = wine_server_call( req ); - wait_handle = wine_server_ptr_handle( reply->wait ); - options = reply->options; - nonblocking = reply->nonblocking; - } - SERVER_END_REQ;
- alerted = status == STATUS_ALERTED; - if (alerted) - { - status = try_recv( fd, async, &information ); - if (status == STATUS_DEVICE_NOT_READY && (force_async || !nonblocking)) - status = STATUS_PENDING; - } +NTSTATUS sock_read( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE apc, + void *apc_user, IO_STATUS_BLOCK *io, void *buffer, ULONG length ) +{ + static const DWORD async_size = offsetof( struct async_recv_ioctl, iov[1] ); + struct async_recv_ioctl *async;
- if (status != STATUS_PENDING) - { - if (!NT_ERROR(status) || (wait_handle && !alerted)) - { - io->Status = status; - io->Information = information; - } - release_fileio( &async->io ); - } + if (!(async = (struct async_recv_ioctl *)alloc_fileio( async_size, async_recv_proc, handle ))) + return STATUS_NO_MEMORY;
- if (alerted) set_async_direct_result( &wait_handle, status, information, FALSE ); - if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT ); - return status; + async->count = 1; + async->iov[0].iov_base = buffer; + async->iov[0].iov_len = length; + async->unix_flags = 0; + async->control = NULL; + async->addr = NULL; + async->addr_len = NULL; + async->ret_flags = NULL; + + return sock_recv( handle, event, apc, apc_user, io, fd, async, 1 ); }
@@ -1334,8 +1365,8 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc unix_flags |= MSG_PEEK; if (params.msg_flags & AFD_MSG_WAITALL) FIXME( "MSG_WAITALL is not supported\n" ); - status = sock_recv( handle, event, apc, apc_user, io, fd, params.buffers, params.count, NULL, - NULL, NULL, NULL, unix_flags, !!(params.recv_flags & AFD_RECV_FORCE_ASYNC) ); + status = sock_ioctl_recv( handle, event, apc, apc_user, io, fd, params.buffers, params.count, NULL, + NULL, NULL, NULL, unix_flags, !!(params.recv_flags & AFD_RECV_FORCE_ASYNC) ); if (needs_close) close( fd ); return status; } @@ -1361,10 +1392,10 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc unix_flags |= MSG_PEEK; if (*ws_flags & WS_MSG_WAITALL) FIXME( "MSG_WAITALL is not supported\n" ); - status = sock_recv( handle, event, apc, apc_user, io, fd, u64_to_user_ptr(params->buffers_ptr), - params->count, u64_to_user_ptr(params->control_ptr), - u64_to_user_ptr(params->addr_ptr), u64_to_user_ptr(params->addr_len_ptr), - ws_flags, unix_flags, params->force_async ); + status = sock_ioctl_recv( handle, event, apc, apc_user, io, fd, u64_to_user_ptr(params->buffers_ptr), + params->count, u64_to_user_ptr(params->control_ptr), + u64_to_user_ptr(params->addr_ptr), u64_to_user_ptr(params->addr_len_ptr), + ws_flags, unix_flags, params->force_async ); if (needs_close) close( fd ); return status; } diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 39b667ddd4a..8d305bdada6 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -256,6 +256,8 @@ extern NTSTATUS serial_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROU extern NTSTATUS serial_FlushBuffersFile( int fd ) DECLSPEC_HIDDEN; extern NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size ) DECLSPEC_HIDDEN; +extern NTSTATUS sock_read( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, + IO_STATUS_BLOCK *io, void *buffer, ULONG length ) DECLSPEC_HIDDEN; extern NTSTATUS tape_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size ) DECLSPEC_HIDDEN; diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 22ccdd0adeb..334c2c41be6 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -2645,7 +2645,7 @@ static void test_read_write(void)
ret = WSAEnumNetworkEvents(client, event, &events); ok(!ret, "got error %lu\n", GetLastError()); - todo_wine ok(events.lNetworkEvents == FD_READ, "got events %#lx\n", events.lNetworkEvents); + ok(events.lNetworkEvents == FD_READ, "got events %#lx\n", events.lNetworkEvents);
memset(buffer, 0xcc, sizeof(buffer)); ret = NtReadFile((HANDLE)client, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL);