Commit 834e2f04 authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

ntdll: Implement IOCTL_AFD_POLL.

parent 30fd3019
...@@ -235,6 +235,159 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi ...@@ -235,6 +235,159 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
return status; return status;
} }
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 NTSTATUS async_poll_proc( void *user, IO_STATUS_BLOCK *io, NTSTATUS status )
{
struct async_poll_ioctl *async = user;
ULONG_PTR information = 0;
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;
information = fill_poll_output( async, status );
}
if (status != STATUS_PENDING)
{
io->Status = status;
io->Information = information;
free( async->input );
release_fileio( &async->io );
}
return status;
}
/* 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, unknown %#x, padding (%#x, %#x, %#x), sockets[0] {%04lx, %#x}\n",
wine_dbgstr_longlong(params->timeout), params->count, params->unknown,
params->padding[0], params->padding[1], params->padding[2],
params->sockets[0].socket, params->sockets[0].flags );
if (params->unknown) FIXME( "unknown boolean is %#x\n", params->unknown );
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, io );
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;
}
NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size ) ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size )
{ {
...@@ -299,6 +452,10 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc ...@@ -299,6 +452,10 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
break; break;
} }
case IOCTL_AFD_POLL:
status = sock_poll( handle, event, apc, apc_user, io, in_buffer, in_size, out_buffer, out_size );
break;
default: default:
{ {
FIXME( "Unknown ioctl %#x (device %#x, access %#x, function %#x, method %#x)\n", FIXME( "Unknown ioctl %#x (device %#x, access %#x, function %#x, method %#x)\n",
......
...@@ -27,6 +27,20 @@ ...@@ -27,6 +27,20 @@
#define IOCTL_AFD_LISTEN CTL_CODE(FILE_DEVICE_BEEP, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS) #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_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 AFD_POLL_READ 0x0001
#define AFD_POLL_OOB 0x0002
#define AFD_POLL_WRITE 0x0004
#define AFD_POLL_HUP 0x0008
#define AFD_POLL_RESET 0x0010
#define AFD_POLL_CLOSE 0x0020
#define AFD_POLL_CONNECT 0x0040
#define AFD_POLL_ACCEPT 0x0080
#define AFD_POLL_CONNECT_ERR 0x0100
/* I have never seen these reported, but StarCraft Remastered polls for them. */
#define AFD_POLL_UNK1 0x0200
#define AFD_POLL_UNK2 0x0400
struct afd_listen_params struct afd_listen_params
{ {
...@@ -50,6 +64,22 @@ struct afd_recv_params ...@@ -50,6 +64,22 @@ struct afd_recv_params
int msg_flags; int msg_flags;
}; };
#include <pshpack4.h>
struct afd_poll_params
{
LONGLONG timeout;
unsigned int count;
BOOLEAN unknown;
BOOLEAN padding[3];
struct
{
SOCKET socket;
int flags;
NTSTATUS status;
} sockets[1];
};
#include <poppack.h>
#define IOCTL_AFD_WINE_CREATE CTL_CODE(FILE_DEVICE_NETWORK, 200, METHOD_BUFFERED, FILE_ANY_ACCESS) #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 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) #define IOCTL_AFD_WINE_ACCEPT_INTO CTL_CODE(FILE_DEVICE_NETWORK, 202, METHOD_BUFFERED, FILE_ANY_ACCESS)
......
...@@ -1834,6 +1834,36 @@ struct recv_socket_reply ...@@ -1834,6 +1834,36 @@ struct recv_socket_reply
}; };
struct poll_socket_input
{
obj_handle_t socket;
int flags;
};
struct poll_socket_output
{
int flags;
unsigned int status;
};
struct poll_socket_request
{
struct request_header __header;
char __pad_12[4];
async_data_t async;
timeout_t timeout;
/* VARARG(sockets,poll_socket_input); */
};
struct poll_socket_reply
{
struct reply_header __header;
obj_handle_t wait;
unsigned int options;
/* VARARG(sockets,poll_socket_output); */
};
struct get_next_console_request_request struct get_next_console_request_request
{ {
...@@ -5485,6 +5515,7 @@ enum request ...@@ -5485,6 +5515,7 @@ enum request
REQ_enable_socket_event, REQ_enable_socket_event,
REQ_set_socket_deferred, REQ_set_socket_deferred,
REQ_recv_socket, REQ_recv_socket,
REQ_poll_socket,
REQ_get_next_console_request, REQ_get_next_console_request,
REQ_read_directory_changes, REQ_read_directory_changes,
REQ_read_change, REQ_read_change,
...@@ -5767,6 +5798,7 @@ union generic_request ...@@ -5767,6 +5798,7 @@ union generic_request
struct enable_socket_event_request enable_socket_event_request; struct enable_socket_event_request enable_socket_event_request;
struct set_socket_deferred_request set_socket_deferred_request; struct set_socket_deferred_request set_socket_deferred_request;
struct recv_socket_request recv_socket_request; struct recv_socket_request recv_socket_request;
struct poll_socket_request poll_socket_request;
struct get_next_console_request_request get_next_console_request_request; struct get_next_console_request_request get_next_console_request_request;
struct read_directory_changes_request read_directory_changes_request; struct read_directory_changes_request read_directory_changes_request;
struct read_change_request read_change_request; struct read_change_request read_change_request;
...@@ -6047,6 +6079,7 @@ union generic_reply ...@@ -6047,6 +6079,7 @@ union generic_reply
struct enable_socket_event_reply enable_socket_event_reply; struct enable_socket_event_reply enable_socket_event_reply;
struct set_socket_deferred_reply set_socket_deferred_reply; struct set_socket_deferred_reply set_socket_deferred_reply;
struct recv_socket_reply recv_socket_reply; struct recv_socket_reply recv_socket_reply;
struct poll_socket_reply poll_socket_reply;
struct get_next_console_request_reply get_next_console_request_reply; struct get_next_console_request_reply get_next_console_request_reply;
struct read_directory_changes_reply read_directory_changes_reply; struct read_directory_changes_reply read_directory_changes_reply;
struct read_change_reply read_change_reply; struct read_change_reply read_change_reply;
...@@ -6267,7 +6300,7 @@ union generic_reply ...@@ -6267,7 +6300,7 @@ union generic_reply
/* ### protocol_version begin ### */ /* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 704 #define SERVER_PROTOCOL_VERSION 705
/* ### protocol_version end ### */ /* ### protocol_version end ### */
......
...@@ -1490,6 +1490,30 @@ enum server_fd_type ...@@ -1490,6 +1490,30 @@ enum server_fd_type
@END @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)
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
/* Retrieve the next pending console ioctl request */ /* Retrieve the next pending console ioctl request */
@REQ(get_next_console_request) @REQ(get_next_console_request)
obj_handle_t handle; /* console server handle */ obj_handle_t handle; /* console server handle */
......
...@@ -178,6 +178,7 @@ DECL_HANDLER(get_socket_info); ...@@ -178,6 +178,7 @@ DECL_HANDLER(get_socket_info);
DECL_HANDLER(enable_socket_event); DECL_HANDLER(enable_socket_event);
DECL_HANDLER(set_socket_deferred); DECL_HANDLER(set_socket_deferred);
DECL_HANDLER(recv_socket); DECL_HANDLER(recv_socket);
DECL_HANDLER(poll_socket);
DECL_HANDLER(get_next_console_request); DECL_HANDLER(get_next_console_request);
DECL_HANDLER(read_directory_changes); DECL_HANDLER(read_directory_changes);
DECL_HANDLER(read_change); DECL_HANDLER(read_change);
...@@ -459,6 +460,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = ...@@ -459,6 +460,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_enable_socket_event, (req_handler)req_enable_socket_event,
(req_handler)req_set_socket_deferred, (req_handler)req_set_socket_deferred,
(req_handler)req_recv_socket, (req_handler)req_recv_socket,
(req_handler)req_poll_socket,
(req_handler)req_get_next_console_request, (req_handler)req_get_next_console_request,
(req_handler)req_read_directory_changes, (req_handler)req_read_directory_changes,
(req_handler)req_read_change, (req_handler)req_read_change,
...@@ -1073,6 +1075,12 @@ C_ASSERT( sizeof(struct recv_socket_request) == 64 ); ...@@ -1073,6 +1075,12 @@ C_ASSERT( sizeof(struct recv_socket_request) == 64 );
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, wait) == 8 ); C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, wait) == 8 );
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, options) == 12 ); C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, options) == 12 );
C_ASSERT( sizeof(struct recv_socket_reply) == 16 ); C_ASSERT( sizeof(struct recv_socket_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct poll_socket_request, async) == 16 );
C_ASSERT( FIELD_OFFSET(struct poll_socket_request, timeout) == 56 );
C_ASSERT( sizeof(struct poll_socket_request) == 64 );
C_ASSERT( FIELD_OFFSET(struct poll_socket_reply, wait) == 8 );
C_ASSERT( FIELD_OFFSET(struct poll_socket_reply, options) == 12 );
C_ASSERT( sizeof(struct poll_socket_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, signal) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, signal) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, read) == 20 ); C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, read) == 20 );
......
...@@ -1372,6 +1372,38 @@ static void dump_varargs_handle_infos( const char *prefix, data_size_t size ) ...@@ -1372,6 +1372,38 @@ static void dump_varargs_handle_infos( const char *prefix, data_size_t size )
fputc( '}', stderr ); 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 ); typedef void (*dump_func)( const void *req );
/* Everything below this line is generated automatically by tools/make_requests */ /* Everything below this line is generated automatically by tools/make_requests */
...@@ -2107,6 +2139,20 @@ static void dump_recv_socket_reply( const struct recv_socket_reply *req ) ...@@ -2107,6 +2139,20 @@ static void dump_recv_socket_reply( const struct recv_socket_reply *req )
fprintf( stderr, ", options=%08x", req->options ); fprintf( stderr, ", options=%08x", req->options );
} }
static void dump_poll_socket_request( const struct poll_socket_request *req )
{
dump_async_data( " async=", &req->async );
dump_timeout( ", timeout=", &req->timeout );
dump_varargs_poll_socket_input( ", sockets=", cur_size );
}
static void dump_poll_socket_reply( const struct poll_socket_reply *req )
{
fprintf( stderr, " wait=%04x", req->wait );
fprintf( stderr, ", options=%08x", req->options );
dump_varargs_poll_socket_output( ", sockets=", cur_size );
}
static void dump_get_next_console_request_request( const struct get_next_console_request_request *req ) static void dump_get_next_console_request_request( const struct get_next_console_request_request *req )
{ {
fprintf( stderr, " handle=%04x", req->handle ); fprintf( stderr, " handle=%04x", req->handle );
...@@ -4555,6 +4601,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { ...@@ -4555,6 +4601,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_enable_socket_event_request, (dump_func)dump_enable_socket_event_request,
(dump_func)dump_set_socket_deferred_request, (dump_func)dump_set_socket_deferred_request,
(dump_func)dump_recv_socket_request, (dump_func)dump_recv_socket_request,
(dump_func)dump_poll_socket_request,
(dump_func)dump_get_next_console_request_request, (dump_func)dump_get_next_console_request_request,
(dump_func)dump_read_directory_changes_request, (dump_func)dump_read_directory_changes_request,
(dump_func)dump_read_change_request, (dump_func)dump_read_change_request,
...@@ -4833,6 +4880,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { ...@@ -4833,6 +4880,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
NULL, NULL,
NULL, NULL,
(dump_func)dump_recv_socket_reply, (dump_func)dump_recv_socket_reply,
(dump_func)dump_poll_socket_reply,
(dump_func)dump_get_next_console_request_reply, (dump_func)dump_get_next_console_request_reply,
NULL, NULL,
(dump_func)dump_read_change_reply, (dump_func)dump_read_change_reply,
...@@ -5111,6 +5159,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { ...@@ -5111,6 +5159,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"enable_socket_event", "enable_socket_event",
"set_socket_deferred", "set_socket_deferred",
"recv_socket", "recv_socket",
"poll_socket",
"get_next_console_request", "get_next_console_request",
"read_directory_changes", "read_directory_changes",
"read_change", "read_change",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment