Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/file.c | 2 +- dlls/ws2_32/tests/afd.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index e459087af76..51c92df57e3 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -5735,7 +5735,7 @@ NTSTATUS WINAPI NtDeviceIoControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUT return server_ioctl_file( handle, event, apc, apc_context, io, code, in_buffer, in_size, out_buffer, out_size );
- if (status != STATUS_PENDING) io->u.Status = status; + if (status != STATUS_PENDING && !NT_ERROR(status)) io->u.Status = status; return status; }
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 9e888f1fcb9..17126fbdf7e 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -1201,7 +1201,7 @@ static void test_recv(void) memset(&io, 0, sizeof(io)); ret = NtDeviceIoControlFile((HANDLE)listener, event, NULL, NULL, &io, IOCTL_AFD_RECV, NULL, 0, NULL, 0); todo_wine ok(ret == STATUS_INVALID_CONNECTION, "got %#x\n", ret); - todo_wine ok(!io.Status, "got status %#x\n", io.Status); + ok(!io.Status, "got status %#x\n", io.Status); ok(!io.Information, "got information %#Ix\n", io.Information);
client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -1213,7 +1213,7 @@ static void test_recv(void) memset(&io, 0, sizeof(io)); ret = NtDeviceIoControlFile((HANDLE)client, event, NULL, NULL, &io, IOCTL_AFD_RECV, NULL, 0, NULL, 0); ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); - todo_wine ok(!io.Status, "got status %#x\n", io.Status); + ok(!io.Status, "got status %#x\n", io.Status); ok(!io.Information, "got information %#Ix\n", io.Information);
wsabufs[0].len = sizeof(buffer); @@ -1301,7 +1301,7 @@ static void test_recv(void) ret = NtDeviceIoControlFile((HANDLE)client, event, NULL, NULL, &io, IOCTL_AFD_RECV, ¶ms, sizeof(params), NULL, 0); ok(ret == STATUS_DEVICE_NOT_READY, "got %#x\n", ret); - todo_wine ok(!io.Status, "got status %#x\n", io.Status); + ok(!io.Status, "got status %#x\n", io.Status); ok(!io.Information, "got information %#Ix\n", io.Information);
ret = send(server, "data", 5, 0); @@ -1368,7 +1368,7 @@ static void test_recv(void) ret = NtDeviceIoControlFile((HANDLE)client, event, NULL, NULL, &io, IOCTL_AFD_RECV, ¶ms, sizeof(params), NULL, 0); ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); - todo_wine ok(io.Status == 0xdeadbeef, "got %#x\n", io.Status); + ok(io.Status == 0xdeadbeef, "got %#x\n", io.Status);
params.msg_flags = AFD_MSG_OOB | AFD_MSG_NOT_OOB;
@@ -1376,7 +1376,7 @@ static void test_recv(void) ret = NtDeviceIoControlFile((HANDLE)client, event, NULL, NULL, &io, IOCTL_AFD_RECV, ¶ms, sizeof(params), NULL, 0); ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); - todo_wine ok(io.Status == 0xdeadbeef, "got %#x\n", io.Status); + ok(io.Status == 0xdeadbeef, "got %#x\n", io.Status);
params.msg_flags = AFD_MSG_OOB;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/wine/afd.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/include/wine/afd.h b/include/wine/afd.h index 3b8bdcb9e5d..1d24c679c75 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -76,6 +76,7 @@ struct afd_bind_params int unknown; struct WS(sockaddr) addr; /* variable size */ }; +C_ASSERT( sizeof(struct afd_bind_params) == 20 );
struct afd_listen_params { @@ -83,6 +84,7 @@ struct afd_listen_params int backlog; int unknown2; }; +C_ASSERT( sizeof(struct afd_listen_params) == 12 );
#define AFD_RECV_FORCE_ASYNC 0x2
@@ -138,6 +140,7 @@ struct afd_get_events_params int flags; NTSTATUS status[13]; }; +C_ASSERT( sizeof(struct afd_get_events_params) == 56 );
#define WINE_AFD_IOC(x) CTL_CODE(FILE_DEVICE_NETWORK, x, METHOD_BUFFERED, FILE_ANY_ACCESS)
@@ -244,12 +247,14 @@ struct afd_create_params int family, type, protocol; unsigned int flags; }; +C_ASSERT( sizeof(struct afd_create_params) == 16 );
struct afd_accept_into_params { ULONG accept_handle; unsigned int recv_len, local_len; }; +C_ASSERT( sizeof(struct afd_accept_into_params) == 12 );
struct afd_connect_params { @@ -258,6 +263,7 @@ struct afd_connect_params /* VARARG(addr, struct WS(sockaddr), addr_len); */ /* VARARG(data, bytes); */ }; +C_ASSERT( sizeof(struct afd_connect_params) == 8 );
struct afd_recvmsg_params { @@ -297,10 +303,12 @@ struct afd_message_select_params unsigned int message; int mask; }; +C_ASSERT( sizeof(struct afd_message_select_params) == 16 );
struct afd_get_info_params { int family, type, protocol; }; +C_ASSERT( sizeof(struct afd_get_info_params) == 12 );
#endif
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/unix_private.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 9b79b712b1e..d9ce8300fa9 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -342,11 +342,19 @@ static inline NTSTATUS wait_async( HANDLE handle, BOOL alertable ) return NtWaitForSingleObject( handle, alertable, NULL ); }
+static inline BOOL in_wow64_call(void) +{ +#ifdef _WIN64 + return !!NtCurrentTeb()->WowTebOffset; +#endif + return FALSE; +} + static inline void set_async_iosb( client_ptr_t iosb, NTSTATUS status, ULONG_PTR info ) { if (!iosb) return; -#ifdef _WIN64 - if (NtCurrentTeb()->WowTebOffset) + + if (in_wow64_call()) { struct iosb32 { @@ -357,7 +365,6 @@ static inline void set_async_iosb( client_ptr_t iosb, NTSTATUS status, ULONG_PTR io->Information = info; } else -#endif { IO_STATUS_BLOCK *io = wine_server_get_ptr( iosb ); #ifdef NONAMELESSUNION @@ -371,12 +378,10 @@ static inline void set_async_iosb( client_ptr_t iosb, NTSTATUS status, ULONG_PTR
static inline client_ptr_t iosb_client_ptr( IO_STATUS_BLOCK *io ) { -#ifdef _WIN64 #ifdef NONAMELESSUNION - if (io && NtCurrentTeb()->WowTebOffset) return wine_server_client_ptr( io->u.Pointer ); + if (io && in_wow64_call()) return wine_server_client_ptr( io->u.Pointer ); #else - if (io && NtCurrentTeb()->WowTebOffset) return wine_server_client_ptr( io->Pointer ); -#endif + if (io && in_wow64_call()) return wine_server_client_ptr( io->Pointer ); #endif return wine_server_client_ptr( io ); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/socket.c | 38 ++++++++++++++++++++++++++++---------- include/wine/afd.h | 6 ++++++ 2 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 59551aa51e8..221e1bf303b 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -595,7 +595,7 @@ 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 WSABUF *buffers, unsigned int count, WSABUF *control, + 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; @@ -614,22 +614,31 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi return STATUS_INVALID_PARAMETER; }
- for (i = 0; i < count; ++i) - { - if (!virtual_check_buffer_for_write( buffers[i].buf, buffers[i].len )) - return STATUS_ACCESS_VIOLATION; - } - async_size = offsetof( struct async_recv_ioctl, iov[count] );
if (!(async = (struct async_recv_ioctl *)alloc_fileio( async_size, async_recv_proc, handle ))) return STATUS_NO_MEMORY;
async->count = count; - for (i = 0; i < count; ++i) + if (in_wow64_call()) { - async->iov[i].iov_base = buffers[i].buf; - async->iov[i].iov_len = buffers[i].len; + 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->control = control; @@ -637,6 +646,15 @@ 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; + } + } + status = try_recv( fd, async, &information );
if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW && status != STATUS_DEVICE_NOT_READY) diff --git a/include/wine/afd.h b/include/wine/afd.h index 1d24c679c75..60dd2806d9d 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -25,6 +25,12 @@ #include <winioctl.h> #include <mswsock.h>
+struct afd_wsabuf_32 +{ + ULONG len; + ULONG buf; +}; + #ifdef USE_WS_PREFIX # define WS(x) WS_##x #else
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/socket.c | 50 ++++++++++++++++++++++++++++------------ include/wine/afd.h | 8 +++++++ 2 files changed, 43 insertions(+), 15 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 221e1bf303b..9cc9352403d 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1278,7 +1278,7 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
case IOCTL_AFD_RECV: { - const struct afd_recv_params *params = in_buffer; + struct afd_recv_params params; int unix_flags = 0;
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) @@ -1286,33 +1286,53 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
if (out_size) FIXME( "unexpected output size %u\n", out_size );
- if (in_size < sizeof(struct afd_recv_params)) + if (in_wow64_call()) { - status = STATUS_INVALID_PARAMETER; - break; + const struct afd_recv_params_32 *params32 = in_buffer; + + if (in_size < sizeof(struct afd_recv_params_32)) + { + status = STATUS_INVALID_PARAMETER; + break; + } + + params.recv_flags = params32->recv_flags; + params.msg_flags = params32->msg_flags; + params.buffers = ULongToPtr( params32->buffers ); + params.count = params32->count; + } + else + { + if (in_size < sizeof(struct afd_recv_params)) + { + status = STATUS_INVALID_PARAMETER; + break; + } + + memcpy( ¶ms, in_buffer, sizeof(params) ); }
- if ((params->msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == 0 || - (params->msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) + if ((params.msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == 0 || + (params.msg_flags & (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) == (AFD_MSG_NOT_OOB | AFD_MSG_OOB)) { status = STATUS_INVALID_PARAMETER; break; }
- if (params->msg_flags & ~(AFD_MSG_NOT_OOB | AFD_MSG_OOB | AFD_MSG_PEEK | AFD_MSG_WAITALL)) - FIXME( "unknown msg_flags %#x\n", params->msg_flags ); - if (params->recv_flags & ~AFD_RECV_FORCE_ASYNC) - FIXME( "unknown recv_flags %#x\n", params->recv_flags ); + if (params.msg_flags & ~(AFD_MSG_NOT_OOB | AFD_MSG_OOB | AFD_MSG_PEEK | AFD_MSG_WAITALL)) + FIXME( "unknown msg_flags %#x\n", params.msg_flags ); + if (params.recv_flags & ~AFD_RECV_FORCE_ASYNC) + FIXME( "unknown recv_flags %#x\n", params.recv_flags );
- if (params->msg_flags & AFD_MSG_OOB) + if (params.msg_flags & AFD_MSG_OOB) unix_flags |= MSG_OOB; - if (params->msg_flags & AFD_MSG_PEEK) + if (params.msg_flags & AFD_MSG_PEEK) unix_flags |= MSG_PEEK; - if (params->msg_flags & AFD_MSG_WAITALL) + 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_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) ); break; }
diff --git a/include/wine/afd.h b/include/wine/afd.h index 60dd2806d9d..9d1af44f117 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -107,6 +107,14 @@ struct afd_recv_params int msg_flags; };
+struct afd_recv_params_32 +{ + ULONG buffers; + unsigned int count; + int recv_flags; + int msg_flags; +}; + #include <pshpack4.h> struct afd_poll_params {
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/socket.c | 99 +++++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 12 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 9cc9352403d..b988253c67a 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -107,7 +107,7 @@ union unix_sockaddr struct async_recv_ioctl { struct async_fileio io; - WSABUF *control; + void *control; struct WS_sockaddr *addr; int *addr_len; DWORD *ret_flags; @@ -504,8 +504,62 @@ error: control->len = 0; return 0; } +#else +static int convert_control_headers(struct msghdr *hdr, WSABUF *control) +{ + ERR( "Message control headers cannot be properly supported on this system.\n" ); + control->len = 0; + return 0; +} #endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */
+struct cmsghdr_32 +{ + ULONG cmsg_len; + INT cmsg_level; + INT cmsg_type; + /* UCHAR cmsg_data[]; */ +}; + +static size_t cmsg_align_32( size_t len ) +{ + return (len + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1); +} + +/* we assume that cmsg_data does not require translation, which is currently + * true for all messages */ +static int wow64_translate_control( const WSABUF *control64, struct afd_wsabuf_32 *control32 ) +{ + char *const buf32 = ULongToPtr(control32->buf); + const ULONG max_len = control32->len; + const char *ptr64 = control64->buf; + char *ptr32 = buf32; + + while (ptr64 < control64->buf + control64->len) + { + struct cmsghdr_32 *cmsg32 = (struct cmsghdr_32 *)ptr32; + const WSACMSGHDR *cmsg64 = (const WSACMSGHDR *)ptr64; + + if (ptr32 + sizeof(*cmsg32) + cmsg_align_32( cmsg64->cmsg_len ) > buf32 + max_len) + { + control32->len = 0; + return 0; + } + + cmsg32->cmsg_len = cmsg64->cmsg_len - sizeof(*cmsg64) + sizeof(*cmsg32); + cmsg32->cmsg_level = cmsg64->cmsg_level; + cmsg32->cmsg_type = cmsg64->cmsg_type; + memcpy( cmsg32 + 1, cmsg64 + 1, cmsg64->cmsg_len ); + + ptr64 += WSA_CMSG_ALIGN( cmsg64->cmsg_len ); + ptr32 += cmsg_align_32( cmsg32->cmsg_len ); + } + + control32->len = ptr32 - buf32; + FIXME("-> %d\n", control32->len); + return 1; +} + static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *size ) { #ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS @@ -543,20 +597,41 @@ static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *siz
status = (hdr.msg_flags & MSG_TRUNC) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
-#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS if (async->control) { - ERR( "Message control headers cannot be properly supported on this system.\n" ); - async->control->len = 0; - } -#else - if (async->control && !convert_control_headers( &hdr, async->control )) - { - WARN( "Application passed insufficient room for control headers.\n" ); - *async->ret_flags |= WS_MSG_CTRUNC; - status = STATUS_BUFFER_OVERFLOW; + if (in_wow64_call()) + { + char control_buffer64[512]; + WSABUF wsabuf; + + wsabuf.len = sizeof(control_buffer64); + wsabuf.buf = control_buffer64; + if (convert_control_headers( &hdr, &wsabuf )) + { + if (!wow64_translate_control( &wsabuf, async->control )) + { + WARN( "Application passed insufficient room for control headers.\n" ); + *async->ret_flags |= WS_MSG_CTRUNC; + status = STATUS_BUFFER_OVERFLOW; + } + } + else + { + FIXME( "control buffer is too small\n" ); + *async->ret_flags |= WS_MSG_CTRUNC; + status = STATUS_BUFFER_OVERFLOW; + } + } + else + { + if (!convert_control_headers( &hdr, async->control )) + { + WARN( "Application passed insufficient room for control headers.\n" ); + *async->ret_flags |= WS_MSG_CTRUNC; + status = STATUS_BUFFER_OVERFLOW; + } + } } -#endif
/* If this socket is connected, Linux doesn't give us msg_name and * msg_namelen from recvmsg, but it does set msg_namelen to zero.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/socket.c | 13 ++++++++----- dlls/ws2_32/socket.c | 10 +++++----- include/wine/afd.h | 11 ++++++----- 3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index b988253c67a..25b1280ac85 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1414,6 +1414,7 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc case IOCTL_AFD_WINE_RECVMSG: { struct afd_recvmsg_params *params = in_buffer; + unsigned int *ws_flags = u64_to_user_ptr(params->ws_flags_ptr); int unix_flags = 0;
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) @@ -1425,15 +1426,17 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc break; }
- if (*params->ws_flags & WS_MSG_OOB) + if (*ws_flags & WS_MSG_OOB) unix_flags |= MSG_OOB; - if (*params->ws_flags & WS_MSG_PEEK) + if (*ws_flags & WS_MSG_PEEK) unix_flags |= MSG_PEEK; - if (*params->ws_flags & WS_MSG_WAITALL) + if (*ws_flags & WS_MSG_WAITALL) FIXME( "MSG_WAITALL is not supported\n" );
- status = sock_recv( handle, event, apc, apc_user, io, fd, params->buffers, params->count, params->control, - params->addr, params->addr_len, params->ws_flags, unix_flags, params->force_async ); + 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 ); break; }
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 2db441bee3c..89aded92098 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -923,13 +923,13 @@ static int WS2_recv_base( SOCKET s, WSABUF *buffers, DWORD buffer_count, DWORD * apc = socket_apc; }
- params.control = control; - params.addr = addr; - params.addr_len = addr_len; - params.ws_flags = flags; + params.control_ptr = u64_from_user_ptr(control); + params.addr_ptr = u64_from_user_ptr(addr); + params.addr_len_ptr = u64_from_user_ptr(addr_len); + params.ws_flags_ptr = u64_from_user_ptr(flags); params.force_async = !!overlapped; params.count = buffer_count; - params.buffers = buffers; + params.buffers_ptr = u64_from_user_ptr(buffers);
status = NtDeviceIoControlFile( (HANDLE)s, event, apc, cvalue, piosb, IOCTL_AFD_WINE_RECVMSG, ¶ms, sizeof(params), NULL, 0 ); diff --git a/include/wine/afd.h b/include/wine/afd.h index 9d1af44f117..7db429c2b79 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -281,14 +281,15 @@ C_ASSERT( sizeof(struct afd_connect_params) == 8 );
struct afd_recvmsg_params { - WSABUF *control; - struct WS(sockaddr) *addr; - int *addr_len; - unsigned int *ws_flags; + ULONGLONG control_ptr; /* WSABUF */ + ULONGLONG addr_ptr; /* WS(sockaddr) */ + ULONGLONG addr_len_ptr; /* int */ + ULONGLONG ws_flags_ptr; /* unsigned int */ int force_async; unsigned int count; - WSABUF *buffers; + ULONGLONG buffers_ptr; /* WSABUF[] */ }; +C_ASSERT( sizeof(struct afd_recvmsg_params) == 48 );
struct afd_sendmsg_params {
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=103810
Your paranoid android.
=== debiant2 (build log) ===
/home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ws2_32/socket.c:926: undefined reference to `u64_from_user_ptr' /usr/bin/i686-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ws2_32/socket.c:927: undefined reference to `u64_from_user_ptr' /usr/bin/i686-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ws2_32/socket.c:928: undefined reference to `u64_from_user_ptr' /usr/bin/i686-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ws2_32/socket.c:929: undefined reference to `u64_from_user_ptr' /usr/bin/i686-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ws2_32/socket.c:932: undefined reference to `u64_from_user_ptr' /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1417: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1438: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1438: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1437: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1436: undefined reference to `u64_to_user_ptr' collect2: error: ld returned 1 exit status collect2: error: ld returned 1 exit status Task: The win32 Wine build failed
=== debiant2 (build log) ===
/home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1417: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1438: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1438: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1437: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1436: undefined reference to `u64_to_user_ptr' collect2: error: ld returned 1 exit status Task: The wow64 Wine build failed
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/socket.c | 27 +++++++++++++++++++++------ dlls/ws2_32/socket.c | 4 ++-- include/wine/afd.h | 11 +++++++++-- 3 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 25b1280ac85..676864744a3 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1001,7 +1001,7 @@ 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 WSABUF *buffers, unsigned int count, + 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; @@ -1017,10 +1017,25 @@ static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi return STATUS_NO_MEMORY;
async->count = count; - for (i = 0; i < count; ++i) + if (in_wow64_call()) { - async->iov[i].iov_base = buffers[i].buf; - async->iov[i].iov_len = buffers[i].len; + 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; @@ -1461,8 +1476,8 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc 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, params->buffers, params->count, - params->addr, params->addr_len, unix_flags, params->force_async ); + 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 ); break; }
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 89aded92098..fb8ae1b2cce 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -990,12 +990,12 @@ static int WS2_sendto( SOCKET s, WSABUF *buffers, DWORD buffer_count, DWORD *ret apc = socket_apc; }
- params.addr = addr; + params.addr_ptr = u64_from_user_ptr( addr ); params.addr_len = addr_len; params.ws_flags = flags; params.force_async = !!overlapped; params.count = buffer_count; - params.buffers = buffers; + params.buffers_ptr = u64_from_user_ptr( buffers );
status = NtDeviceIoControlFile( (HANDLE)s, event, apc, cvalue, piosb, IOCTL_AFD_WINE_SENDMSG, ¶ms, sizeof(params), NULL, 0 ); diff --git a/include/wine/afd.h b/include/wine/afd.h index 7db429c2b79..ee67e255dd0 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -256,6 +256,12 @@ C_ASSERT( sizeof(struct afd_get_events_params) == 56 ); #define IOCTL_AFD_WINE_GET_IP_RECVTOS WINE_AFD_IOC(295) #define IOCTL_AFD_WINE_SET_IP_RECVTOS WINE_AFD_IOC(296)
+struct afd_iovec +{ + ULONGLONG ptr; + ULONG len; +}; + struct afd_create_params { int family, type, protocol; @@ -293,13 +299,14 @@ C_ASSERT( sizeof(struct afd_recvmsg_params) == 48 );
struct afd_sendmsg_params { - const struct WS(sockaddr) *addr; + ULONGLONG addr_ptr; /* const struct WS(sockaddr) */ unsigned int addr_len; unsigned int ws_flags; int force_async; unsigned int count; - const WSABUF *buffers; + ULONGLONG buffers_ptr; /* const WSABUF[] */ }; +C_ASSERT( sizeof(struct afd_sendmsg_params) == 32 );
struct afd_transmit_params {
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=103811
Your paranoid android.
=== debiant2 (build log) ===
/home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1432: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1453: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1453: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1452: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/ntdll/unix/socket.c:1451: undefined reference to `u64_to_user_ptr' collect2: error: ld returned 1 exit status Task: The win32 Wine build failed
=== debiant2 (build log) ===
/home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1432: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1453: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1453: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1452: undefined reference to `u64_to_user_ptr' /usr/bin/ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ntdll/unix/socket.c:1451: undefined reference to `u64_to_user_ptr' collect2: error: ld returned 1 exit status /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ws2_32/socket.c:926: undefined reference to `u64_from_user_ptr' /usr/bin/x86_64-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ws2_32/socket.c:927: undefined reference to `u64_from_user_ptr' /usr/bin/x86_64-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ws2_32/socket.c:928: undefined reference to `u64_from_user_ptr' /usr/bin/x86_64-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ws2_32/socket.c:929: undefined reference to `u64_from_user_ptr' /usr/bin/x86_64-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/ws2_32/socket.c:932: undefined reference to `u64_from_user_ptr' collect2: error: ld returned 1 exit status Task: The wow64 Wine build failed
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/socket.c | 32 ++++++++++++++++++++------------ dlls/ws2_32/socket.c | 12 ++++++++++-- include/wine/afd.h | 10 +++++++--- 3 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 676864744a3..20368ad6415 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -91,6 +91,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
+#define u64_to_user_ptr(u) ((void *)(uintptr_t)(u)) + union unix_sockaddr { struct sockaddr addr; @@ -141,7 +143,10 @@ struct async_transmit_ioctl unsigned int tail_cursor; /* amount of tail data already sent */ unsigned int file_len; /* total file length to send */ DWORD flags; - TRANSMIT_FILE_BUFFERS buffers; + const char *head; + const char *tail; + unsigned int head_len; + unsigned int tail_len; LARGE_INTEGER offset; };
@@ -1088,11 +1093,11 @@ static NTSTATUS try_transmit( int sock_fd, int file_fd, struct async_transmit_io { ssize_t ret;
- while (async->head_cursor < async->buffers.HeadLength) + while (async->head_cursor < async->head_len) { - TRACE( "sending %u bytes of header data\n", async->buffers.HeadLength - async->head_cursor ); - ret = do_send( sock_fd, (char *)async->buffers.Head + async->head_cursor, - async->buffers.HeadLength - async->head_cursor, 0 ); + TRACE( "sending %u bytes of header data\n", async->head_len - async->head_cursor ); + ret = do_send( sock_fd, async->head + async->head_cursor, + async->head_len - async->head_cursor, 0 ); if (ret < 0) return sock_errno_to_status( errno ); TRACE( "send returned %zd\n", ret ); async->head_cursor += ret; @@ -1137,11 +1142,11 @@ static NTSTATUS try_transmit( int sock_fd, int file_fd, struct async_transmit_io return STATUS_DEVICE_NOT_READY; /* still more data to send */ }
- while (async->tail_cursor < async->buffers.TailLength) + while (async->tail_cursor < async->tail_len) { - TRACE( "sending %u bytes of tail data\n", async->buffers.TailLength - async->tail_cursor ); - ret = do_send( sock_fd, (char *)async->buffers.Tail + async->tail_cursor, - async->buffers.TailLength - async->tail_cursor, 0 ); + TRACE( "sending %u bytes of tail data\n", async->tail_len - async->tail_cursor ); + ret = do_send( sock_fd, async->tail + async->tail_cursor, + async->tail_len - async->tail_cursor, 0 ); if (ret < 0) return sock_errno_to_status( errno ); TRACE( "send returned %zd\n", ret ); async->tail_cursor += ret; @@ -1200,7 +1205,7 @@ static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
if (params->file) { - if ((status = server_get_unix_fd( params->file, 0, &file_fd, &file_needs_close, &file_type, NULL ))) + if ((status = server_get_unix_fd( ULongToHandle( params->file ), 0, &file_fd, &file_needs_close, &file_type, NULL ))) return status; if (file_needs_close) close( file_fd );
@@ -1214,7 +1219,7 @@ static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, if (!(async = (struct async_transmit_ioctl *)alloc_fileio( sizeof(*async), async_transmit_proc, handle ))) return STATUS_NO_MEMORY;
- async->file = params->file; + async->file = ULongToHandle( params->file ); async->buffer_size = params->buffer_size ? params->buffer_size : 65536; if (!(async->buffer = malloc( async->buffer_size ))) { @@ -1228,7 +1233,10 @@ static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, async->tail_cursor = 0; async->file_len = params->file_len; async->flags = params->flags; - async->buffers = params->buffers; + async->head = u64_to_user_ptr(params->head_ptr); + async->head_len = params->head_len; + async->tail = u64_to_user_ptr(params->tail_ptr); + async->tail_len = params->tail_len; async->offset = params->offset;
SERVER_START_REQ( send_socket ) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index fb8ae1b2cce..3a5b77e32e6 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -35,6 +35,8 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
#define TIMEOUT_INFINITE _I64_MAX
+#define u64_from_user_ptr(ptr) ((ULONGLONG)(uintptr_t)(ptr)) + static const WSAPROTOCOL_INFOW supported_protocols[] = { { @@ -842,10 +844,16 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE file, DWORD file_len, DWOR params.offset.QuadPart = FILE_USE_FILE_POINTER_POSITION; }
- params.file = file; + params.file = HandleToULong( file ); params.file_len = file_len; params.buffer_size = buffer_size; - if (buffers) params.buffers = *buffers; + if (buffers) + { + params.head_ptr = u64_from_user_ptr(buffers->Head); + params.head_len = buffers->HeadLength; + params.tail_ptr = u64_from_user_ptr(buffers->Tail); + params.tail_len = buffers->TailLength; + } params.flags = flags;
status = NtDeviceIoControlFile( (HANDLE)s, event, NULL, cvalue, piosb, diff --git a/include/wine/afd.h b/include/wine/afd.h index ee67e255dd0..97128c67ca6 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -310,13 +310,17 @@ C_ASSERT( sizeof(struct afd_sendmsg_params) == 32 );
struct afd_transmit_params { - HANDLE file; + LARGE_INTEGER offset; + ULONGLONG head_ptr; + ULONGLONG tail_ptr; + DWORD head_len; + DWORD tail_len; + ULONG file; DWORD file_len; DWORD buffer_size; - LARGE_INTEGER offset; - TRANSMIT_FILE_BUFFERS buffers; DWORD flags; }; +C_ASSERT( sizeof(struct afd_transmit_params) == 48 );
struct afd_message_select_params {
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=103812
Your paranoid android.
=== debiant2 (32 bit report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit Chinese:China report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit WoW report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (64 bit WoW report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/sock.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 8521e34ed7e..d674d2a8f84 100644 --- a/server/sock.c +++ b/server/sock.c @@ -128,7 +128,7 @@ struct poll_req struct { struct sock *sock; - int flags; + int mask; } sockets[1]; };
@@ -862,13 +862,13 @@ static void complete_async_polls( struct sock *sock, int event, int error ) for (i = 0; i < req->count; ++i) { if (req->sockets[i].sock != sock) continue; - if (!(req->sockets[i].flags & flags)) continue; + if (!(req->sockets[i].mask & flags)) continue;
if (debug_level) fprintf( stderr, "completing poll for socket %p, wanted %#x got %#x\n", - sock, req->sockets[i].flags, flags ); + sock, req->sockets[i].mask, flags );
- req->output[i].flags = req->sockets[i].flags & flags; + req->output[i].flags = req->sockets[i].mask & flags; req->output[i].status = sock_get_ntstatus( error );
complete_async_poll( req, STATUS_SUCCESS ); @@ -1220,7 +1220,7 @@ static int sock_get_poll_events( struct fd *fd ) { if (req->sockets[i].sock != sock) continue;
- ev |= poll_flags_from_afd( sock, req->sockets[i].flags ); + ev |= poll_flags_from_afd( sock, req->sockets[i].mask ); } }
@@ -2936,7 +2936,7 @@ static void poll_socket( struct sock *poll_sock, struct async *async, int exclus free( output ); return; } - req->sockets[i].flags = input[i].flags; + req->sockets[i].mask = input[i].flags; }
req->exclusive = exclusive; @@ -2954,7 +2954,7 @@ static void poll_socket( struct sock *poll_sock, struct async *async, int exclus for (i = 0; i < count; ++i) { struct sock *sock = req->sockets[i].sock; - int mask = req->sockets[i].flags; + int mask = req->sockets[i].mask; int flags = poll_single_socket( sock, mask );
if (flags)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/socket.c | 153 +------------------------------- dlls/ws2_32/tests/afd.c | 2 +- include/wine/afd.h | 30 ++++++- server/protocol.def | 25 ------ server/sock.c | 182 ++++++++++++++++++++++++++++----------- server/trace.c | 32 ------- 6 files changed, 167 insertions(+), 257 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 20368ad6415..92374e39db7 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -770,151 +770,6 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi }
-struct async_poll_ioctl -{ - struct async_fileio io; - unsigned int count; - struct afd_poll_params *input, *output; - struct poll_socket_output sockets[1]; -}; - -static ULONG_PTR fill_poll_output( struct async_poll_ioctl *async, NTSTATUS status ) -{ - struct afd_poll_params *input = async->input, *output = async->output; - unsigned int i, count = 0; - - memcpy( output, input, offsetof( struct afd_poll_params, sockets[0] ) ); - - if (!status) - { - for (i = 0; i < async->count; ++i) - { - if (async->sockets[i].flags) - { - output->sockets[count].socket = input->sockets[i].socket; - output->sockets[count].flags = async->sockets[i].flags; - output->sockets[count].status = async->sockets[i].status; - ++count; - } - } - } - output->count = count; - return offsetof( struct afd_poll_params, sockets[count] ); -} - -static BOOL async_poll_proc( void *user, ULONG_PTR *info, NTSTATUS *status ) -{ - struct async_poll_ioctl *async = user; - - if (*status == STATUS_ALERTED) - { - SERVER_START_REQ( get_async_result ) - { - req->user_arg = wine_server_client_ptr( async ); - wine_server_set_reply( req, async->sockets, async->count * sizeof(async->sockets[0]) ); - *status = wine_server_call( req ); - } - SERVER_END_REQ; - - *info = fill_poll_output( async, *status ); - } - - free( async->input ); - release_fileio( &async->io ); - return TRUE; -} - - -/* we could handle this ioctl entirely on the server side, but the differing - * structure size makes it painful */ -static NTSTATUS sock_poll( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, - void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size ) -{ - const struct afd_poll_params *params = in_buffer; - struct poll_socket_input *input; - struct async_poll_ioctl *async; - HANDLE wait_handle; - DWORD async_size; - NTSTATUS status; - unsigned int i; - ULONG options; - - if (in_size < sizeof(*params) || out_size < in_size || !params->count - || in_size < offsetof( struct afd_poll_params, sockets[params->count] )) - return STATUS_INVALID_PARAMETER; - - TRACE( "timeout %s, count %u, exclusive %#x, padding (%#x, %#x, %#x), sockets[0] {%04lx, %#x}\n", - wine_dbgstr_longlong(params->timeout), params->count, params->exclusive, - params->padding[0], params->padding[1], params->padding[2], - params->sockets[0].socket, params->sockets[0].flags ); - - if (params->padding[0]) FIXME( "padding[0] is %#x\n", params->padding[0] ); - if (params->padding[1]) FIXME( "padding[1] is %#x\n", params->padding[1] ); - if (params->padding[2]) FIXME( "padding[2] is %#x\n", params->padding[2] ); - for (i = 0; i < params->count; ++i) - { - if (params->sockets[i].flags & ~0x1ff) - FIXME( "unknown socket flags %#x\n", params->sockets[i].flags ); - } - - if (!(input = malloc( params->count * sizeof(*input) ))) - return STATUS_NO_MEMORY; - - async_size = offsetof( struct async_poll_ioctl, sockets[params->count] ); - - if (!(async = (struct async_poll_ioctl *)alloc_fileio( async_size, async_poll_proc, handle ))) - { - free( input ); - return STATUS_NO_MEMORY; - } - - if (!(async->input = malloc( in_size ))) - { - release_fileio( &async->io ); - free( input ); - return STATUS_NO_MEMORY; - } - memcpy( async->input, in_buffer, in_size ); - - async->count = params->count; - async->output = out_buffer; - - for (i = 0; i < params->count; ++i) - { - input[i].socket = params->sockets[i].socket; - input[i].flags = params->sockets[i].flags; - } - - SERVER_START_REQ( poll_socket ) - { - req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) ); - req->exclusive = !!params->exclusive; - req->timeout = params->timeout; - wine_server_add_data( req, input, params->count * sizeof(*input) ); - wine_server_set_reply( req, async->sockets, params->count * sizeof(async->sockets[0]) ); - status = wine_server_call( req ); - wait_handle = wine_server_ptr_handle( reply->wait ); - options = reply->options; - if (wait_handle && status != STATUS_PENDING) - { - io->Status = status; - io->Information = fill_poll_output( async, status ); - } - } - SERVER_END_REQ; - - free( input ); - - if (status != STATUS_PENDING) - { - free( async->input ); - release_fileio( &async->io ); - } - - if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT) ); - return status; -} - static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) { union unix_sockaddr unix_addr; @@ -1374,6 +1229,10 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc status = STATUS_BAD_DEVICE_TYPE; break;
+ case IOCTL_AFD_POLL: + status = STATUS_BAD_DEVICE_TYPE; + break; + case IOCTL_AFD_RECV: { struct afd_recv_params params; @@ -1516,10 +1375,6 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc break; }
- case IOCTL_AFD_POLL: - status = sock_poll( handle, event, apc, apc_user, io, in_buffer, in_size, out_buffer, out_size ); - break; - case IOCTL_AFD_WINE_FIONREAD: { int value, ret; diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 17126fbdf7e..55029bfd30d 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -688,7 +688,7 @@ static void test_poll(void) ret = NtDeviceIoControlFile((HANDLE)client, event, NULL, NULL, &io, IOCTL_AFD_POLL, in_params, params_size, out_params, params_size); ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret); - todo_wine ok(!io.Status, "got %#x\n", io.Status); + ok(!io.Status, "got %#x\n", io.Status); ok(!io.Information, "got %#Ix\n", io.Information);
/* Test passing the same handle twice. */ diff --git a/include/wine/afd.h b/include/wine/afd.h index 97128c67ca6..efd5787e90a 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -122,13 +122,41 @@ struct afd_poll_params unsigned int count; BOOLEAN exclusive; BOOLEAN padding[3]; - struct + struct afd_poll_socket { SOCKET socket; int flags; NTSTATUS status; } sockets[1]; }; + +struct afd_poll_params_64 +{ + LONGLONG timeout; + unsigned int count; + BOOLEAN exclusive; + BOOLEAN padding[3]; + struct afd_poll_socket_64 + { + ULONGLONG socket; + int flags; + NTSTATUS status; + } sockets[1]; +}; + +struct afd_poll_params_32 +{ + LONGLONG timeout; + unsigned int count; + BOOLEAN exclusive; + BOOLEAN padding[3]; + struct afd_poll_socket_32 + { + ULONG socket; + int flags; + NTSTATUS status; + } sockets[1]; +}; #include <poppack.h>
struct afd_event_select_params diff --git a/server/protocol.def b/server/protocol.def index efe0d22cbc4..db73f0418a9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1443,31 +1443,6 @@ enum server_fd_type @END
-struct poll_socket_input -{ - obj_handle_t socket; /* socket handle */ - int flags; /* events to poll for */ -}; - -struct poll_socket_output -{ - int flags; /* events signaled */ - unsigned int status; /* socket status */ -}; - -/* Perform an async poll on a socket */ -@REQ(poll_socket) - int exclusive; /* is the poll exclusive? */ - async_data_t async; /* async I/O parameters */ - timeout_t timeout; /* timeout */ - VARARG(sockets,poll_socket_input); /* list of sockets to poll */ -@REPLY - obj_handle_t wait; /* handle to wait on for blocking poll */ - unsigned int options; /* file open options */ - VARARG(sockets,poll_socket_output); /* data returned */ -@END - - /* Perform a send on a socket */ @REQ(send_socket) async_data_t async; /* async I/O parameters */ diff --git a/server/sock.c b/server/sock.c index d674d2a8f84..4f728ef74dc 100644 --- a/server/sock.c +++ b/server/sock.c @@ -122,13 +122,16 @@ struct poll_req struct async *async; struct iosb *iosb; struct timeout_user *timeout; + timeout_t orig_timeout; int exclusive; unsigned int count; - struct poll_socket_output *output; struct { struct sock *sock; int mask; + obj_handle_t handle; + int flags; + unsigned int status; } sockets[1]; };
@@ -235,6 +238,8 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock ); static struct sock *accept_socket( struct sock *sock ); static int sock_get_ntstatus( int err ); static unsigned int sock_get_error( int err ); +static void poll_socket( struct sock *poll_sock, struct async *async, int exclusive, timeout_t timeout, + unsigned int count, const struct afd_poll_socket_64 *sockets );
static const struct object_ops sock_ops = { @@ -789,7 +794,6 @@ static void free_poll_req( void *private ) release_object( req->async ); release_object( req->iosb ); list_remove( &req->entry ); - free( req->output ); free( req ); }
@@ -832,8 +836,7 @@ static int get_poll_flags( struct sock *sock, int event )
static void complete_async_poll( struct poll_req *req, unsigned int status ) { - struct poll_socket_output *output = req->output; - unsigned int i; + unsigned int i, signaled_count = 0;;
for (i = 0; i < req->count; ++i) { @@ -843,9 +846,65 @@ static void complete_async_poll( struct poll_req *req, unsigned int status ) sock->main_poll = NULL; }
- /* pass 0 as result; client will set actual result size */ - req->output = NULL; - async_request_complete( req->async, status, 0, req->count * sizeof(*output), output ); + if (!status) + { + for (i = 0; i < req->count; ++i) + { + if (req->sockets[i].flags) + ++signaled_count; + } + } + + if (is_machine_64bit( async_get_thread( req->async )->process->machine )) + { + size_t output_size = offsetof( struct afd_poll_params_64, sockets[signaled_count] ); + struct afd_poll_params_64 *output; + + if (!(output = mem_alloc( output_size ))) + { + async_terminate( req->async, get_error() ); + return; + } + memset( output, 0, output_size ); + output->timeout = req->orig_timeout; + output->exclusive = req->exclusive; + for (i = 0; i < req->count; ++i) + { + if (!req->sockets[i].flags) continue; + output->sockets[output->count].socket = req->sockets[i].handle; + output->sockets[output->count].flags = req->sockets[i].flags; + output->sockets[output->count].status = req->sockets[i].status; + ++output->count; + } + assert( output->count == signaled_count ); + + async_request_complete( req->async, status, output_size, output_size, output ); + } + else + { + size_t output_size = offsetof( struct afd_poll_params_32, sockets[signaled_count] ); + struct afd_poll_params_32 *output; + + if (!(output = mem_alloc( output_size ))) + { + async_terminate( req->async, get_error() ); + return; + } + memset( output, 0, output_size ); + output->timeout = req->orig_timeout; + output->exclusive = req->exclusive; + for (i = 0; i < req->count; ++i) + { + if (!req->sockets[i].flags) continue; + output->sockets[output->count].socket = req->sockets[i].handle; + output->sockets[output->count].flags = req->sockets[i].flags; + output->sockets[output->count].status = req->sockets[i].status; + ++output->count; + } + assert( output->count == signaled_count ); + + async_request_complete( req->async, status, output_size, output_size, output ); + } }
static void complete_async_polls( struct sock *sock, int event, int error ) @@ -868,8 +927,8 @@ static void complete_async_polls( struct sock *sock, int event, int error ) fprintf( stderr, "completing poll for socket %p, wanted %#x got %#x\n", sock, req->sockets[i].mask, flags );
- req->output[i].flags = req->sockets[i].mask & flags; - req->output[i].status = sock_get_ntstatus( error ); + req->sockets[i].flags = req->sockets[i].mask & flags; + req->sockets[i].status = sock_get_ntstatus( error );
complete_async_poll( req, STATUS_SUCCESS ); break; @@ -1353,8 +1412,8 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h if (poll_req->sockets[i].sock == sock) { signaled = TRUE; - poll_req->output[i].flags = AFD_POLL_CLOSE; - poll_req->output[i].status = 0; + poll_req->sockets[i].flags = AFD_POLL_CLOSE; + poll_req->sockets[i].status = 0; } }
@@ -2849,6 +2908,55 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; }
+ case IOCTL_AFD_POLL: + { + if (get_reply_max_size() < get_req_data_size()) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if (is_machine_64bit( current->process->machine )) + { + const struct afd_poll_params_64 *params = get_req_data(); + + if (get_req_data_size() < sizeof(struct afd_poll_params_64) || + get_req_data_size() < offsetof( struct afd_poll_params_64, sockets[params->count] )) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + poll_socket( sock, async, params->exclusive, params->timeout, params->count, params->sockets ); + } + else + { + const struct afd_poll_params_32 *params = get_req_data(); + struct afd_poll_socket_64 *sockets; + unsigned int i; + + if (get_req_data_size() < sizeof(struct afd_poll_params_32) || + get_req_data_size() < offsetof( struct afd_poll_params_32, sockets[params->count] )) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if (!(sockets = mem_alloc( params->count * sizeof(*sockets) ))) return; + for (i = 0; i < params->count; ++i) + { + sockets[i].socket = params->sockets[i].socket; + sockets[i].flags = params->sockets[i].flags; + sockets[i].status = params->sockets[i].status; + } + + poll_socket( sock, async, params->exclusive, params->timeout, params->count, sockets ); + free( sockets ); + } + + return; + } + default: set_error( STATUS_NOT_SUPPORTED ); return; @@ -2899,51 +3007,49 @@ static void handle_exclusive_poll(struct poll_req *req) }
static void poll_socket( struct sock *poll_sock, struct async *async, int exclusive, timeout_t timeout, - unsigned int count, const struct poll_socket_input *input ) + unsigned int count, const struct afd_poll_socket_64 *sockets ) { - struct poll_socket_output *output; BOOL signaled = FALSE; struct poll_req *req; unsigned int i, j;
- if (!(output = mem_alloc( count * sizeof(*output) ))) + if (!count) + { + set_error( STATUS_INVALID_PARAMETER ); return; - memset( output, 0, count * sizeof(*output) ); + }
if (!(req = mem_alloc( offsetof( struct poll_req, sockets[count] ) ))) - { - free( output ); return; - }
req->timeout = NULL; if (timeout && timeout != TIMEOUT_INFINITE && !(req->timeout = add_timeout_user( timeout, async_poll_timeout, req ))) { free( req ); - free( output ); return; } + req->orig_timeout = timeout;
for (i = 0; i < count; ++i) { - req->sockets[i].sock = (struct sock *)get_handle_obj( current->process, input[i].socket, 0, &sock_ops ); + req->sockets[i].sock = (struct sock *)get_handle_obj( current->process, sockets[i].socket, 0, &sock_ops ); if (!req->sockets[i].sock) { for (j = 0; j < i; ++j) release_object( req->sockets[i].sock ); if (req->timeout) remove_timeout_user( req->timeout ); free( req ); - free( output ); return; } - req->sockets[i].mask = input[i].flags; + req->sockets[i].handle = sockets[i].socket; + req->sockets[i].mask = sockets[i].flags; + req->sockets[i].flags = 0; }
req->exclusive = exclusive; req->count = count; req->async = (struct async *)grab_object( async ); req->iosb = async_get_iosb( async ); - req->output = output;
handle_exclusive_poll(req);
@@ -2960,16 +3066,16 @@ static void poll_socket( struct sock *poll_sock, struct async *async, int exclus if (flags) { signaled = TRUE; - output[i].flags = flags; - output[i].status = sock_get_ntstatus( sock_error( sock->fd ) ); + req->sockets[i].flags = flags; + req->sockets[i].status = sock_get_ntstatus( sock_error( sock->fd ) ); }
/* FIXME: do other error conditions deserve a similar treatment? */ if (sock->state != SOCK_CONNECTING && sock->errors[AFD_POLL_BIT_CONNECT_ERR] && (mask & AFD_POLL_CONNECT_ERR)) { signaled = TRUE; - output[i].flags |= AFD_POLL_CONNECT_ERR; - output[i].status = sock_get_ntstatus( sock->errors[AFD_POLL_BIT_CONNECT_ERR] ); + req->sockets[i].flags |= AFD_POLL_CONNECT_ERR; + req->sockets[i].status = sock_get_ntstatus( sock->errors[AFD_POLL_BIT_CONNECT_ERR] ); } }
@@ -3335,28 +3441,6 @@ DECL_HANDLER(recv_socket) release_object( sock ); }
-DECL_HANDLER(poll_socket) -{ - struct sock *sock = (struct sock *)get_handle_obj( current->process, req->async.handle, 0, &sock_ops ); - const struct poll_socket_input *input = get_req_data(); - struct async *async; - unsigned int count; - - if (!sock) return; - - count = get_req_data_size() / sizeof(*input); - - if ((async = create_request_async( sock->fd, get_fd_comp_flags( sock->fd ), &req->async ))) - { - poll_socket( sock, async, req->exclusive, req->timeout, count, input ); - reply->wait = async_handoff( async, NULL, 0 ); - reply->options = get_fd_options( sock->fd ); - release_object( async ); - } - - release_object( sock ); -} - DECL_HANDLER(send_socket) { struct sock *sock = (struct sock *)get_handle_obj( current->process, req->async.handle, 0, &sock_ops ); diff --git a/server/trace.c b/server/trace.c index f7c9cbd975e..3d0f39cb30b 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1394,38 +1394,6 @@ static void dump_varargs_handle_infos( const char *prefix, data_size_t size ) fputc( '}', stderr ); }
-static void dump_varargs_poll_socket_input( const char *prefix, data_size_t size ) -{ - const struct poll_socket_input *input; - - fprintf( stderr, "%s{", prefix ); - while (size >= sizeof(*input)) - { - input = cur_data; - fprintf( stderr, "{socket=%04x,flags=%08x}", input->socket, input->flags ); - size -= sizeof(*input); - remove_data( sizeof(*input) ); - if (size) fputc( ',', stderr ); - } - fputc( '}', stderr ); -} - -static void dump_varargs_poll_socket_output( const char *prefix, data_size_t size ) -{ - const struct poll_socket_output *output; - - fprintf( stderr, "%s{", prefix ); - while (size >= sizeof(*output)) - { - output = cur_data; - fprintf( stderr, "{flags=%08x,status=%s}", output->flags, get_status_name( output->status ) ); - size -= sizeof(*output); - remove_data( sizeof(*output) ); - if (size) fputc( ',', stderr ); - } - fputc( '}', stderr ); -} - typedef void (*dump_func)( const void *req );
/* Everything below this line is generated automatically by tools/make_requests */
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=103804
Your paranoid android.
=== debiant2 (32 bit report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit Arabic:Morocco report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit German report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit French report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit Hebrew:Israel report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit Hindi:India report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit Japanese:Japan report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit Chinese:China report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (32 bit WoW report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0
=== debiant2 (64 bit WoW report) ===
ws2_32: afd.c:691: Test succeeded inside todo block: got 0