From: Zebediah Figura zfigura@codeweavers.com
--- dlls/ntdll/unix/socket.c | 26 ++++++++++++++++++++-- server/protocol.def | 10 +++++++++ server/sock.c | 48 ++++++++++++++++++++++------------------ 3 files changed, 60 insertions(+), 24 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 80105eda0c9..6969f411955 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1552,10 +1552,32 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc }
case IOCTL_AFD_GET_EVENTS: + { + struct afd_get_events_params *params = out_buffer; + HANDLE reset_event = in_buffer; /* sic */ + + TRACE( "reset_event %p\n", reset_event ); if (in_size) FIXME( "unexpected input size %u\n", in_size );
- status = STATUS_BAD_DEVICE_TYPE; - break; + if (out_size < sizeof(*params)) + { + status = STATUS_INVALID_PARAMETER; + break; + } + + SERVER_START_REQ( socket_get_events ) + { + req->handle = wine_server_obj_handle( handle ); + req->event = wine_server_obj_handle( reset_event ); + wine_server_set_reply( req, params->status, sizeof(params->status) ); + if (!(status = wine_server_call( req ))) + params->flags = reply->flags; + } + SERVER_END_REQ; + + complete_async( handle, event, apc, apc_user, io, status, 0 ); + return status; + }
case IOCTL_AFD_POLL: status = STATUS_BAD_DEVICE_TYPE; diff --git a/server/protocol.def b/server/protocol.def index 41c857f5cb9..c8670b1bdc1 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1514,6 +1514,16 @@ enum server_fd_type @END
+/* Get socket event flags */ +@REQ(socket_get_events) + obj_handle_t handle; /* socket handle */ + obj_handle_t event; /* event to reset */ +@REPLY + int flags; /* event mask */ + VARARG(status,uints); /* array of status codes */ +@END + + /* Store ICMP id for ICMP over datagram fixup */ @REQ(socket_send_icmp_id) obj_handle_t handle; /* socket handle */ diff --git a/server/sock.c b/server/sock.c index 2aae9aefbf0..f24abd2ab6f 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2762,28 +2762,6 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) } return;
- case IOCTL_AFD_GET_EVENTS: - { - struct afd_get_events_params params = {0}; - unsigned int i; - - if (get_reply_max_size() < sizeof(params)) - { - set_error( STATUS_INVALID_PARAMETER ); - return; - } - - params.flags = sock->pending_events & sock->mask; - for (i = 0; i < ARRAY_SIZE( params.status ); ++i) - params.status[i] = sock_get_ntstatus( sock->errors[i] ); - - sock->pending_events &= ~sock->mask; - sock_reselect( sock ); - - set_reply_data( ¶ms, sizeof(params) ); - return; - } - case IOCTL_AFD_EVENT_SELECT: { struct event *event = NULL; @@ -3937,6 +3915,32 @@ DECL_HANDLER(send_socket) release_object( sock ); }
+DECL_HANDLER(socket_get_events) +{ + struct sock *sock = (struct sock *)get_handle_obj( current->process, req->handle, 0, &sock_ops ); + unsigned int status[13]; + unsigned int i; + + if (get_reply_max_size() < sizeof(status)) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if (!sock) return; + + reply->flags = sock->pending_events & sock->mask; + for (i = 0; i < ARRAY_SIZE( status ); ++i) + status[i] = sock_get_ntstatus( sock->errors[i] ); + + sock->pending_events &= ~sock->mask; + sock_reselect( sock ); + + set_reply_data( status, sizeof(status) ); + + release_object( sock ); +} + DECL_HANDLER(socket_send_icmp_id) { struct sock *sock = (struct sock *)get_handle_obj( current->process, req->handle, 0, &sock_ops );
From: Zebediah Figura zfigura@codeweavers.com
So that it is done atomically with retrieving events.
Wine-Bug: https://bugs.winehq.org//show_bug.cgi?id=52474 --- dlls/ws2_32/socket.c | 4 +--- dlls/ws2_32/tests/afd.c | 14 ++++++++++++++ server/sock.c | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 5d647d12699..8ef7920e0fc 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3604,10 +3604,8 @@ int WINAPI WSAEnumNetworkEvents( SOCKET s, WSAEVENT event, WSANETWORKEVENTS *ret
TRACE( "socket %#Ix, event %p, events %p\n", s, event, ret_events );
- ResetEvent( event ); - status = NtDeviceIoControlFile( (HANDLE)s, NULL, NULL, NULL, &io, IOCTL_AFD_GET_EVENTS, - NULL, 0, ¶ms, sizeof(params) ); + event, 0, ¶ms, sizeof(params) ); if (!status) { ret_events->lNetworkEvents = afd_poll_flag_to_win32( params.flags ); diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 97139605bf1..b856caee853 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -1969,6 +1969,20 @@ static void test_get_events(void) for (i = 0; i < ARRAY_SIZE(params.status); ++i) ok(!params.status[i], "got status[%u] %#x\n", i, params.status[i]);
+ SetEvent(event); + + memset(¶ms, 0xcc, sizeof(params)); + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_GET_EVENTS, event, 0, ¶ms, sizeof(params)); + ok(!ret, "got %#x\n", ret); + ok(!params.flags, "got flags %#x\n", params.flags); + for (i = 0; i < ARRAY_SIZE(params.status); ++i) + ok(!params.status[i], "got status[%u] %#x\n", i, params.status[i]); + + ret = WaitForSingleObject(event, 0); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + closesocket(client); closesocket(server);
diff --git a/server/sock.c b/server/sock.c index f24abd2ab6f..550fe61e477 100644 --- a/server/sock.c +++ b/server/sock.c @@ -3919,6 +3919,7 @@ DECL_HANDLER(socket_get_events) { struct sock *sock = (struct sock *)get_handle_obj( current->process, req->handle, 0, &sock_ops ); unsigned int status[13]; + struct event *event = NULL; unsigned int i;
if (get_reply_max_size() < sizeof(status)) @@ -3929,6 +3930,15 @@ DECL_HANDLER(socket_get_events)
if (!sock) return;
+ if (req->event) + { + if (!(event = get_event_obj( current->process, req->event, EVENT_MODIFY_STATE ))) + { + release_object( sock ); + return; + } + } + reply->flags = sock->pending_events & sock->mask; for (i = 0; i < ARRAY_SIZE( status ); ++i) status[i] = sock_get_ntstatus( sock->errors[i] ); @@ -3936,6 +3946,12 @@ DECL_HANDLER(socket_get_events) sock->pending_events &= ~sock->mask; sock_reselect( sock );
+ if (event) + { + reset_event( event ); + release_object( event ); + } + set_reply_data( status, sizeof(status) );
release_object( sock );