Signed-off-by: Huw Davies huw@codeweavers.com --- dlls/nsiproxy.sys/device.c | 16 ++++++++++++++-- dlls/nsiproxy.sys/icmp_echo.c | 31 +++++++++++++++++++++++++++++-- dlls/nsiproxy.sys/nsi.c | 1 + dlls/nsiproxy.sys/unix_private.h | 1 + 4 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/dlls/nsiproxy.sys/device.c b/dlls/nsiproxy.sys/device.c index 6461071c395..90a7a3ded7c 100644 --- a/dlls/nsiproxy.sys/device.c +++ b/dlls/nsiproxy.sys/device.c @@ -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 ) diff --git a/dlls/nsiproxy.sys/icmp_echo.c b/dlls/nsiproxy.sys/icmp_echo.c index cef5c04a6c7..999b53186c2 100644 --- a/dlls/nsiproxy.sys/icmp_echo.c +++ b/dlls/nsiproxy.sys/icmp_echo.c @@ -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; diff --git a/dlls/nsiproxy.sys/nsi.c b/dlls/nsiproxy.sys/nsi.c index b92de7a9a11..fa997d2fe36 100644 --- a/dlls/nsiproxy.sys/nsi.c +++ b/dlls/nsiproxy.sys/nsi.c @@ -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, diff --git a/dlls/nsiproxy.sys/unix_private.h b/dlls/nsiproxy.sys/unix_private.h index 855c06011f9..ffb48cc7380 100644 --- a/dlls/nsiproxy.sys/unix_private.h +++ b/dlls/nsiproxy.sys/unix_private.h @@ -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;