nsiproxy: Implement the ability to cancel the listener.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2021-10-05 07:37:53 +01:00 committed by Alexandre Julliard
parent 881577deaf
commit 19a6d409c0
4 changed files with 45 additions and 4 deletions

View file

@ -58,6 +58,7 @@ static NTSTATUS nsiproxy_call( unsigned int code, void *args )
enum unix_calls
{
icmp_cancel_listen,
icmp_close,
icmp_listen,
icmp_send_echo,
@ -191,12 +192,23 @@ static inline HANDLE irp_set_icmp_handle( IRP *irp, HANDLE handle )
static void WINAPI icmp_echo_cancel( DEVICE_OBJECT *device, IRP *irp )
{
HANDLE handle;
TRACE( "device %p, irp %p.\n", device, irp );
IoReleaseCancelSpinLock( irp->CancelIrql );
/* FIXME: at the moment just let the request thread bail */
return;
EnterCriticalSection( &nsiproxy_cs );
/* If the handle is not set, either the irp is still
in the request queue, in which case the request thread will
cancel it, or the irp has already finished. If the handle
does exist then notify the listen thread. In all cases the irp
will be completed elsewhere. */
handle = irp_get_icmp_handle( irp );
if (handle) nsiproxy_call( icmp_cancel_listen, handle );
LeaveCriticalSection( &nsiproxy_cs );
}
static NTSTATUS nsiproxy_icmp_echo( IRP *irp )

View file

@ -100,6 +100,7 @@ struct icmp_data
{
LARGE_INTEGER send_time;
int socket;
int cancel_pipe[2];
unsigned short id;
unsigned short seq;
const struct family_ops *ops;
@ -522,8 +523,14 @@ static NTSTATUS icmp_data_create( ADDRESS_FAMILY win_family, struct icmp_data **
if (ops->family == AF_INET) ops = &ipv4_linux_ping;
#endif
}
data->ops = ops;
if (pipe( data->cancel_pipe ))
{
close( data->socket );
free( data );
return STATUS_ACCESS_DENIED;
}
data->ops = ops;
*icmp_data = data;
return STATUS_SUCCESS;
}
@ -531,6 +538,8 @@ static NTSTATUS icmp_data_create( ADDRESS_FAMILY win_family, struct icmp_data **
static void icmp_data_free( struct icmp_data *data )
{
close( data->socket );
close( data->cancel_pipe[0] );
close( data->cancel_pipe[1] );
free( data );
}
@ -668,7 +677,7 @@ NTSTATUS icmp_listen( void *args )
{
struct icmp_listen_params *params = args;
struct icmp_data *data;
struct pollfd fds[1];
struct pollfd fds[2];
NTSTATUS status;
int ret;
@ -677,9 +686,17 @@ NTSTATUS icmp_listen( void *args )
fds[0].fd = data->socket;
fds[0].events = POLLIN;
fds[1].fd = data->cancel_pipe[0];
fds[1].events = POLLIN;
while ((ret = poll( fds, ARRAY_SIZE(fds), get_timeout( data->send_time, params->timeout ) )) > 0)
{
if (fds[1].revents & POLLIN)
{
TRACE( "cancelled\n" );
return STATUS_CANCELLED;
}
status = recv_msg( data, params );
if (status == STATUS_RETRY) continue;
return status;
@ -694,6 +711,16 @@ NTSTATUS icmp_listen( void *args )
return set_reply_ip_status( params, errno_to_ip_status( errno ) );
}
NTSTATUS icmp_cancel_listen( void *args )
{
HANDLE handle = args;
struct icmp_data *data = handle_data( handle );
if (!data) return STATUS_INVALID_PARAMETER;
write( data->cancel_pipe[1], "x", 1 );
return STATUS_SUCCESS;
}
NTSTATUS icmp_close( void *args )
{
HANDLE handle = args;

View file

@ -147,6 +147,7 @@ static NTSTATUS unix_nsi_get_parameter_ex( void *args )
const unixlib_entry_t __wine_unix_call_funcs[] =
{
icmp_cancel_listen,
icmp_close,
icmp_listen,
icmp_send_echo,

View file

@ -157,6 +157,7 @@ static inline int ascii_strcasecmp( const char *s1, const char *s2 )
return ascii_strncasecmp( s1, s2, -1 );
}
NTSTATUS icmp_cancel_listen( void *args ) DECLSPEC_HIDDEN;
NTSTATUS icmp_close( void *args ) DECLSPEC_HIDDEN;
NTSTATUS icmp_listen( void *args ) DECLSPEC_HIDDEN;
NTSTATUS icmp_send_echo( void *args ) DECLSPEC_HIDDEN;