Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/unix/socket.c | 6 ++++++ include/wine/afd.h | 7 +++++++ server/sock.c | 22 ++++++++++++++++++++++ 3 files changed, 35 insertions(+)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 088f29f85ff..3b8206474f0 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1181,6 +1181,12 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc break; }
+ case IOCTL_AFD_GET_EVENTS: + if (in_size) FIXME( "unexpected input size %u\n", in_size ); + + status = STATUS_BAD_DEVICE_TYPE; + break; + case IOCTL_AFD_RECV: { const struct afd_recv_params *params = in_buffer; diff --git a/include/wine/afd.h b/include/wine/afd.h index 2eb3e6f12a9..46d242c7582 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -36,6 +36,7 @@ #define IOCTL_AFD_RECV CTL_CODE(FILE_DEVICE_BEEP, 0x805, METHOD_NEITHER, FILE_ANY_ACCESS) #define IOCTL_AFD_POLL CTL_CODE(FILE_DEVICE_BEEP, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_EVENT_SELECT CTL_CODE(FILE_DEVICE_BEEP, 0x821, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_AFD_GET_EVENTS CTL_CODE(FILE_DEVICE_BEEP, 0x822, METHOD_NEITHER, FILE_ANY_ACCESS)
enum afd_poll_bit { @@ -125,6 +126,12 @@ struct afd_event_select_params_32 int mask; };
+struct afd_get_events_params +{ + int flags; + NTSTATUS status[13]; +}; + #define IOCTL_AFD_WINE_CREATE CTL_CODE(FILE_DEVICE_NETWORK, 200, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_ACCEPT CTL_CODE(FILE_DEVICE_NETWORK, 201, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_ACCEPT_INTO CTL_CODE(FILE_DEVICE_NETWORK, 202, METHOD_BUFFERED, FILE_ANY_ACCESS) diff --git a/server/sock.c b/server/sock.c index 3556ee21aa3..1d992d8f9e4 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2011,6 +2011,28 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) } return 1;
+ 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 0; + } + + 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 = 0; + sock_reselect( sock ); + + set_reply_data( ¶ms, sizeof(params) ); + return 0; + } + case IOCTL_AFD_EVENT_SELECT: { struct event *event = NULL;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- server/sock.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 1d992d8f9e4..e1b30507514 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1063,11 +1063,20 @@ static int sock_get_poll_events( struct fd *fd ) { if (async_waiting( &sock->read_q )) ev |= POLLIN | POLLPRI; } - else if (!sock->rd_shutdown && (mask & AFD_POLL_READ)) - ev |= POLLIN | POLLPRI; - /* We use POLLIN with 0 bytes recv() as hangup indication for stream sockets. */ - else if (sock->state == SOCK_CONNECTED && (mask & AFD_POLL_HUP) && !(sock->reported_events & AFD_POLL_READ)) - ev |= POLLIN; + else + { + if (!sock->rd_shutdown) + { + if (mask & AFD_POLL_READ) + ev |= POLLIN; + if (mask & AFD_POLL_OOB) + ev |= POLLPRI; + } + + /* We use POLLIN with 0 bytes recv() as hangup indication for stream sockets. */ + if (sock->state == SOCK_CONNECTED && (mask & AFD_POLL_HUP) && !(sock->reported_events & AFD_POLL_READ)) + ev |= POLLIN; + }
if (async_queued( &sock->write_q )) {
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 82 ++++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 22 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 69dec158e5a..fc320ea0247 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3826,6 +3826,33 @@ int WINAPI WS_select(int nfds, WS_fd_set *ws_readfds, return ret; }
+ +static unsigned int afd_poll_flag_to_win32( unsigned int flags ) +{ + static const unsigned int map[] = + { + FD_READ, /* READ */ + FD_OOB, /* OOB */ + FD_WRITE, /* WRITE */ + FD_CLOSE, /* HUP */ + FD_CLOSE, /* RESET */ + 0, /* CLOSE */ + FD_CONNECT, /* CONNECT */ + FD_ACCEPT, /* ACCEPT */ + FD_CONNECT, /* CONNECT_ERR */ + }; + + unsigned int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(map); ++i) + { + if (flags & (1 << i)) ret |= map[i]; + } + + return ret; +} + + /*********************************************************************** * WSAPoll */ @@ -4347,36 +4374,47 @@ SOCKET WINAPI WS_socket(int af, int type, int protocol)
/*********************************************************************** - * WSAEnumNetworkEvents (WS2_32.36) + * WSAEnumNetworkEvents (ws2_32.@) */ -int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lpEvent) +int WINAPI WSAEnumNetworkEvents( SOCKET s, WSAEVENT event, WSANETWORKEVENTS *ret_events ) { - int ret; - int i; - int errors[FD_MAX_EVENTS]; + struct afd_get_events_params params; + IO_STATUS_BLOCK io; + NTSTATUS status;
- TRACE("%04lx, hEvent %p, lpEvent %p\n", s, hEvent, lpEvent ); + TRACE( "socket %#lx, event %p, events %p\n", s, event, ret_events );
- SERVER_START_REQ( get_socket_event ) + ResetEvent( event ); + + status = NtDeviceIoControlFile( (HANDLE)s, NULL, NULL, NULL, &io, IOCTL_AFD_GET_EVENTS, + NULL, 0, ¶ms, sizeof(params) ); + if (!status) { - req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) ); - req->service = TRUE; - req->c_event = wine_server_obj_handle( hEvent ); - wine_server_set_reply( req, errors, sizeof(errors) ); - if (!(ret = wine_server_call(req))) lpEvent->lNetworkEvents = reply->pmask & reply->mask; - } - SERVER_END_REQ; - if (!ret) - { - for (i = 0; i < FD_MAX_EVENTS; i++) + ret_events->lNetworkEvents = afd_poll_flag_to_win32( params.flags ); + + if (ret_events->lNetworkEvents & FD_READ) + ret_events->iErrorCode[FD_READ_BIT] = NtStatusToWSAError( params.status[AFD_POLL_BIT_READ] ); + + if (ret_events->lNetworkEvents & FD_WRITE) + ret_events->iErrorCode[FD_WRITE_BIT] = NtStatusToWSAError( params.status[AFD_POLL_BIT_WRITE] ); + + if (ret_events->lNetworkEvents & FD_OOB) + ret_events->iErrorCode[FD_OOB_BIT] = NtStatusToWSAError( params.status[AFD_POLL_BIT_OOB] ); + + if (ret_events->lNetworkEvents & FD_ACCEPT) + ret_events->iErrorCode[FD_ACCEPT_BIT] = NtStatusToWSAError( params.status[AFD_POLL_BIT_ACCEPT] ); + + if (ret_events->lNetworkEvents & FD_CONNECT) + ret_events->iErrorCode[FD_CONNECT_BIT] = NtStatusToWSAError( params.status[AFD_POLL_BIT_CONNECT_ERR] ); + + if (ret_events->lNetworkEvents & FD_CLOSE) { - if (lpEvent->lNetworkEvents & (1 << i)) - lpEvent->iErrorCode[i] = errors[i]; + if (!(ret_events->iErrorCode[FD_CLOSE_BIT] = NtStatusToWSAError( params.status[AFD_POLL_BIT_HUP] ))) + ret_events->iErrorCode[FD_CLOSE_BIT] = NtStatusToWSAError( params.status[AFD_POLL_BIT_RESET] ); } - return 0; } - SetLastError(WSAEINVAL); - return SOCKET_ERROR; + SetLastError( NtStatusToWSAError( status ) ); + return status ? -1 : 0; }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- v2: make the failed connection test interactive only
dlls/ws2_32/tests/afd.c | 105 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index e08fc977ad4..443b6e4e42f 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -1229,6 +1229,110 @@ static void test_event_select(void) CloseHandle(event); }
+static void test_get_events(void) +{ + const struct sockaddr_in invalid_addr = + { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + .sin_port = 255, + }; + struct afd_get_events_params params; + WSANETWORKEVENTS events; + SOCKET client, server; + IO_STATUS_BLOCK io; + unsigned int i; + HANDLE event; + int ret; + + event = CreateEventW(NULL, TRUE, FALSE, NULL); + + tcp_socketpair(&client, &server); + + ret = WSAEventSelect(client, event, FD_ACCEPT | FD_CLOSE | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE); + ok(!ret, "got error %u\n", GetLastError()); + + memset(¶ms, 0xcc, sizeof(params)); + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_GET_EVENTS, NULL, 0, NULL, 0); + ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); + + memset(¶ms, 0xcc, sizeof(params)); + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_GET_EVENTS, NULL, 0, ¶ms, sizeof(params)); + ok(!ret, "got %#x\n", ret); + ok(params.flags == (AFD_POLL_WRITE | AFD_POLL_CONNECT), "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 = WSAEnumNetworkEvents(client, event, &events); + ok(!ret, "got error %u\n", GetLastError()); + ok(!events.lNetworkEvents, "got events %#x\n", events.lNetworkEvents); + + closesocket(client); + closesocket(server); + + tcp_socketpair(&client, &server); + + ret = WSAEventSelect(client, event, FD_ACCEPT | FD_CLOSE | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE); + ok(!ret, "got error %u\n", GetLastError()); + + ret = WSAEnumNetworkEvents(client, event, &events); + ok(!ret, "got error %u\n", GetLastError()); + ok(events.lNetworkEvents == (FD_WRITE | FD_CONNECT), "got events %#x\n", events.lNetworkEvents); + + memset(¶ms, 0xcc, sizeof(params)); + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_GET_EVENTS, NULL, 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]); + + closesocket(client); + closesocket(server); + + /* Test a failed connection. The following call can take over 2 seconds to + * complete, so make the test interactive-only. */ + + if (winetest_interactive) + { + client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + ResetEvent(event); + ret = WSAEventSelect(client, event, FD_CONNECT); + ok(!ret, "got error %u\n", GetLastError()); + + ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); + + ret = WaitForSingleObject(event, 2000); + ok(!ret, "got %#x\n", ret); + + memset(¶ms, 0xcc, sizeof(params)); + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_GET_EVENTS, NULL, 0, ¶ms, sizeof(params)); + ok(!ret, "got %#x\n", ret); + ok(params.flags == AFD_POLL_CONNECT_ERR, "got flags %#x\n", params.flags); + for (i = 0; i < ARRAY_SIZE(params.status); ++i) + { + if (i == AFD_POLL_BIT_CONNECT_ERR) + ok(params.status[i] == STATUS_CONNECTION_REFUSED, "got status[%u] %#x\n", i, params.status[i]); + else + ok(!params.status[i], "got status[%u] %#x\n", i, params.status[i]); + } + + closesocket(client); + } + + CloseHandle(event); +} + START_TEST(afd) { WSADATA data; @@ -1240,6 +1344,7 @@ START_TEST(afd) test_poll_completion_port(); test_recv(); test_event_select(); + test_get_events();
WSACleanup(); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- include/wine/afd.h | 9 +++++++++ server/sock.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+)
diff --git a/include/wine/afd.h b/include/wine/afd.h index 46d242c7582..35d047c59d8 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -147,6 +147,7 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_SIOCATMARK CTL_CODE(FILE_DEVICE_NETWORK, 212, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_GET_INTERFACE_LIST CTL_CODE(FILE_DEVICE_NETWORK, 213, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_KEEPALIVE_VALS CTL_CODE(FILE_DEVICE_NETWORK, 214, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_MESSAGE_SELECT CTL_CODE(FILE_DEVICE_NETWORK, 215, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct afd_create_params { @@ -199,4 +200,12 @@ struct afd_transmit_params DWORD flags; };
+struct afd_message_select_params +{ + obj_handle_t handle; + user_handle_t window; + unsigned int message; + int mask; +}; + #endif diff --git a/server/sock.c b/server/sock.c index e1b30507514..6d2ac6af2b7 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2095,6 +2095,35 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 1; }
+ case IOCTL_AFD_WINE_MESSAGE_SELECT: + { + const struct afd_message_select_params *params = get_req_data(); + + if (get_req_data_size() < sizeof(params)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + + if (sock->event) release_object( sock->event ); + + if (params->window) + { + sock->pending_events = 0; + sock->reported_events = 0; + } + sock->event = NULL; + sock->mask = params->mask; + sock->window = params->window; + sock->message = params->message; + sock->wparam = params->handle; + sock->nonblocking = 1; + + sock_reselect( sock ); + + return 1; + } + default: set_error( STATUS_NOT_SUPPORTED ); return 0;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index fc320ea0247..2fa1471ae3b 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -4508,29 +4508,28 @@ BOOL WINAPI WSAGetOverlappedResult( SOCKET s, LPWSAOVERLAPPED lpOverlapped,
/*********************************************************************** - * WSAAsyncSelect (WS2_32.101) + * WSAAsyncSelect (ws2_32.@) */ -INT WINAPI WSAAsyncSelect(SOCKET s, HWND hWnd, UINT uMsg, LONG lEvent) +int WINAPI WSAAsyncSelect( SOCKET s, HWND window, UINT message, LONG mask ) { - int ret; + struct afd_message_select_params params; + IO_STATUS_BLOCK io; + NTSTATUS status;
- TRACE("%04lx, hWnd %p, uMsg %08x, event %08x\n", s, hWnd, uMsg, lEvent); + TRACE( "socket %#lx, window %p, message %#x, mask %#x\n", s, window, message, mask );
- SERVER_START_REQ( set_socket_event ) - { - req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) ); - req->mask = lEvent; - req->event = 0; - req->window = wine_server_user_handle( hWnd ); - req->msg = uMsg; - ret = wine_server_call( req ); - } - SERVER_END_REQ; - if (!ret) return 0; - SetLastError(WSAEINVAL); - return SOCKET_ERROR; + params.handle = wine_server_obj_handle( (HANDLE)s ); + params.window = wine_server_user_handle( window ); + params.message = message; + params.mask = afd_poll_flag_from_win32( mask ); + + status = NtDeviceIoControlFile( (HANDLE)s, NULL, NULL, NULL, &io, IOCTL_AFD_WINE_MESSAGE_SELECT, + ¶ms, sizeof(params), NULL, 0 ); + SetLastError( NtStatusToWSAError( status ) ); + return status ? -1 : 0; }
+ /*********************************************************************** * WSACreateEvent (WS2_32.31) *
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- server/protocol.def | 10 -------- server/sock.c | 60 --------------------------------------------- 2 files changed, 70 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 3609261b848..d3f44482c37 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1423,16 +1423,6 @@ enum server_fd_type @END
-/* Set socket event parameters */ -@REQ(set_socket_event) - obj_handle_t handle; /* handle to the socket */ - unsigned int mask; /* event mask */ - obj_handle_t event; /* event object */ - user_handle_t window; /* window to send the message to */ - unsigned int msg; /* message to send */ -@END - - /* Get socket event parameters */ @REQ(get_socket_event) obj_handle_t handle; /* handle to the socket */ diff --git a/server/sock.c b/server/sock.c index 6d2ac6af2b7..a3062cff8ab 100644 --- a/server/sock.c +++ b/server/sock.c @@ -444,28 +444,6 @@ static unsigned int afd_poll_flag_to_win32( unsigned int flags ) return ret; }
-static unsigned int afd_poll_flag_from_win32( unsigned int flags ) -{ - static const unsigned int map[] = - { - AFD_POLL_READ, - AFD_POLL_WRITE, - AFD_POLL_OOB, - AFD_POLL_ACCEPT, - AFD_POLL_CONNECT | AFD_POLL_CONNECT_ERR, - AFD_POLL_RESET | AFD_POLL_HUP, - }; - - unsigned int i, ret = 0; - - for (i = 0; i < ARRAY_SIZE(map); ++i) - { - if (flags & (1 << i)) ret |= map[i]; - } - - return ret; -} - /* wake anybody waiting on the socket event or send the associated message */ static void sock_wake_up( struct sock *sock ) { @@ -2520,44 +2498,6 @@ struct object *create_socket_device( struct object *root, const struct unicode_s return create_named_object( root, &socket_device_ops, name, attr, sd ); }
-/* set socket event parameters */ -DECL_HANDLER(set_socket_event) -{ - struct sock *sock; - struct event *old_event; - - if (!(sock = (struct sock *)get_handle_obj( current->process, req->handle, - FILE_WRITE_ATTRIBUTES, &sock_ops))) return; - if (get_unix_fd( sock->fd ) == -1) return; - old_event = sock->event; - sock->mask = afd_poll_flag_from_win32( req->mask ); - if (req->window) - { - sock->pending_events &= ~sock->mask; - sock->reported_events &= ~sock->mask; - } - sock->event = NULL; - sock->window = req->window; - sock->message = req->msg; - sock->wparam = req->handle; /* wparam is the socket handle */ - if (req->event) sock->event = get_event_obj( current->process, req->event, EVENT_MODIFY_STATE ); - - if (debug_level && sock->event) fprintf(stderr, "event ptr: %p\n", sock->event); - - sock_reselect( sock ); - - sock->nonblocking = 1; - - /* if a network event is pending, signal the event object - it is possible that CONNECT or ACCEPT network events has happened - before a WSAEventSelect() was done on it. - (when dealing with Asynchronous socket) */ - sock_wake_up( sock ); - - if (old_event) release_object( old_event ); /* we're through with it */ - release_object( &sock->obj ); -} - /* get socket event parameters */ DECL_HANDLER(get_socket_event) {