[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