Hans Leidekker : webservices: Allow listeners to be cancelled.

Alexandre Julliard julliard at winehq.org
Wed May 10 17:23:15 CDT 2017


Module: wine
Branch: master
Commit: 350cf6654e186d52a1ebbf4cc1a7fcc20567a7e9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=350cf6654e186d52a1ebbf4cc1a7fcc20567a7e9

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Wed May 10 14:26:15 2017 +0200

webservices: Allow listeners to be cancelled.

Signed-off-by: Hans Leidekker <hans at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at 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 );
 




More information about the wine-cvs mailing list