webservices: Implement WsOpenListener and WsCloseListener.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
79be5ad469
commit
823aa24f85
|
@ -1,6 +1,6 @@
|
|||
MODULE = webservices.dll
|
||||
IMPORTLIB = webservices
|
||||
IMPORTS = winhttp rpcrt4 user32
|
||||
IMPORTS = winhttp rpcrt4 user32 ws2_32
|
||||
|
||||
C_SRCS = \
|
||||
channel.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.@]
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue