webservices: Allow listeners to be cancelled.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2017-05-10 14:26:15 +02:00 committed by Alexandre Julliard
parent 5f7848595f
commit 350cf6654e
4 changed files with 116 additions and 38 deletions

View File

@ -1168,39 +1168,39 @@ HRESULT WINAPI WsWriteMessageEnd( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_
return hr; return hr;
} }
HRESULT channel_accept_tcp( SOCKET socket, WS_CHANNEL *handle ) static HRESULT sock_accept( SOCKET socket, HANDLE wait, HANDLE cancel, SOCKET *ret )
{ {
struct channel *channel = (struct channel *)handle; HANDLE handles[] = { wait, cancel };
ULONG nonblocking = 0;
HRESULT hr = S_OK;
EnterCriticalSection( &channel->cs ); if (WSAEventSelect( socket, handles[0], FD_ACCEPT )) return HRESULT_FROM_WIN32( WSAGetLastError() );
if (channel->magic != CHANNEL_MAGIC) switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE ))
{ {
LeaveCriticalSection( &channel->cs ); case 0:
return E_INVALIDARG; 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;
} }
if ((channel->u.tcp.socket = accept( socket, NULL, NULL )) == -1) return hr;
{
LeaveCriticalSection( &channel->cs );
return HRESULT_FROM_WIN32( WSAGetLastError() );
}
LeaveCriticalSection( &channel->cs );
return S_OK;
} }
static HRESULT sock_wait( SOCKET socket ) HRESULT channel_accept_tcp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle )
{
fd_set read;
FD_ZERO( &read );
FD_SET( socket, &read );
if (select( socket + 1, &read, NULL, NULL, NULL ) < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
return S_OK;
}
HRESULT channel_accept_udp( SOCKET socket, WS_CHANNEL *handle )
{ {
struct channel *channel = (struct channel *)handle; struct channel *channel = (struct channel *)handle;
HRESULT hr; HRESULT hr;
@ -1213,7 +1213,54 @@ HRESULT channel_accept_udp( SOCKET socket, WS_CHANNEL *handle )
return E_INVALIDARG; return E_INVALIDARG;
} }
if ((hr = sock_wait( socket )) == S_OK) channel->u.udp.socket = socket; hr = sock_accept( socket, wait, cancel, &channel->u.tcp.socket );
LeaveCriticalSection( &channel->cs );
return hr;
}
static HRESULT sock_wait( SOCKET socket, HANDLE wait, HANDLE cancel )
{
HANDLE handles[] = { wait, cancel };
ULONG nonblocking = 0;
HRESULT hr;
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, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle )
{
struct channel *channel = (struct channel *)handle;
HRESULT hr;
EnterCriticalSection( &channel->cs );
if (channel->magic != CHANNEL_MAGIC)
{
LeaveCriticalSection( &channel->cs );
return E_INVALIDARG;
}
if ((hr = sock_wait( socket, wait, cancel )) == S_OK) channel->u.udp.socket = socket;
LeaveCriticalSection( &channel->cs ); LeaveCriticalSection( &channel->cs );
return hr; return hr;

View File

@ -75,6 +75,9 @@ struct listener
WS_CHANNEL_TYPE type; WS_CHANNEL_TYPE type;
WS_CHANNEL_BINDING binding; WS_CHANNEL_BINDING binding;
WS_LISTENER_STATE state; WS_LISTENER_STATE state;
HANDLE wait;
HANDLE cancel;
WS_CHANNEL *channel;
union union
{ {
struct struct
@ -100,7 +103,18 @@ static struct listener *alloc_listener(void)
if (!(ret = heap_alloc_zero( size ))) return NULL; 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 ); InitializeCriticalSection( &ret->cs );
ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": listener.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 ) static void reset_listener( struct listener *listener )
{ {
listener->state = WS_LISTENER_STATE_CREATED; listener->state = WS_LISTENER_STATE_CREATED;
SetEvent( listener->cancel );
listener->channel = NULL;
switch (listener->binding) switch (listener->binding)
{ {
@ -132,6 +148,10 @@ static void reset_listener( struct listener *listener )
static void free_listener( struct listener *listener ) static void free_listener( struct listener *listener )
{ {
reset_listener( listener ); reset_listener( listener );
CloseHandle( listener->wait );
CloseHandle( listener->cancel );
listener->cs.DebugInfo->Spare[0] = 0; listener->cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection( &listener->cs ); DeleteCriticalSection( &listener->cs );
heap_free( listener ); heap_free( listener );
@ -569,7 +589,8 @@ HRESULT WINAPI WsAcceptChannel( WS_LISTENER *handle, WS_CHANNEL *channel_handle,
WS_ERROR *error ) WS_ERROR *error )
{ {
struct listener *listener = (struct listener *)handle; 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 ); TRACE( "%p %p %p %p\n", handle, channel_handle, ctx, error );
if (error) FIXME( "ignoring error parameter\n" ); if (error) FIXME( "ignoring error parameter\n" );
@ -585,27 +606,34 @@ HRESULT WINAPI WsAcceptChannel( WS_LISTENER *handle, WS_CHANNEL *channel_handle,
return E_INVALIDARG; return E_INVALIDARG;
} }
if (listener->state != WS_LISTENER_STATE_OPEN) if (listener->state != WS_LISTENER_STATE_OPEN || listener->channel)
{ {
LeaveCriticalSection( &listener->cs ); LeaveCriticalSection( &listener->cs );
return WS_E_INVALID_OPERATION; return WS_E_INVALID_OPERATION;
} }
wait = listener->wait;
cancel = listener->cancel;
listener->channel = channel_handle;
switch (listener->binding) switch (listener->binding)
{ {
case WS_TCP_CHANNEL_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: case WS_UDP_CHANNEL_BINDING:
/* hand over socket on success */ {
if ((hr = channel_accept_udp( listener->u.udp.socket, channel_handle )) == S_OK) SOCKET socket = listener->u.udp.socket;
listener->u.udp.socket = -1;
break;
LeaveCriticalSection( &listener->cs );
return channel_accept_udp( socket, wait, cancel, channel_handle );
}
default: default:
FIXME( "listener binding %u not supported\n", listener->binding ); FIXME( "listener binding %u not supported\n", listener->binding );
hr = E_NOTIMPL;
break; break;
} }

View File

@ -20,5 +20,5 @@
void winsock_init(void) DECLSPEC_HIDDEN; void winsock_init(void) DECLSPEC_HIDDEN;
HRESULT resolve_hostname( const WCHAR *, USHORT, struct sockaddr *, int * ) 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_tcp( SOCKET, HANDLE, HANDLE, WS_CHANNEL * ) DECLSPEC_HIDDEN;
HRESULT channel_accept_udp( SOCKET, WS_CHANNEL * ) DECLSPEC_HIDDEN; HRESULT channel_accept_udp( SOCKET, HANDLE, HANDLE, WS_CHANNEL * ) DECLSPEC_HIDDEN;

View File

@ -282,6 +282,9 @@ static DWORD CALLBACK listener_proc( void *arg )
hr = WsAcceptChannel( listener, channel, NULL, NULL ); hr = WsAcceptChannel( listener, channel, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr ); 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 ); hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL );
ok( hr == S_OK, "got %08x\n", hr ); ok( hr == S_OK, "got %08x\n", hr );