Module: wine Branch: master Commit: 350cf6654e186d52a1ebbf4cc1a7fcc20567a7e9 URL: http://source.winehq.org/git/wine.git/?a=commit;h=350cf6654e186d52a1ebbf4cc1...
Author: Hans Leidekker hans@codeweavers.com Date: Wed May 10 14:26:15 2017 +0200
webservices: Allow listeners to be cancelled.
Signed-off-by: Hans Leidekker hans@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/webservices/channel.c | 77 +++++++++++++++++++++++++++++++-------- dlls/webservices/listener.c | 48 +++++++++++++++++++----- dlls/webservices/sock.h | 4 +- dlls/webservices/tests/listener.c | 3 ++ 4 files changed, 105 insertions(+), 27 deletions(-)
diff --git a/dlls/webservices/channel.c b/dlls/webservices/channel.c index aa78d1e..9fb1944 100644 --- a/dlls/webservices/channel.c +++ b/dlls/webservices/channel.c @@ -1168,9 +1168,42 @@ HRESULT WINAPI WsWriteMessageEnd( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ return hr; }
-HRESULT channel_accept_tcp( SOCKET socket, WS_CHANNEL *handle ) +static HRESULT sock_accept( SOCKET socket, HANDLE wait, HANDLE cancel, SOCKET *ret ) +{ + HANDLE handles[] = { wait, cancel }; + ULONG nonblocking = 0; + HRESULT hr = S_OK; + + if (WSAEventSelect( socket, handles[0], FD_ACCEPT )) return HRESULT_FROM_WIN32( WSAGetLastError() ); + + switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE )) + { + case 0: + if ((*ret = accept( socket, NULL, NULL )) != -1) + { + WSAEventSelect( *ret, NULL, 0 ); + ioctlsocket( *ret, FIONBIO, &nonblocking ); + break; + } + hr = HRESULT_FROM_WIN32( WSAGetLastError() ); + break; + + case 1: + hr = WS_E_OPERATION_ABORTED; + break; + + default: + hr = HRESULT_FROM_WIN32( WSAGetLastError() ); + break; + } + + return hr; +} + +HRESULT channel_accept_tcp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle ) { struct channel *channel = (struct channel *)handle; + HRESULT hr;
EnterCriticalSection( &channel->cs );
@@ -1180,27 +1213,41 @@ HRESULT channel_accept_tcp( SOCKET socket, WS_CHANNEL *handle ) return E_INVALIDARG; }
- if ((channel->u.tcp.socket = accept( socket, NULL, NULL )) == -1) - { - LeaveCriticalSection( &channel->cs ); - return HRESULT_FROM_WIN32( WSAGetLastError() ); - } + hr = sock_accept( socket, wait, cancel, &channel->u.tcp.socket );
LeaveCriticalSection( &channel->cs ); - return S_OK; + return hr; }
-static HRESULT sock_wait( SOCKET socket ) +static HRESULT sock_wait( SOCKET socket, HANDLE wait, HANDLE cancel ) { - fd_set read; + HANDLE handles[] = { wait, cancel }; + ULONG nonblocking = 0; + HRESULT hr;
- FD_ZERO( &read ); - FD_SET( socket, &read ); - if (select( socket + 1, &read, NULL, NULL, NULL ) < 0) return HRESULT_FROM_WIN32( WSAGetLastError() ); - return S_OK; + if (WSAEventSelect( socket, handles[0], FD_READ )) return HRESULT_FROM_WIN32( WSAGetLastError() ); + + switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE )) + { + case 0: + hr = S_OK; + break; + + case 1: + hr = WS_E_OPERATION_ABORTED; + break; + + default: + hr = HRESULT_FROM_WIN32( WSAGetLastError() ); + break; + } + + WSAEventSelect( socket, NULL, 0 ); + ioctlsocket( socket, FIONBIO, &nonblocking ); + return hr; }
-HRESULT channel_accept_udp( SOCKET socket, WS_CHANNEL *handle ) +HRESULT channel_accept_udp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle ) { struct channel *channel = (struct channel *)handle; HRESULT hr; @@ -1213,7 +1260,7 @@ HRESULT channel_accept_udp( SOCKET socket, WS_CHANNEL *handle ) return E_INVALIDARG; }
- if ((hr = sock_wait( socket )) == S_OK) channel->u.udp.socket = socket; + if ((hr = sock_wait( socket, wait, cancel )) == S_OK) channel->u.udp.socket = socket;
LeaveCriticalSection( &channel->cs ); return hr; diff --git a/dlls/webservices/listener.c b/dlls/webservices/listener.c index 7d49b73..5d6d1a8 100644 --- a/dlls/webservices/listener.c +++ b/dlls/webservices/listener.c @@ -75,6 +75,9 @@ struct listener WS_CHANNEL_TYPE type; WS_CHANNEL_BINDING binding; WS_LISTENER_STATE state; + HANDLE wait; + HANDLE cancel; + WS_CHANNEL *channel; union { struct @@ -100,7 +103,18 @@ static struct listener *alloc_listener(void)
if (!(ret = heap_alloc_zero( size ))) return NULL;
- ret->magic = LISTENER_MAGIC; + ret->magic = LISTENER_MAGIC; + if (!(ret->wait = CreateEventW( NULL, FALSE, FALSE, NULL ))) + { + heap_free( ret ); + return NULL; + } + if (!(ret->cancel = CreateEventW( NULL, FALSE, FALSE, NULL ))) + { + CloseHandle( ret->wait ); + heap_free( ret ); + return NULL; + } InitializeCriticalSection( &ret->cs ); ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": listener.cs");
@@ -112,6 +126,8 @@ static struct listener *alloc_listener(void) static void reset_listener( struct listener *listener ) { listener->state = WS_LISTENER_STATE_CREATED; + SetEvent( listener->cancel ); + listener->channel = NULL;
switch (listener->binding) { @@ -132,6 +148,10 @@ static void reset_listener( struct listener *listener ) static void free_listener( struct listener *listener ) { reset_listener( listener ); + + CloseHandle( listener->wait ); + CloseHandle( listener->cancel ); + listener->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &listener->cs ); heap_free( listener ); @@ -569,7 +589,8 @@ HRESULT WINAPI WsAcceptChannel( WS_LISTENER *handle, WS_CHANNEL *channel_handle, WS_ERROR *error ) { struct listener *listener = (struct listener *)handle; - HRESULT hr; + HRESULT hr = E_NOTIMPL; + HANDLE wait, cancel;
TRACE( "%p %p %p %p\n", handle, channel_handle, ctx, error ); if (error) FIXME( "ignoring error parameter\n" ); @@ -585,27 +606,34 @@ HRESULT WINAPI WsAcceptChannel( WS_LISTENER *handle, WS_CHANNEL *channel_handle, return E_INVALIDARG; }
- if (listener->state != WS_LISTENER_STATE_OPEN) + if (listener->state != WS_LISTENER_STATE_OPEN || listener->channel) { LeaveCriticalSection( &listener->cs ); return WS_E_INVALID_OPERATION; }
+ wait = listener->wait; + cancel = listener->cancel; + listener->channel = channel_handle; + switch (listener->binding) { case WS_TCP_CHANNEL_BINDING: - hr = channel_accept_tcp( listener->u.tcp.socket, channel_handle ); - break; + { + SOCKET socket = listener->u.tcp.socket;
+ LeaveCriticalSection( &listener->cs ); + return channel_accept_tcp( socket, wait, cancel, channel_handle ); + } case WS_UDP_CHANNEL_BINDING: - /* hand over socket on success */ - if ((hr = channel_accept_udp( listener->u.udp.socket, channel_handle )) == S_OK) - listener->u.udp.socket = -1; - break; + { + SOCKET socket = listener->u.udp.socket;
+ LeaveCriticalSection( &listener->cs ); + return channel_accept_udp( socket, wait, cancel, channel_handle ); + } default: FIXME( "listener binding %u not supported\n", listener->binding ); - hr = E_NOTIMPL; break; }
diff --git a/dlls/webservices/sock.h b/dlls/webservices/sock.h index 6b30f64..e03b91e 100644 --- a/dlls/webservices/sock.h +++ b/dlls/webservices/sock.h @@ -20,5 +20,5 @@
void winsock_init(void) DECLSPEC_HIDDEN; HRESULT resolve_hostname( const WCHAR *, USHORT, struct sockaddr *, int * ) DECLSPEC_HIDDEN; -HRESULT channel_accept_tcp( SOCKET, WS_CHANNEL * ) DECLSPEC_HIDDEN; -HRESULT channel_accept_udp( SOCKET, WS_CHANNEL * ) DECLSPEC_HIDDEN; +HRESULT channel_accept_tcp( SOCKET, HANDLE, HANDLE, WS_CHANNEL * ) DECLSPEC_HIDDEN; +HRESULT channel_accept_udp( SOCKET, HANDLE, HANDLE, WS_CHANNEL * ) DECLSPEC_HIDDEN; diff --git a/dlls/webservices/tests/listener.c b/dlls/webservices/tests/listener.c index 929b197..10539f9 100644 --- a/dlls/webservices/tests/listener.c +++ b/dlls/webservices/tests/listener.c @@ -282,6 +282,9 @@ static DWORD CALLBACK listener_proc( void *arg ) hr = WsAcceptChannel( listener, channel, NULL, NULL ); ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsAcceptChannel( listener, channel, NULL, NULL ); + ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr ); + hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL ); ok( hr == S_OK, "got %08x\n", hr );