Signed-off-by: Zebediah Figura z.figura12@gmail.com --- include/wine/afd.h | 19 ++++++ server/sock.c | 166 +++++++++++++++++++++++++++++---------------- 2 files changed, 128 insertions(+), 57 deletions(-)
diff --git a/include/wine/afd.h b/include/wine/afd.h index 595fc572a1c..c4a15d6688c 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -36,6 +36,25 @@ #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)
+enum afd_poll_bit +{ + AFD_POLL_BIT_READ = 0, + AFD_POLL_BIT_OOB = 1, + AFD_POLL_BIT_WRITE = 2, + AFD_POLL_BIT_HUP = 3, + AFD_POLL_BIT_RESET = 4, + AFD_POLL_BIT_CLOSE = 5, + AFD_POLL_BIT_CONNECT = 6, + AFD_POLL_BIT_ACCEPT = 7, + AFD_POLL_BIT_CONNECT_ERR = 8, + /* IOCTL_AFD_GET_EVENTS has space for 13 events. */ + AFD_POLL_BIT_UNK1 = 9, + AFD_POLL_BIT_UNK2 = 10, + AFD_POLL_BIT_UNK3 = 11, + AFD_POLL_BIT_UNK4 = 12, + AFD_POLL_BIT_COUNT = 13, +}; + #define AFD_POLL_READ 0x0001 #define AFD_POLL_OOB 0x0002 #define AFD_POLL_WRITE 0x0004 diff --git a/server/sock.c b/server/sock.c index 66440a540dc..2a22bb2340b 100644 --- a/server/sock.c +++ b/server/sock.c @@ -146,14 +146,14 @@ struct sock struct fd *fd; /* socket file descriptor */ enum connection_state state; /* connection state */ unsigned int mask; /* event mask */ - /* pending FD_* events which have not yet been reported to the application */ + /* pending AFD_POLL_* events which have not yet been reported to the application */ unsigned int pending_events; - /* FD_* events which have already been reported and should not be selected - * for again until reset by a relevant call. + /* AFD_POLL_* events which have already been reported and should not be + * selected for again until reset by a relevant call. * - * For example, if FD_READ is set here and not in pending_events, it has - * already been reported and consumed, and we should not report it again, - * even if POLLIN is signaled, until it is reset by e.g recv(). + * For example, if AFD_POLL_READ is set here and not in pending_events, it + * has already been reported and consumed, and we should not report it + * again, even if POLLIN is signaled, until it is reset by e.g recv(). * * If an event has been signaled and not consumed yet, it will be set in * both pending_events and reported_events (as we should only ever report @@ -167,7 +167,7 @@ struct sock user_handle_t window; /* window to send the message to */ unsigned int message; /* message to send */ obj_handle_t wparam; /* message wparam (socket handle) */ - unsigned int errors[FD_MAX_EVENTS]; /* event errors */ + unsigned int errors[AFD_POLL_BIT_COUNT]; /* event errors */ timeout_t connect_time;/* time the socket was connected */ struct sock *deferred; /* socket that waits for a deferred accept */ struct async_queue read_q; /* queue for asynchronous reads */ @@ -338,27 +338,21 @@ static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_socka } }
-/* Permutation of 0..FD_MAX_EVENTS - 1 representing the order in which - * we post messages if there are multiple events. Used to send - * messages. The problem is if there is both a FD_CONNECT event and, - * say, an FD_READ event available on the same socket, we want to - * notify the app of the connect event first. Otherwise it may - * discard the read event because it thinks it hasn't connected yet. - */ -static const int event_bitorder[FD_MAX_EVENTS] = +/* some events are generated at the same time but must be sent in a particular + * order (e.g. CONNECT must be sent before READ) */ +static const enum afd_poll_bit event_bitorder[] = { - FD_CONNECT_BIT, - FD_ACCEPT_BIT, - FD_OOB_BIT, - FD_WRITE_BIT, - FD_READ_BIT, - FD_CLOSE_BIT, - 6, 7, 8, 9 /* leftovers */ + AFD_POLL_BIT_CONNECT, + AFD_POLL_BIT_CONNECT_ERR, + AFD_POLL_BIT_ACCEPT, + AFD_POLL_BIT_OOB, + AFD_POLL_BIT_WRITE, + AFD_POLL_BIT_READ, + AFD_POLL_BIT_RESET, + AFD_POLL_BIT_HUP, + AFD_POLL_BIT_CLOSE, };
-/* Flags that make sense only for SOCK_STREAM sockets */ -#define STREAM_FLAG_MASK ((unsigned int) (FD_CONNECT | FD_ACCEPT | FD_WINE_LISTENING | FD_WINE_CONNECTED)) - typedef enum { SOCK_SHUTDOWN_ERROR = -1, SOCK_SHUTDOWN_EOF = 0, @@ -425,6 +419,53 @@ static int sock_reselect( struct sock *sock ) return ev; }
+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; +} + +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 ) { @@ -440,12 +481,12 @@ static void sock_wake_up( struct sock *sock ) if (sock->window) { if (debug_level) fprintf(stderr, "signalling events %x win %08x\n", events, sock->window ); - for (i = 0; i < FD_MAX_EVENTS; i++) + for (i = 0; i < ARRAY_SIZE(event_bitorder); i++) { - int event = event_bitorder[i]; + enum afd_poll_bit event = event_bitorder[i]; if (events & (1 << event)) { - lparam_t lparam = (1 << event) | (sock->errors[event] << 16); + lparam_t lparam = afd_poll_flag_to_win32(1 << event) | (sock->errors[event] << 16); post_message( sock->window, sock->message, sock->wparam, lparam ); } } @@ -810,7 +851,7 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) return event; }
-static void post_socket_event( struct sock *sock, unsigned int event_bit, unsigned int error ) +static void post_socket_event( struct sock *sock, enum afd_poll_bit event_bit, unsigned int error ) { unsigned int event = (1 << event_bit);
@@ -830,28 +871,30 @@ static void sock_dispatch_events( struct sock *sock, enum connection_state prevs break;
case SOCK_CONNECTING: - if (event & (POLLOUT | POLLERR | POLLHUP)) - post_socket_event( sock, FD_CONNECT_BIT, sock_get_error( error ) ); + if (event & POLLOUT) + post_socket_event( sock, AFD_POLL_BIT_CONNECT, 0 ); + if (event & (POLLERR | POLLHUP)) + post_socket_event( sock, AFD_POLL_BIT_CONNECT_ERR, sock_get_error( error ) ); break;
case SOCK_LISTENING: if (event & (POLLIN | POLLERR | POLLHUP)) - post_socket_event( sock, FD_ACCEPT_BIT, sock_get_error( error ) ); + post_socket_event( sock, AFD_POLL_BIT_ACCEPT, sock_get_error( error ) ); break;
case SOCK_CONNECTED: case SOCK_CONNECTIONLESS: if (event & POLLIN) - post_socket_event( sock, FD_READ_BIT, 0 ); + post_socket_event( sock, AFD_POLL_BIT_READ, 0 );
if (event & POLLOUT) - post_socket_event( sock, FD_WRITE_BIT, 0 ); + post_socket_event( sock, AFD_POLL_BIT_WRITE, 0 );
if (event & POLLPRI) - post_socket_event( sock, FD_OOB_BIT, 0 ); + post_socket_event( sock, AFD_POLL_BIT_OOB, 0 );
if (event & (POLLERR | POLLHUP)) - post_socket_event( sock, FD_CLOSE_BIT, sock_get_error( error ) ); + post_socket_event( sock, AFD_POLL_BIT_HUP, sock_get_error( error ) ); break; }
@@ -1006,7 +1049,7 @@ static int sock_get_poll_events( struct fd *fd ) return POLLOUT;
case SOCK_LISTENING: - if (!list_empty( &sock->accept_list ) || (mask & FD_ACCEPT)) + if (!list_empty( &sock->accept_list ) || (mask & AFD_POLL_ACCEPT)) ev |= POLLIN; break;
@@ -1020,17 +1063,17 @@ static int sock_get_poll_events( struct fd *fd ) { if (async_waiting( &sock->read_q )) ev |= POLLIN | POLLPRI; } - else if (!sock->rd_shutdown && (mask & FD_READ)) + else if (!sock->rd_shutdown && (mask & AFD_POLL_READ)) ev |= POLLIN | POLLPRI; - /* We use POLLIN with 0 bytes recv() as FD_CLOSE indication for stream sockets. */ - else if (sock->state == SOCK_CONNECTED && (mask & FD_CLOSE) && !(sock->reported_events & FD_READ)) + /* 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;
if (async_queued( &sock->write_q )) { if (async_waiting( &sock->write_q )) ev |= POLLOUT; } - else if (!sock->wr_shutdown && (mask & FD_WRITE)) + else if (!sock->wr_shutdown && (mask & AFD_POLL_WRITE)) { ev |= POLLOUT; } @@ -1465,8 +1508,8 @@ static struct sock *accept_socket( struct sock *sock ) } } clear_error(); - sock->pending_events &= ~FD_ACCEPT; - sock->reported_events &= ~FD_ACCEPT; + sock->pending_events &= ~AFD_POLL_ACCEPT; + sock->reported_events &= ~AFD_POLL_ACCEPT; sock_reselect( sock ); return acceptsock; } @@ -1514,8 +1557,8 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock ) acceptsock->fd = newfd;
clear_error(); - sock->pending_events &= ~FD_ACCEPT; - sock->reported_events &= ~FD_ACCEPT; + sock->pending_events &= ~AFD_POLL_ACCEPT; + sock->reported_events &= ~AFD_POLL_ACCEPT; sock_reselect( sock );
return TRUE; @@ -1791,7 +1834,7 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) /* a listening socket can no longer be accepted into */ allow_fd_caching( sock->fd );
- /* we may already be selecting for FD_ACCEPT */ + /* we may already be selecting for AFD_POLL_ACCEPT */ sock_reselect( sock ); return 0; } @@ -2374,11 +2417,11 @@ DECL_HANDLER(set_socket_event) FILE_WRITE_ATTRIBUTES, &sock_ops))) return; if (get_unix_fd( sock->fd ) == -1) return; old_event = sock->event; - sock->mask = req->mask; + sock->mask = afd_poll_flag_from_win32( req->mask ); if (req->window) { - sock->pending_events &= ~req->mask; - sock->reported_events &= ~req->mask; + sock->pending_events &= ~sock->mask; + sock->reported_events &= ~sock->mask; } sock->event = NULL; sock->window = req->window; @@ -2393,7 +2436,7 @@ DECL_HANDLER(set_socket_event) sock->nonblocking = 1;
/* if a network event is pending, signal the event object - it is possible that FD_CONNECT or FD_ACCEPT network events has happened + 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 ); @@ -2405,14 +2448,23 @@ DECL_HANDLER(set_socket_event) /* get socket event parameters */ DECL_HANDLER(get_socket_event) { + unsigned int errors[FD_MAX_EVENTS] = {0}; struct sock *sock;
if (!(sock = (struct sock *)get_handle_obj( current->process, req->handle, FILE_READ_ATTRIBUTES, &sock_ops ))) return; if (get_unix_fd( sock->fd ) == -1) return; - reply->mask = sock->mask; - reply->pmask = sock->pending_events; - set_reply_data( sock->errors, min( get_reply_max_size(), sizeof(sock->errors) )); + reply->mask = afd_poll_flag_to_win32( sock->mask ); + reply->pmask = afd_poll_flag_to_win32( sock->pending_events ); + + errors[FD_READ_BIT] = sock->errors[AFD_POLL_BIT_READ]; + errors[FD_WRITE_BIT] = sock->errors[AFD_POLL_BIT_WRITE]; + errors[FD_OOB_BIT] = sock->errors[AFD_POLL_BIT_OOB]; + errors[FD_ACCEPT_BIT] = sock->errors[AFD_POLL_BIT_ACCEPT]; + errors[FD_CONNECT_BIT] = sock->errors[AFD_POLL_BIT_CONNECT_ERR]; + if (!(errors[FD_CLOSE_BIT] = sock->errors[AFD_POLL_BIT_HUP])) + errors[FD_CLOSE_BIT] = sock->errors[AFD_POLL_BIT_RESET]; + set_reply_data( errors, min( get_reply_max_size(), sizeof(errors) ));
if (req->service) { @@ -2499,8 +2551,8 @@ DECL_HANDLER(recv_socket)
if (status == STATUS_PENDING && sock->rd_shutdown) status = STATUS_PIPE_DISCONNECTED;
- sock->pending_events &= ~(req->oob ? FD_OOB : FD_READ); - sock->reported_events &= ~(req->oob ? FD_OOB : FD_READ); + sock->pending_events &= ~(req->oob ? AFD_POLL_OOB : AFD_POLL_READ); + sock->reported_events &= ~(req->oob ? AFD_POLL_OOB : AFD_POLL_READ);
if ((async = create_request_async( fd, get_fd_comp_flags( fd ), &req->async ))) { @@ -2570,8 +2622,8 @@ DECL_HANDLER(send_socket) if (status != STATUS_SUCCESS) { /* send() calls only clear and reselect events if unsuccessful. */ - sock->pending_events &= ~FD_WRITE; - sock->reported_events &= ~FD_WRITE; + sock->pending_events &= ~AFD_POLL_WRITE; + sock->reported_events &= ~AFD_POLL_WRITE; }
/* If we had a short write and the socket is nonblocking (and the client is
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- server/sock.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 2a22bb2340b..026188e79af 100644 --- a/server/sock.c +++ b/server/sock.c @@ -167,7 +167,7 @@ struct sock user_handle_t window; /* window to send the message to */ unsigned int message; /* message to send */ obj_handle_t wparam; /* message wparam (socket handle) */ - unsigned int errors[AFD_POLL_BIT_COUNT]; /* event errors */ + int errors[AFD_POLL_BIT_COUNT]; /* event errors */ timeout_t connect_time;/* time the socket was connected */ struct sock *deferred; /* socket that waits for a deferred accept */ struct async_queue read_q; /* queue for asynchronous reads */ @@ -486,7 +486,7 @@ static void sock_wake_up( struct sock *sock ) enum afd_poll_bit event = event_bitorder[i]; if (events & (1 << event)) { - lparam_t lparam = afd_poll_flag_to_win32(1 << event) | (sock->errors[event] << 16); + lparam_t lparam = afd_poll_flag_to_win32(1 << event) | (sock_get_error( sock->errors[event] ) << 16); post_message( sock->window, sock->message, sock->wparam, lparam ); } } @@ -851,7 +851,7 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) return event; }
-static void post_socket_event( struct sock *sock, enum afd_poll_bit event_bit, unsigned int error ) +static void post_socket_event( struct sock *sock, enum afd_poll_bit event_bit, int error ) { unsigned int event = (1 << event_bit);
@@ -874,12 +874,12 @@ static void sock_dispatch_events( struct sock *sock, enum connection_state prevs if (event & POLLOUT) post_socket_event( sock, AFD_POLL_BIT_CONNECT, 0 ); if (event & (POLLERR | POLLHUP)) - post_socket_event( sock, AFD_POLL_BIT_CONNECT_ERR, sock_get_error( error ) ); + post_socket_event( sock, AFD_POLL_BIT_CONNECT_ERR, error ); break;
case SOCK_LISTENING: if (event & (POLLIN | POLLERR | POLLHUP)) - post_socket_event( sock, AFD_POLL_BIT_ACCEPT, sock_get_error( error ) ); + post_socket_event( sock, AFD_POLL_BIT_ACCEPT, error ); break;
case SOCK_CONNECTED: @@ -894,7 +894,7 @@ static void sock_dispatch_events( struct sock *sock, enum connection_state prevs post_socket_event( sock, AFD_POLL_BIT_OOB, 0 );
if (event & (POLLERR | POLLHUP)) - post_socket_event( sock, AFD_POLL_BIT_HUP, sock_get_error( error ) ); + post_socket_event( sock, AFD_POLL_BIT_HUP, error ); break; }
@@ -2457,13 +2457,13 @@ DECL_HANDLER(get_socket_event) reply->mask = afd_poll_flag_to_win32( sock->mask ); reply->pmask = afd_poll_flag_to_win32( sock->pending_events );
- errors[FD_READ_BIT] = sock->errors[AFD_POLL_BIT_READ]; - errors[FD_WRITE_BIT] = sock->errors[AFD_POLL_BIT_WRITE]; - errors[FD_OOB_BIT] = sock->errors[AFD_POLL_BIT_OOB]; - errors[FD_ACCEPT_BIT] = sock->errors[AFD_POLL_BIT_ACCEPT]; - errors[FD_CONNECT_BIT] = sock->errors[AFD_POLL_BIT_CONNECT_ERR]; - if (!(errors[FD_CLOSE_BIT] = sock->errors[AFD_POLL_BIT_HUP])) - errors[FD_CLOSE_BIT] = sock->errors[AFD_POLL_BIT_RESET]; + errors[FD_READ_BIT] = sock_get_error( sock->errors[AFD_POLL_BIT_READ] ); + errors[FD_WRITE_BIT] = sock_get_error( sock->errors[AFD_POLL_BIT_WRITE] ); + errors[FD_OOB_BIT] = sock_get_error( sock->errors[AFD_POLL_BIT_OOB] ); + errors[FD_ACCEPT_BIT] = sock_get_error( sock->errors[AFD_POLL_BIT_ACCEPT] ); + errors[FD_CONNECT_BIT] = sock_get_error( sock->errors[AFD_POLL_BIT_CONNECT_ERR] ); + if (!(errors[FD_CLOSE_BIT] = sock_get_error( sock->errors[AFD_POLL_BIT_HUP] ))) + errors[FD_CLOSE_BIT] = sock_get_error( sock->errors[AFD_POLL_BIT_RESET] ); set_reply_data( errors, min( get_reply_max_size(), sizeof(errors) ));
if (req->service)
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/unix/socket.c | 11 +++++++++ include/wine/afd.h | 19 ++++++++++++++ server/sock.c | 53 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index c1cd319ccf9..088f29f85ff 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1170,6 +1170,17 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc break; }
+ case IOCTL_AFD_EVENT_SELECT: + { + const struct afd_event_select_params *params = in_buffer; + + TRACE( "event %p, mask %#x\n", params->event, params->mask ); + if (out_size) FIXME( "unexpected output size %u\n", out_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 c4a15d6688c..2eb3e6f12a9 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -35,6 +35,7 @@ #define IOCTL_AFD_LISTEN CTL_CODE(FILE_DEVICE_BEEP, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS) #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)
enum afd_poll_bit { @@ -106,6 +107,24 @@ struct afd_poll_params }; #include <poppack.h>
+struct afd_event_select_params +{ + HANDLE event; + int mask; +}; + +struct afd_event_select_params_64 +{ + ULONGLONG event; + int mask; +}; + +struct afd_event_select_params_32 +{ + ULONG event; + int mask; +}; + #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 026188e79af..3556ee21aa3 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2011,6 +2011,59 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) } return 1;
+ case IOCTL_AFD_EVENT_SELECT: + { + struct event *event = NULL; + obj_handle_t event_handle; + int mask; + + if (is_machine_64bit( current->process->machine )) + { + const struct afd_event_select_params_64 *params = get_req_data(); + + if (get_req_data_size() < sizeof(params)) + { + set_error( STATUS_INVALID_PARAMETER ); + return 1; + } + + event_handle = params->event; + mask = params->mask; + } + else + { + const struct afd_event_select_params_32 *params = get_req_data(); + + if (get_req_data_size() < sizeof(params)) + { + set_error( STATUS_INVALID_PARAMETER ); + return 1; + } + + event_handle = params->event; + mask = params->mask; + } + + if ((event_handle || mask) && + !(event = get_event_obj( current->process, event_handle, EVENT_MODIFY_STATE ))) + { + set_error( STATUS_INVALID_PARAMETER ); + return 1; + } + + if (sock->event) release_object( sock->event ); + sock->event = event; + sock->mask = mask; + sock->window = 0; + sock->message = 0; + sock->wparam = 0; + 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 | 59 ++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 19 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index f4e3a6c9e43..69dec158e5a 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -4379,30 +4379,51 @@ int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lp return SOCKET_ERROR; }
-/*********************************************************************** - * WSAEventSelect (WS2_32.39) - */ -int WINAPI WSAEventSelect(SOCKET s, WSAEVENT hEvent, LONG lEvent) + +static unsigned int afd_poll_flag_from_win32( unsigned int flags ) { - int ret; - - TRACE("%04lx, hEvent %p, event %08x\n", s, hEvent, lEvent); - - SERVER_START_REQ( set_socket_event ) + static const unsigned int map[] = { - req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) ); - req->mask = lEvent; - req->event = wine_server_obj_handle( hEvent ); - req->window = 0; - req->msg = 0; - ret = wine_server_call( req ); + 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]; } - SERVER_END_REQ; - if (!ret) return 0; - SetLastError(WSAEINVAL); - return SOCKET_ERROR; + + return ret; }
+ +/*********************************************************************** + * WSAEventSelect (ws2_32.@) + */ +int WINAPI WSAEventSelect( SOCKET s, WSAEVENT event, LONG mask ) +{ + struct afd_event_select_params params; + IO_STATUS_BLOCK io; + NTSTATUS status; + + TRACE( "socket %#lx, event %p, mask %#x\n", s, event, mask ); + + params.event = event; + params.mask = afd_poll_flag_from_win32( mask ); + + status = NtDeviceIoControlFile( (HANDLE)s, NULL, NULL, NULL, &io, IOCTL_AFD_EVENT_SELECT, + ¶ms, sizeof(params), NULL, 0 ); + SetLastError( NtStatusToWSAError( status ) ); + return status ? -1 : 0; +} + + /********************************************************************** * WSAGetOverlappedResult (WS2_32.40) */
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/tests/afd.c | 94 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 87e4779b980..e08fc977ad4 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -1136,6 +1136,99 @@ static void test_recv(void) CloseHandle(event); }
+static void test_event_select(void) +{ + struct afd_event_select_params params; + WSANETWORKEVENTS events; + SOCKET client, server; + IO_STATUS_BLOCK io; + HANDLE event; + int ret; + + event = CreateEventW(NULL, TRUE, FALSE, NULL); + + tcp_socketpair(&client, &server); + + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_EVENT_SELECT, NULL, 0, NULL, 0); + ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); + ok(io.Status == STATUS_INVALID_PARAMETER, "got status %#x\n", io.Status); + ok(!io.Information, "got information %#Ix\n", io.Information); + + params.event = 0; + params.mask = ~0; + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_EVENT_SELECT, ¶ms, sizeof(params), NULL, 0); + ok(ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret); + ok(io.Status == STATUS_INVALID_PARAMETER, "got status %#x\n", io.Status); + ok(!io.Information, "got information %#Ix\n", io.Information); + + params.event = event; + params.mask = ~0; + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_EVENT_SELECT, ¶ms, sizeof(params), NULL, 0); + ok(!ret, "got %#x\n", ret); + ok(!io.Status, "got status %#x\n", io.Status); + ok(!io.Information, "got information %#Ix\n", io.Information); + + ret = WSAEnumNetworkEvents(client, event, &events); + ok(!ret, "got error %u\n", WSAGetLastError()); + ok(events.lNetworkEvents == (FD_CONNECT | FD_WRITE), "got events %#x\n", events.lNetworkEvents); + + closesocket(client); + closesocket(server); + + tcp_socketpair(&client, &server); + + params.event = event; + params.mask = AFD_POLL_CONNECT; + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_EVENT_SELECT, ¶ms, sizeof(params), NULL, 0); + ok(!ret, "got %#x\n", ret); + ok(!io.Status, "got status %#x\n", io.Status); + ok(!io.Information, "got information %#Ix\n", io.Information); + + ret = WSAEnumNetworkEvents(client, event, &events); + ok(!ret, "got error %u\n", WSAGetLastError()); + ok(events.lNetworkEvents == FD_CONNECT, "got events %#x\n", events.lNetworkEvents); + + closesocket(client); + closesocket(server); + + tcp_socketpair(&client, &server); + + params.event = event; + params.mask = ~0; + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_EVENT_SELECT, ¶ms, sizeof(params), NULL, 0); + ok(!ret, "got %#x\n", ret); + ok(!io.Status, "got status %#x\n", io.Status); + ok(!io.Information, "got information %#Ix\n", io.Information); + + params.event = 0; + params.mask = 0; + memset(&io, 0xcc, sizeof(io)); + ret = NtDeviceIoControlFile((HANDLE)client, NULL, NULL, NULL, &io, + IOCTL_AFD_EVENT_SELECT, ¶ms, sizeof(params), NULL, 0); + ok(!ret, "got %#x\n", ret); + ok(!io.Status, "got status %#x\n", io.Status); + ok(!io.Information, "got information %#Ix\n", io.Information); + + ret = WSAEnumNetworkEvents(client, event, &events); + ok(!ret, "got error %u\n", WSAGetLastError()); + ok(!events.lNetworkEvents, "got events %#x\n", events.lNetworkEvents); + + closesocket(client); + closesocket(server); + + CloseHandle(event); +} + START_TEST(afd) { WSADATA data; @@ -1146,6 +1239,7 @@ START_TEST(afd) test_poll(); test_poll_completion_port(); test_recv(); + test_event_select();
WSACleanup(); }