[02/10] webservices: Implement WsOpenListener and WsCloseListener.

Hans Leidekker hans at codeweavers.com
Thu Apr 20 03:45:44 CDT 2017


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/Makefile.in      |   2 +-
 dlls/webservices/listener.c       | 187 ++++++++++++++++++++++++++++++++++++++
 dlls/webservices/tests/listener.c |  76 ++++++++++++++++
 dlls/webservices/webservices.spec |   4 +-
 4 files changed, 266 insertions(+), 3 deletions(-)

diff --git a/dlls/webservices/Makefile.in b/dlls/webservices/Makefile.in
index 70ca1fcc63..f201d38564 100644
--- a/dlls/webservices/Makefile.in
+++ b/dlls/webservices/Makefile.in
@@ -1,6 +1,6 @@
 MODULE    = webservices.dll
 IMPORTLIB = webservices
-IMPORTS   = winhttp rpcrt4 user32
+IMPORTS   = winhttp rpcrt4 user32 ws2_32
 
 C_SRCS = \
 	channel.c \
diff --git a/dlls/webservices/listener.c b/dlls/webservices/listener.c
index 4adddf4af5..a236ab954c 100644
--- a/dlls/webservices/listener.c
+++ b/dlls/webservices/listener.c
@@ -20,6 +20,7 @@
 
 #include "windef.h"
 #include "winbase.h"
+#include "ws2tcpip.h"
 #include "webservices.h"
 
 #include "wine/debug.h"
@@ -29,6 +30,23 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
 
+static BOOL winsock_loaded;
+
+static BOOL WINAPI winsock_startup( INIT_ONCE *once, void *param, void **ctx )
+{
+    int ret;
+    WSADATA data;
+    if (!(ret = WSAStartup( MAKEWORD(1,1), &data ))) winsock_loaded = TRUE;
+    else ERR( "WSAStartup failed: %d\n", ret );
+    return TRUE;
+}
+
+static void winsock_init(void)
+{
+    static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
+    InitOnceExecuteOnce( &once, winsock_startup, NULL, NULL );
+}
+
 static const struct prop_desc listener_props[] =
 {
     { sizeof(ULONG), FALSE },                               /* WS_LISTENER_PROPERTY_LISTEN_BACKLOG */
@@ -57,6 +75,7 @@ struct listener
     WS_CHANNEL_TYPE         type;
     WS_CHANNEL_BINDING      binding;
     WS_LISTENER_STATE       state;
+    SOCKET                  socket;
     ULONG                   prop_count;
     struct prop             prop[sizeof(listener_props)/sizeof(listener_props[0])];
 };
@@ -80,8 +99,16 @@ static struct listener *alloc_listener(void)
     return ret;
 }
 
