Commit 823aa24f authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

webservices: Implement WsOpenListener and WsCloseListener.

parent 79be5ad4
MODULE = webservices.dll MODULE = webservices.dll
IMPORTLIB = webservices IMPORTLIB = webservices
IMPORTS = winhttp rpcrt4 user32 IMPORTS = winhttp rpcrt4 user32 ws2_32
C_SRCS = \ C_SRCS = \
channel.c \ channel.c \
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "ws2tcpip.h"
#include "webservices.h" #include "webservices.h"
#include "wine/debug.h" #include "wine/debug.h"
...@@ -29,6 +30,23 @@ ...@@ -29,6 +30,23 @@
WINE_DEFAULT_DEBUG_CHANNEL(webservices); 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[] = static const struct prop_desc listener_props[] =
{ {
{ sizeof(ULONG), FALSE }, /* WS_LISTENER_PROPERTY_LISTEN_BACKLOG */ { sizeof(ULONG), FALSE }, /* WS_LISTENER_PROPERTY_LISTEN_BACKLOG */
...@@ -57,6 +75,7 @@ struct listener ...@@ -57,6 +75,7 @@ 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;
SOCKET socket;
ULONG prop_count; ULONG prop_count;
struct prop prop[sizeof(listener_props)/sizeof(listener_props[0])]; struct prop prop[sizeof(listener_props)/sizeof(listener_props[0])];
}; };
...@@ -80,8 +99,16 @@ static struct listener *alloc_listener(void) ...@@ -80,8 +99,16 @@ static struct listener *alloc_listener(void)
return ret; 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 ) static void free_listener( struct listener *listener )
{ {
reset_listener( listener );
listener->cs.DebugInfo->Spare[0] = 0; listener->cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection( &listener->cs ); DeleteCriticalSection( &listener->cs );
heap_free( listener ); heap_free( listener );
...@@ -109,6 +136,7 @@ static HRESULT create_listener( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding ...@@ -109,6 +136,7 @@ static HRESULT create_listener( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding
listener->type = type; listener->type = type;
listener->binding = binding; listener->binding = binding;
listener->socket = -1;
*ret = listener; *ret = listener;
return S_OK; return S_OK;
...@@ -173,6 +201,165 @@ void WINAPI WsFreeListener( WS_LISTENER *handle ) ...@@ -173,6 +201,165 @@ void WINAPI WsFreeListener( WS_LISTENER *handle )
free_listener( listener ); 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.@] * WsGetListenerProperty [webservices.@]
*/ */
......
...@@ -79,7 +79,83 @@ static void test_WsCreateListener(void) ...@@ -79,7 +79,83 @@ static void test_WsCreateListener(void)
WsFreeListener( listener ); 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) START_TEST(listener)
{ {
test_WsCreateListener(); test_WsCreateListener();
test_WsOpenListener();
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
@ stdcall WsCall(ptr ptr ptr ptr ptr long ptr ptr) @ stdcall WsCall(ptr ptr ptr ptr ptr long ptr ptr)
@ stub WsCheckMustUnderstandHeaders @ stub WsCheckMustUnderstandHeaders
@ stdcall WsCloseChannel(ptr ptr ptr) @ stdcall WsCloseChannel(ptr ptr ptr)
@ stub WsCloseListener @ stdcall WsCloseListener(ptr ptr ptr)
@ stub WsCloseServiceHost @ stub WsCloseServiceHost
@ stdcall WsCloseServiceProxy(ptr ptr ptr) @ stdcall WsCloseServiceProxy(ptr ptr ptr)
@ stub WsCombineUrl @ stub WsCombineUrl
...@@ -96,7 +96,7 @@ ...@@ -96,7 +96,7 @@
@ stdcall WsMoveReader(ptr long ptr ptr) @ stdcall WsMoveReader(ptr long ptr ptr)
@ stdcall WsMoveWriter(ptr long ptr ptr) @ stdcall WsMoveWriter(ptr long ptr ptr)
@ stdcall WsOpenChannel(ptr ptr ptr ptr) @ stdcall WsOpenChannel(ptr ptr ptr ptr)
@ stub WsOpenListener @ stdcall WsOpenListener(ptr ptr ptr ptr)
@ stub WsOpenServiceHost @ stub WsOpenServiceHost
@ stdcall WsOpenServiceProxy(ptr ptr ptr ptr) @ stdcall WsOpenServiceProxy(ptr ptr ptr ptr)
@ stub WsPullBytes @ stub WsPullBytes
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment