From: Zebediah Figura zfigura@codeweavers.com
--- dlls/ws2_32/tests/afd.c | 154 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 3 deletions(-)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index f84e7084a27..22ccdd0adeb 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -33,16 +33,16 @@
#define TIMEOUT_INFINITE _I64_MAX
-static void tcp_socketpair(SOCKET *src, SOCKET *dst) +static void tcp_socketpair_flags(SOCKET *src, SOCKET *dst, DWORD flags) { SOCKET server = INVALID_SOCKET; struct sockaddr_in addr; int len, ret;
- *src = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + *src = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, flags); ok(*src != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError());
- server = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + server = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, flags); ok(server != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError());
memset(&addr, 0, sizeof(addr)); @@ -68,6 +68,11 @@ static void tcp_socketpair(SOCKET *src, SOCKET *dst) closesocket(server); }
+static void tcp_socketpair(SOCKET *src, SOCKET *dst) +{ + tcp_socketpair_flags(src, dst, WSA_FLAG_OVERLAPPED); +} + static void set_blocking(SOCKET s, ULONG blocking) { int ret; @@ -2575,6 +2580,148 @@ static void test_async_thread_termination(void) closesocket(listener); }
+static DWORD WINAPI sync_read_file_thread(void *arg) +{ + HANDLE server = arg; + IO_STATUS_BLOCK io; + char buffer[5]; + NTSTATUS ret; + + memset(buffer, 0xcc, sizeof(buffer)); + memset(&io, 0xcc, sizeof(io)); + ret = NtReadFile(server, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL); + ok(!ret, "got status %#lx\n", ret); + ok(!io.Status, "got status %#lx\n", io.Status); + ok(io.Information == 4, "got size %Iu\n", io.Information); + ok(!memcmp(buffer, "data", 4), "got data %s\n", debugstr_an(buffer, io.Information)); + + return 0; +} + +static void test_read_write(void) +{ + WSANETWORKEVENTS events; + IO_STATUS_BLOCK io, io2; + SOCKET client, server; + LARGE_INTEGER offset; + HANDLE event, thread; + char buffer[5]; + NTSTATUS ret; + + event = CreateEventA(NULL, TRUE, FALSE, NULL); + + tcp_socketpair_flags(&client, &server, 0); + set_blocking(server, FALSE); + + memset(&io, 0xcc, sizeof(io)); + ret = NtWriteFile((HANDLE)client, NULL, NULL, NULL, &io, "data", 4, NULL, NULL); + ok(!ret, "got status %#lx\n", ret); + ok(!io.Status, "got status %#lx\n", io.Status); + ok(io.Information == 4, "got size %Iu\n", io.Information); + + memset(buffer, 0xcc, sizeof(buffer)); + memset(&io, 0xcc, sizeof(io)); + ret = NtReadFile((HANDLE)server, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL); + ok(!ret, "got status %#lx\n", ret); + ok(!io.Status, "got status %#lx\n", io.Status); + ok(io.Information == 4, "got size %Iu\n", io.Information); + ok(!memcmp(buffer, "data", 4), "got data %s\n", debugstr_an(buffer, io.Information)); + + ret = send(server, "data", 4, 0); + ok(ret == 4, "got %ld\n", ret); + + ret = WSAEventSelect(client, event, FD_READ); + ok(!ret, "got error %lu\n", GetLastError()); + + ret = WSAEnumNetworkEvents(client, event, &events); + ok(!ret, "got error %lu\n", GetLastError()); + 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, 1, NULL, NULL); + ok(!ret, "got status %#lx\n", ret); + ok(io.Information == 1, "got size %Iu\n", io.Information); + ok(buffer[0] == 'd', "got data %s\n", debugstr_an(buffer, io.Information)); + + 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); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = NtReadFile((HANDLE)client, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL); + ok(!ret, "got status %#lx\n", ret); + ok(io.Information == 3, "got size %Iu\n", io.Information); + ok(!memcmp(buffer, "ata", 3), "got data %s\n", debugstr_an(buffer, io.Information)); + + /* NtReadFile always blocks, even when the socket is non-overlapped and nonblocking */ + + thread = CreateThread(NULL, 0, sync_read_file_thread, (void *)server, 0, NULL); + ret = WaitForSingleObject(thread, 100); + ok(ret == WAIT_TIMEOUT, "got %ld\n", ret); + + ret = NtWriteFile((HANDLE)client, NULL, NULL, NULL, &io, "data", 4, NULL, NULL); + ok(!ret, "got status %#lx\n", ret); + + ret = WaitForSingleObject(thread, 1000); + ok(!ret, "got %ld\n", ret); + CloseHandle(thread); + + closesocket(server); + closesocket(client); + + tcp_socketpair(&client, &server); + + ret = NtReadFile((HANDLE)server, event, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL); + todo_wine ok(ret == STATUS_INVALID_PARAMETER, "got status %#lx\n", ret); + if (ret == STATUS_PENDING) + { + CancelIo((HANDLE)server); + ret = WaitForSingleObject(event, 100); + ok(!ret, "wait timed out\n"); + } + + offset.QuadPart = -1; + ret = NtReadFile((HANDLE)server, event, NULL, NULL, &io, buffer, sizeof(buffer), &offset, NULL); + todo_wine ok(ret == STATUS_INVALID_PARAMETER, "got status %#lx\n", ret); + if (ret == STATUS_PENDING) + { + CancelIo((HANDLE)server); + ret = WaitForSingleObject(event, 100); + ok(!ret, "wait timed out\n"); + } + + memset(buffer, 0xcc, sizeof(buffer)); + memset(&io, 0xcc, sizeof(io)); + offset.QuadPart = 1; + ret = NtReadFile((HANDLE)server, event, NULL, NULL, &io, buffer, sizeof(buffer), &offset, NULL); + ok(ret == STATUS_PENDING, "got status %#lx\n", ret); + + ret = NtWriteFile((HANDLE)client, NULL, NULL, NULL, &io2, "data", 4, NULL, NULL); + todo_wine ok(ret == STATUS_INVALID_PARAMETER, "got status %#lx\n", ret); + + offset.QuadPart = -3; + ret = NtWriteFile((HANDLE)client, NULL, NULL, NULL, &io2, "data", 4, &offset, NULL); + todo_wine ok(ret == STATUS_INVALID_PARAMETER, "got status %#lx\n", ret); + + memset(&io2, 0xcc, sizeof(io2)); + offset.QuadPart = 2; + ret = NtWriteFile((HANDLE)client, NULL, NULL, NULL, &io2, "data", 4, &offset, NULL); + ok(!ret, "got status %#lx\n", ret); + ok(!io2.Status, "got status %#lx\n", io2.Status); + ok(io2.Information == 4, "got size %Iu\n", io2.Information); + + ret = WaitForSingleObject(event, 1000); + ok(!ret, "wait timed out\n"); + ok(!io.Status, "got status %#lx\n", io.Status); + ok(io.Information == 4, "got size %Iu\n", io.Information); + ok(!memcmp(buffer, "data", 4), "got data %s\n", debugstr_an(buffer, io.Information)); + + closesocket(server); + closesocket(client); + + CloseHandle(event); +} + START_TEST(afd) { WSADATA data; @@ -2593,6 +2740,7 @@ START_TEST(afd) test_bind(); test_getsockname(); test_async_thread_termination(); + test_read_write();
WSACleanup(); }
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);
From: Zebediah Figura zfigura@codeweavers.com
send_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 send requests so that they go through send_socket. --- dlls/ntdll/unix/file.c | 10 ++- dlls/ntdll/unix/socket.c | 111 +++++++++++++++++++++------------ dlls/ntdll/unix/unix_private.h | 2 + 3 files changed, 81 insertions(+), 42 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index f57532f55bf..738367dbb57 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4768,7 +4768,7 @@ static BOOL async_write_proc( void *user, ULONG_PTR *info, NTSTATUS *status ) &needs_close, &type, NULL ))) break;
- if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET)) + if (!fileio->count && type == FD_TYPE_MAILSLOT) result = send( fd, fileio->buffer, 0, 0 ); else result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already ); @@ -5498,11 +5498,17 @@ NTSTATUS WINAPI NtWriteFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, v goto done; } } + else if (type == FD_TYPE_SOCKET) + { + status = sock_write( handle, unix_handle, event, apc, apc_user, io, buffer, length ); + if (needs_close) close( unix_handle ); + return status; + }
for (;;) { /* zero-length writes on sockets may not work with plain write(2) */ - if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET)) + if (!length && type == FD_TYPE_MAILSLOT) result = send( unix_handle, buffer, 0, 0 ); else result = write( unix_handle, (const char *)buffer + total, length - total ); diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 6abee680ee5..ef3c8494c3d 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -895,49 +895,13 @@ static BOOL async_send_proc( void *user, ULONG_PTR *info, NTSTATUS *status ) }
static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, - IO_STATUS_BLOCK *io, int fd, const void *buffers_ptr, unsigned int count, - const struct WS_sockaddr *addr, unsigned int addr_len, int unix_flags, int force_async ) + IO_STATUS_BLOCK *io, int fd, struct async_send_ioctl *async, int force_async ) { - struct async_send_ioctl *async; + BOOL nonblocking, alerted; ULONG_PTR information; HANDLE wait_handle; - DWORD async_size; NTSTATUS status; - unsigned int i; ULONG options; - BOOL nonblocking, alerted; - - async_size = offsetof( struct async_send_ioctl, iov[count] ); - - if (!(async = (struct async_send_ioctl *)alloc_fileio( async_size, async_send_proc, handle ))) - return STATUS_NO_MEMORY; - - async->count = count; - if (in_wow64_call()) - { - const struct afd_wsabuf_32 *buffers = buffers_ptr; - - for (i = 0; i < count; ++i) - { - async->iov[i].iov_base = ULongToPtr( buffers[i].buf ); - async->iov[i].iov_len = buffers[i].len; - } - } - else - { - const WSABUF *buffers = buffers_ptr; - - for (i = 0; i < count; ++i) - { - async->iov[i].iov_base = buffers[i].buf; - async->iov[i].iov_len = buffers[i].len; - } - } - async->unix_flags = unix_flags; - async->addr = addr; - async->addr_len = addr_len; - async->iov_cursor = 0; - async->sent_len = 0;
SERVER_START_REQ( send_socket ) { @@ -982,6 +946,72 @@ static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi return status; }
+static NTSTATUS sock_ioctl_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, + IO_STATUS_BLOCK *io, int fd, const void *buffers_ptr, unsigned int count, + const struct WS_sockaddr *addr, unsigned int addr_len, int unix_flags, int force_async ) +{ + struct async_send_ioctl *async; + DWORD async_size; + unsigned int i; + + async_size = offsetof( struct async_send_ioctl, iov[count] ); + + if (!(async = (struct async_send_ioctl *)alloc_fileio( async_size, async_send_proc, handle ))) + return STATUS_NO_MEMORY; + + async->count = count; + if (in_wow64_call()) + { + const struct afd_wsabuf_32 *buffers = buffers_ptr; + + for (i = 0; i < count; ++i) + { + async->iov[i].iov_base = ULongToPtr( buffers[i].buf ); + async->iov[i].iov_len = buffers[i].len; + } + } + else + { + const WSABUF *buffers = buffers_ptr; + + for (i = 0; i < count; ++i) + { + async->iov[i].iov_base = buffers[i].buf; + async->iov[i].iov_len = buffers[i].len; + } + } + async->unix_flags = unix_flags; + async->addr = addr; + async->addr_len = addr_len; + async->iov_cursor = 0; + async->sent_len = 0; + + return sock_send( handle, event, apc, apc_user, io, fd, async, force_async ); +} + + +NTSTATUS sock_write( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE apc, + void *apc_user, IO_STATUS_BLOCK *io, const void *buffer, ULONG length ) +{ + static const DWORD async_size = offsetof( struct async_send_ioctl, iov[1] ); + struct async_send_ioctl *async; + + if (!(async = (struct async_send_ioctl *)alloc_fileio( async_size, async_recv_proc, handle ))) + return STATUS_NO_MEMORY; + + async->count = 1; + async->iov[0].iov_base = (void *)buffer; + async->iov[0].iov_len = length; + async->unix_flags = 0; + async->addr = NULL; + async->addr_len = 0; + async->iov_cursor = 0; + async->sent_len = 0; + + return sock_send( handle, event, apc, apc_user, io, fd, async, 1 ); +} + + static ssize_t do_send( int fd, const void *buffer, size_t len, int flags ) { ssize_t ret; @@ -1420,8 +1450,9 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc WARN( "ignoring MSG_PARTIAL\n" ); if (params->ws_flags & ~(WS_MSG_OOB | WS_MSG_PARTIAL)) FIXME( "unknown flags %#x\n", params->ws_flags ); - status = sock_send( handle, event, apc, apc_user, io, fd, u64_to_user_ptr( params->buffers_ptr ), params->count, - u64_to_user_ptr( params->addr_ptr ), params->addr_len, unix_flags, params->force_async ); + status = sock_ioctl_send( handle, event, apc, apc_user, io, fd, u64_to_user_ptr( params->buffers_ptr ), + params->count, u64_to_user_ptr( params->addr_ptr ), params->addr_len, + 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 8d305bdada6..47f0f9c56a9 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -258,6 +258,8 @@ extern NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, vo 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 sock_write( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, + IO_STATUS_BLOCK *io, const 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;
From: Zebediah Figura zfigura@codeweavers.com
--- server/sock.c | 47 +---------------------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-)
diff --git a/server/sock.c b/server/sock.c index caa68dd213b..9f872c65637 100644 --- a/server/sock.c +++ b/server/sock.c @@ -237,7 +237,6 @@ static void sock_poll_event( struct fd *fd, int event ); static enum server_fd_type sock_get_fd_type( struct fd *fd ); static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ); static void sock_cancel_async( struct fd *fd, struct async *async ); -static void sock_queue_async( struct fd *fd, struct async *async, int type, int count ); static void sock_reselect_async( struct fd *fd, struct async_queue *queue );
static int accept_into_socket( struct sock *sock, struct sock *acceptsock ); @@ -283,7 +282,7 @@ static const struct fd_ops sock_fd_ops = no_fd_get_volume_info, /* get_volume_info */ sock_ioctl, /* ioctl */ sock_cancel_async, /* cancel_async */ - sock_queue_async, /* queue_async */ + no_fd_queue_async, /* queue_async */ sock_reselect_async /* reselect_async */ };
@@ -1376,50 +1375,6 @@ static void sock_cancel_async( struct fd *fd, struct async *async ) async_terminate( async, STATUS_CANCELLED ); }
-static void sock_queue_async( struct fd *fd, struct async *async, int type, int count ) -{ - struct sock *sock = get_fd_user( fd ); - struct async_queue *queue; - - assert( sock->obj.ops == &sock_ops ); - - switch (type) - { - case ASYNC_TYPE_READ: - if (sock->rd_shutdown) - { - set_error( STATUS_PIPE_DISCONNECTED ); - return; - } - queue = &sock->read_q; - break; - - case ASYNC_TYPE_WRITE: - if (sock->wr_shutdown) - { - set_error( STATUS_PIPE_DISCONNECTED ); - return; - } - queue = &sock->write_q; - break; - - default: - set_error( STATUS_INVALID_PARAMETER ); - return; - } - - if (sock->state != SOCK_CONNECTED) - { - set_error( STATUS_PIPE_DISCONNECTED ); - return; - } - - queue_async( queue, async ); - sock_reselect( sock ); - - set_error( STATUS_PENDING ); -} - static void sock_reselect_async( struct fd *fd, struct async_queue *queue ) { struct sock *sock = get_fd_user( fd );