+static void reset_listener( struct listener *listener )
+{
+    closesocket( listener->socket );
+    listener->socket = -1;
+    listener->state  = WS_LISTENER_STATE_CREATED;
+}
+
 static void free_listener( struct listener *listener )
 {
+    reset_listener( listener );
     listener->cs.DebugInfo->Spare[0] = 0;
     DeleteCriticalSection( &listener->cs );
     heap_free( listener );
@@ -109,6 +136,7 @@ static HRESULT create_listener( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding
 
     listener->type    = type;
     listener->binding = binding;
+    listener->socket  = -1;
 
     *ret = listener;
     return S_OK;
@@ -173,6 +201,165 @@ void WINAPI WsFreeListener( WS_LISTENER *handle )
     free_listener( listener );
 }
 
+static HRESULT resolve_hostname( const WCHAR *host, USHORT port, struct sockaddr *addr, int *addr_len )
+{
+    static const WCHAR fmtW[] = {'%','u',0};
+    WCHAR service[6];
+    ADDRINFOW *res, *info;
+    HRESULT hr = WS_E_ADDRESS_NOT_AVAILABLE;
+
+    *addr_len = 0;
+    sprintfW( service, fmtW, port );
+    if (GetAddrInfoW( host, service, NULL, &res )) return HRESULT_FROM_WIN32( WSAGetLastError() );
+
+    info = res;
+    while (info && info->ai_family != AF_INET && info->ai_family != AF_INET6) info = info->ai_next;
+    if (info)
+    {
+        memcpy( addr, info->ai_addr, info->ai_addrlen );
+        *addr_len = info->ai_addrlen;
+        hr = S_OK;
+    }
+
+    FreeAddrInfoW( res );
+    return hr;
+}
+
+static HRESULT parse_url( const WS_STRING *str, WCHAR **host, USHORT *port )
+{
+    WS_HEAP *heap;
+    WS_NETTCP_URL *url;
+    HRESULT hr;
+
+    if ((hr = WsCreateHeap( 1 << 8, 0, NULL, 0, &heap, NULL )) != S_OK) return hr;
+    if ((hr = WsDecodeUrl( str, 0, heap, (WS_URL **)&url, NULL )) != S_OK)
+    {
+        WsFreeHeap( heap );
+        return hr;
+    }
+
+    if (url->host.length == 1 && (url->host.chars[0] == '+' || url->host.chars[0] == '*')) *host = NULL;
+    else
+    {
+        if (!(*host = heap_alloc( (url->host.length + 1) * sizeof(WCHAR) )))
+        {
+            WsFreeHeap( heap );
+            return E_OUTOFMEMORY;
+        }
+        memcpy( *host, url->host.chars, url->host.length * sizeof(WCHAR) );
+        (*host)[url->host.length] = 0;
+    }
+    *port = url->port;
+
+    WsFreeHeap( heap );
+    return hr;
+}
+
+static HRESULT open_listener( struct listener *listener, const WS_STRING *url )
+{
+    struct sockaddr_storage storage;
+    struct sockaddr *addr = (struct sockaddr *)&storage;
+    int addr_len;
+    WCHAR *host;
+    USHORT port;
+    HRESULT hr;
+
+    if ((hr = parse_url( url, &host, &port )) != S_OK) return hr;
+
+    winsock_init();
+
+    hr = resolve_hostname( host, port, addr, &addr_len );
+    heap_free( host );
+    if (hr != S_OK) return hr;
+
+    if ((listener->socket = socket( addr->sa_family, SOCK_STREAM, 0 )) == -1)
+        return HRESULT_FROM_WIN32( WSAGetLastError() );
+
+    if (bind( listener->socket, addr, addr_len ) < 0)
+    {
+        closesocket( listener->socket );
+        listener->socket = -1;
+        return HRESULT_FROM_WIN32( WSAGetLastError() );
+    }
+
+    if (listen( listener->socket, 0 ) < 0)
+    {
+        closesocket( listener->socket );
+        listener->socket = -1;
+        return HRESULT_FROM_WIN32( WSAGetLastError() );
+    }
+
+    listener->state = WS_LISTENER_STATE_OPEN;
+    return S_OK;
+}
+
+/**************************************************************************
+ *          WsOpenListener		[webservices.@]
+ */
+HRESULT WINAPI WsOpenListener( WS_LISTENER *handle, WS_STRING *url, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
+{
+    struct listener *listener = (struct listener *)handle;
+    HRESULT hr;
+
+    TRACE( "%p %s %p %p\n", handle, url ? debugstr_wn(url->chars, url->length) : "null", ctx, error );
+    if (error) FIXME( "ignoring error parameter\n" );
+    if (ctx) FIXME( "ignoring ctx parameter\n" );
+
+    if (!listener || !url) return E_INVALIDARG;
+
+    EnterCriticalSection( &listener->cs );
+
+    if (listener->magic != LISTENER_MAGIC)
+    {
+        LeaveCriticalSection( &listener->cs );
+        return E_INVALIDARG;
+    }
+
+    if (listener->state != WS_LISTENER_STATE_CREATED)
+    {
+        LeaveCriticalSection( &listener->cs );
+        return WS_E_INVALID_OPERATION;
+    }
+
+    hr = open_listener( listener, url );
+
+    LeaveCriticalSection( &listener->cs );
+    return hr;
+}
+
+static void close_listener( struct listener *listener )
+{
+    reset_listener( listener );
+    listener->state = WS_LISTENER_STATE_CLOSED;
+}
+
+/**************************************************************************
+ *          WsCloseListener		[webservices.@]
+ */
+HRESULT WINAPI WsCloseListener( WS_LISTENER *handle, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
+{
+    struct listener *listener = (struct listener *)handle;
+
+    TRACE( "%p %p %p\n", handle, ctx, error );
+    if (error) FIXME( "ignoring error parameter\n" );
+    if (ctx) FIXME( "ignoring ctx parameter\n" );
+
+    if (!listener) return E_INVALIDARG;
+
+    EnterCriticalSection( &listener->cs );
+
+    if (listener->magic != LISTENER_MAGIC)
+    {
+        LeaveCriticalSection( &listener->cs );
+        return E_INVALIDARG;
+    }
+
+    close_listener( listener );
+
+    LeaveCriticalSection( &listener->cs );
+    return S_OK;
+}
+
 /**************************************************************************
  *          WsGetListenerProperty		[webservices.@]
  */
diff --git a/dlls/webservices/tests/listener.c b/dlls/webservices/tests/listener.c
index 901a9a0d08..ab2fba9c04 100644
--- a/dlls/webservices/tests/listener.c
+++ b/dlls/webservices/tests/listener.c
@@ -79,7 +79,83 @@ static void test_WsCreateListener(void)
     WsFreeListener( listener );
 }
 
+static void test_WsOpenListener(void)
+{
+    WCHAR str[] =
+        {'n','e','t','.','t','c','p',':','/','/','+',':','2','0','1','7','/','p','a','t','h'};
+    WCHAR str2[] =
+        {'n','e','t','.','t','c','p',':','/','/','l','o','c','a','l','h','o','s','t',':','2','0','1','7'};
+    WCHAR str3[] =
+        {'n','e','t','.','t','c','p',':','/','/','1','2','7','.','0','.','0','.','1',':','2','0','1','7'};
+    WS_STRING url;
+    WS_LISTENER *listener;
+    HRESULT hr;
+
+    hr = WsOpenListener( NULL, NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = WsCreateListener( WS_CHANNEL_TYPE_DUPLEX_SESSION, WS_TCP_CHANNEL_BINDING, NULL, 0, NULL, &listener, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsCloseListener( listener, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    WsFreeListener( listener );
+
+    hr = WsCreateListener( WS_CHANNEL_TYPE_DUPLEX_SESSION, WS_TCP_CHANNEL_BINDING, NULL, 0, NULL, &listener, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsOpenListener( listener, NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    url.length = sizeof(str)/sizeof(str[0]);
+    url.chars  = str;
+    hr = WsOpenListener( NULL, &url, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = WsOpenListener( listener, &url, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsOpenListener( listener, &url, NULL, NULL );
+    ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
+
+    hr = WsCloseListener( listener, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    WsFreeListener( listener );
+
+    hr = WsCreateListener( WS_CHANNEL_TYPE_DUPLEX_SESSION, WS_TCP_CHANNEL_BINDING, NULL, 0, NULL, &listener, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    url.length = sizeof(str2)/sizeof(str2[0]);
+    url.chars  = str2;
+    hr = WsOpenListener( listener, &url, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsCloseListener( listener, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    WsFreeListener( listener );
+
+    hr = WsCreateListener( WS_CHANNEL_TYPE_DUPLEX_SESSION, WS_TCP_CHANNEL_BINDING, NULL, 0, NULL, &listener, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    url.length = sizeof(str3)/sizeof(str3[0]);
+    url.chars  = str3;
+    hr = WsOpenListener( listener, &url, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsCloseListener( listener, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsCloseListener( NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    WsFreeListener( listener );
+}
+
 START_TEST(listener)
 {
     test_WsCreateListener();
+    test_WsOpenListener();
 }
diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec
index 7e8dbee583..ff35777b8e 100644
--- a/dlls/webservices/webservices.spec
+++ b/dlls/webservices/webservices.spec
@@ -14,7 +14,7 @@
 @ stdcall WsCall(ptr ptr ptr ptr ptr long ptr ptr)
 @ stub WsCheckMustUnderstandHeaders
 @ stdcall WsCloseChannel(ptr ptr ptr)
-@ stub WsCloseListener
+@ stdcall WsCloseListener(ptr ptr ptr)
 @ stub WsCloseServiceHost
 @ stdcall WsCloseServiceProxy(ptr ptr ptr)
 @ stub WsCombineUrl
@@ -96,7 +96,7 @@
 @ stdcall WsMoveReader(ptr long ptr ptr)
 @ stdcall WsMoveWriter(ptr long ptr ptr)
 @ stdcall WsOpenChannel(ptr ptr ptr ptr)
-@ stub WsOpenListener
+@ stdcall WsOpenListener(ptr ptr ptr ptr)
 @ stub WsOpenServiceHost
 @ stdcall WsOpenServiceProxy(ptr ptr ptr ptr)
 @ stub WsPullBytes
-- 
2.11.0




More information about the wine-patches mailing list