[1/3] webservices: Allow listeners to be cancelled.
Hans Leidekker
hans at codeweavers.com
Wed May 10 07:26:15 CDT 2017
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
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 aa78d1e762..9fb1944d37 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 7d49b73d32..5d6d1a82f2 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 6b30f64601..e03b91e622 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 929b1975a0..10539f9d9c 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 );
--
2.11.0
More information about the wine-patches
mailing list