webservices: Implement WsRequestReply.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2018-10-31 14:21:31 +01:00 committed by Alexandre Julliard
parent 57db798965
commit 5a58080a66
4 changed files with 260 additions and 61 deletions

View File

@ -2007,6 +2007,121 @@ HRESULT WINAPI WsReceiveMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_M
return hr;
}
static HRESULT request_reply( struct channel *channel, WS_MESSAGE *request,
const WS_MESSAGE_DESCRIPTION *request_desc, WS_WRITE_OPTION write_option,
const void *request_body, ULONG request_size, WS_MESSAGE *reply,
const WS_MESSAGE_DESCRIPTION *reply_desc, WS_READ_OPTION read_option,
WS_HEAP *heap, void *value, ULONG size )
{
HRESULT hr;
WsInitializeMessage( request, WS_REQUEST_MESSAGE, NULL, NULL );
if ((hr = WsAddressMessage( request, &channel->addr, NULL )) != S_OK) return hr;
if ((hr = message_set_action( request, request_desc->action )) != S_OK) return hr;
if ((hr = init_writer( channel )) != S_OK) return hr;
if ((hr = write_message( channel, request, request_desc->bodyElementDescription, write_option, request_body,
request_size )) != S_OK) return hr;
if ((hr = send_message( channel, request )) != S_OK) return hr;
return receive_message( channel, reply, &reply_desc, 1, WS_RECEIVE_OPTIONAL_MESSAGE, read_option, heap,
value, size, NULL );
}
struct request_reply
{
struct task task;
struct channel *channel;
WS_MESSAGE *request;
const WS_MESSAGE_DESCRIPTION *request_desc;
WS_WRITE_OPTION write_option;
const void *request_body;
ULONG request_size;
WS_MESSAGE *reply;
const WS_MESSAGE_DESCRIPTION *reply_desc;
WS_READ_OPTION read_option;
WS_HEAP *heap;
void *value;
ULONG size;
WS_ASYNC_CONTEXT ctx;
};
static void request_reply_proc( struct task *task )
{
struct request_reply *r = (struct request_reply *)task;
HRESULT hr;
hr = request_reply( r->channel, r->request, r->request_desc, r->write_option, r->request_body, r->request_size,
r->reply, r->reply_desc, r->read_option, r->heap, r->value, r->size );
TRACE( "calling %p(%08x)\n", r->ctx.callback, hr );
r->ctx.callback( hr, WS_LONG_CALLBACK, r->ctx.callbackState );
TRACE( "%p returned\n", r->ctx.callback );
}
static HRESULT queue_request_reply( struct channel *channel, WS_MESSAGE *request,
const WS_MESSAGE_DESCRIPTION *request_desc, WS_WRITE_OPTION write_option,
const void *request_body, ULONG request_size, WS_MESSAGE *reply,
const WS_MESSAGE_DESCRIPTION *reply_desc, WS_READ_OPTION read_option,
WS_HEAP *heap, void *value, ULONG size, const WS_ASYNC_CONTEXT *ctx )
{
struct request_reply *r;
if (!(r = heap_alloc( sizeof(*r) ))) return E_OUTOFMEMORY;
r->task.proc = request_reply_proc;
r->channel = channel;
r->request = request;
r->request_desc = request_desc;
r->write_option = write_option;
r->request_body = request_body;
r->request_size = request_size;
r->reply = reply;
r->reply_desc = reply_desc;
r->read_option = read_option;
r->heap = heap;
r->value = value;
r->size = size;
r->ctx = *ctx;
return queue_task( &channel->recv_q, &r->task );
}
/**************************************************************************
* WsRequestReply [webservices.@]
*/
HRESULT WINAPI WsRequestReply( WS_CHANNEL *handle, WS_MESSAGE *request, const WS_MESSAGE_DESCRIPTION *request_desc,
WS_WRITE_OPTION write_option, const void *request_body, ULONG request_size,
WS_MESSAGE *reply, const WS_MESSAGE_DESCRIPTION *reply_desc, WS_READ_OPTION read_option,
WS_HEAP *heap, void *value, ULONG size, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
{
struct channel *channel = (struct channel *)handle;
HRESULT hr;
TRACE( "%p %p %p %08x %p %u %p %p %08x %p %p %u %p %p\n", handle, request, request_desc, write_option,
request_body, request_size, reply, reply_desc, read_option, heap, value, size, ctx, error );
if (error) FIXME( "ignoring error parameter\n" );
if (ctx) FIXME( "ignoring ctx parameter\n" );
if (!channel || !request || !reply) return E_INVALIDARG;
EnterCriticalSection( &channel->cs );
if (channel->magic != CHANNEL_MAGIC)
{
LeaveCriticalSection( &channel->cs );
return E_INVALIDARG;
}
if (ctx)
hr = queue_request_reply( channel, request, request_desc, write_option, request_body, request_size, reply,
reply_desc, read_option, heap, value, size, ctx );
else
hr = request_reply( channel, request, request_desc, write_option, request_body, request_size, reply,
reply_desc, read_option, heap, value, size );
LeaveCriticalSection( &channel->cs );
TRACE( "returning %08x\n", hr );
return hr;
}
/**************************************************************************
* WsReadMessageStart [webservices.@]
*/

View File

@ -433,16 +433,21 @@ static void test_WsResetListener(void)
WsFreeListener( listener );
}
static const WCHAR fmt_soap_udp[] =
{'s','o','a','p','.','u','d','p',':','/','/','l','o','c','a','l','h','o','s','t',':','%','u',0};
static const WCHAR fmt_net_tcp[] =
{'n','e','t','.','t','c','p',':','/','/','l','o','c','a','l','h','o','s','t',':','%','u',0};
struct listener_info
{
int port;
HANDLE wait;
WS_CHANNEL_BINDING binding;
WS_CHANNEL_TYPE type;
void (*test_func)( WS_CHANNEL * );
void (*server_func)( WS_CHANNEL * );
};
static void client_message_read_write( WS_CHANNEL *channel )
static void server_message_read_write( WS_CHANNEL *channel )
{
WS_MESSAGE *msg;
HRESULT hr;
@ -476,10 +481,8 @@ static void client_message_read_write( WS_CHANNEL *channel )
WsFreeMessage( msg );
}
static void test_message_read_write( const struct listener_info *info )
static void client_message_read_write( const struct listener_info *info )
{
static const WCHAR fmt[] =
{'s','o','a','p','.','u','d','p',':','/','/','l','o','c','a','l','h','o','s','t',':','%','u',0};
WS_ENDPOINT_ADDRESS addr;
WCHAR buf[64];
WS_CHANNEL *channel;
@ -491,7 +494,7 @@ static void test_message_read_write( const struct listener_info *info )
ok( hr == S_OK, "got %08x\n", hr );
memset( &addr, 0, sizeof(addr) );
addr.url.length = wsprintfW( buf, fmt, info->port );
addr.url.length = wsprintfW( buf, fmt_soap_udp, info->port );
addr.url.chars = buf;
hr = WsOpenChannel( channel, &addr, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
@ -545,7 +548,7 @@ struct async_test
HANDLE wait;
};
static void CALLBACK callback_duplex_session( HRESULT hr, WS_CALLBACK_MODEL model, void *state )
static void CALLBACK async_callback( HRESULT hr, WS_CALLBACK_MODEL model, void *state )
{
struct async_test *test = state;
@ -555,7 +558,7 @@ static void CALLBACK callback_duplex_session( HRESULT hr, WS_CALLBACK_MODEL mode
SetEvent( test->wait );
}
static void client_duplex_session( WS_CHANNEL *channel )
static void server_duplex_session( WS_CHANNEL *channel )
{
WS_XML_STRING action = {6, (BYTE *)"action"}, localname = {9, (BYTE *)"localname"}, ns = {2, (BYTE *)"ns"};
WS_ELEMENT_DESCRIPTION desc_body;
@ -580,7 +583,7 @@ static void client_duplex_session( WS_CHANNEL *channel )
test.call_count = 0;
test.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
ctx.callback = callback_duplex_session;
ctx.callback = async_callback;
ctx.callbackState = &test;
hr = WsReceiveMessage( channel, msg, desc, 1, WS_RECEIVE_OPTIONAL_MESSAGE, WS_READ_REQUIRED_VALUE,
@ -612,10 +615,8 @@ static void client_duplex_session( WS_CHANNEL *channel )
WsFreeMessage( msg2 );
}
static void test_duplex_session( const struct listener_info *info )
static void client_duplex_session( const struct listener_info *info )
{
static const WCHAR fmt[] =
{'n','e','t','.','t','c','p',':','/','/','l','o','c','a','l','h','o','s','t',':','%','u',0};
WS_XML_STRING action = {6, (BYTE *)"action"}, localname = {9, (BYTE *)"localname"}, ns = {2, (BYTE *)"ns"};
WS_ELEMENT_DESCRIPTION desc_body;
WS_MESSAGE_DESCRIPTION desc;
@ -634,7 +635,7 @@ static void test_duplex_session( const struct listener_info *info )
ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
memset( &addr, 0, sizeof(addr) );
addr.url.length = wsprintfW( buf, fmt, info->port );
addr.url.length = wsprintfW( buf, fmt_net_tcp, info->port );
addr.url.chars = buf;
hr = WsOpenChannel( channel, &addr, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
@ -675,7 +676,7 @@ static void test_duplex_session( const struct listener_info *info )
WsFreeChannel( channel );
}
static void client_accept_channel( WS_CHANNEL *channel )
static void server_accept_channel( WS_CHANNEL *channel )
{
WS_XML_STRING localname = {9, (BYTE *)"localname"}, ns = {2, (BYTE *)"ns"}, action = {6, (BYTE *)"action"};
WS_ELEMENT_DESCRIPTION body;
@ -704,13 +705,9 @@ static void client_accept_channel( WS_CHANNEL *channel )
WsFreeMessage( msg );
}
static void test_WsAcceptChannel( const struct listener_info *info )
static void client_accept_channel( const struct listener_info *info )
{
static const WCHAR fmt_tcp[] =
{'n','e','t','.','t','c','p',':','/','/','l','o','c','a','l','h','o','s','t',':','%','u',0};
static const WCHAR fmt_udp[] =
{'s','o','a','p','.','u','d','p',':','/','/','l','o','c','a','l','h','o','s','t',':','%','u',0};
const WCHAR *fmt = (info->binding == WS_TCP_CHANNEL_BINDING) ? fmt_tcp : fmt_udp;
const WCHAR *fmt = (info->binding == WS_TCP_CHANNEL_BINDING) ? fmt_net_tcp : fmt_soap_udp;
WS_XML_STRING localname = {9, (BYTE *)"localname"}, ns = {2, (BYTE *)"ns"}, action = {6, (BYTE *)"action"};
WCHAR buf[64];
WS_LISTENER *listener;
@ -773,14 +770,104 @@ static void test_WsAcceptChannel( const struct listener_info *info )
WsFreeChannel( channel );
}
static void server_request_reply( WS_CHANNEL *channel )
{
WS_XML_STRING localname = {9, (BYTE *)"localname"}, ns = {2, (BYTE *)"ns"};
WS_XML_STRING req_action = {7, (BYTE *)"request"}, reply_action= {5, (BYTE *)"reply"};
WS_ELEMENT_DESCRIPTION body;
WS_MESSAGE_DESCRIPTION in_desc, out_desc;
const WS_MESSAGE_DESCRIPTION *desc[1];
WS_MESSAGE *msg;
INT32 val = 0;
HRESULT hr;
hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL );
ok( hr == S_OK, "got %08x\n", hr );
body.elementLocalName = &localname;
body.elementNs = &ns;
body.type = WS_INT32_TYPE;
body.typeDescription = NULL;
in_desc.action = &req_action;
in_desc.bodyElementDescription = &body;
desc[0] = &in_desc;
hr = WsReceiveMessage( channel, msg, desc, 1, WS_RECEIVE_REQUIRED_MESSAGE, WS_READ_REQUIRED_VALUE,
NULL, &val, sizeof(val), NULL, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
ok( val == -1, "got %d\n", val );
WsFreeMessage( msg );
hr = WsCreateMessageForChannel( channel, NULL, 0, &msg, NULL );
ok( hr == S_OK, "got %08x\n", hr );
out_desc.action = &reply_action;
out_desc.bodyElementDescription = &body;
hr = WsSendMessage( channel, msg, &out_desc, WS_WRITE_REQUIRED_VALUE, &val, sizeof(val), NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
WsFreeMessage( msg );
}
static void client_request_reply( const struct listener_info *info )
{
WS_XML_STRING localname = {9, (BYTE *)"localname"}, ns = {2, (BYTE *)"ns"};
WS_XML_STRING req_action = {7, (BYTE *)"request"}, reply_action= {5, (BYTE *)"reply"};
WCHAR buf[64];
WS_CHANNEL *channel;
WS_MESSAGE *req, *reply;
WS_ENDPOINT_ADDRESS addr;
WS_ELEMENT_DESCRIPTION body;
WS_MESSAGE_DESCRIPTION req_desc, reply_desc;
INT32 val_in = -1, val_out = 0;
HRESULT hr;
hr = WsCreateChannel( info->type, info->binding, NULL, 0, NULL, &channel, NULL );
ok( hr == S_OK, "got %08x\n", hr );
memset( &addr, 0, sizeof(addr) );
addr.url.length = wsprintfW( buf, fmt_net_tcp, info->port );
addr.url.chars = buf;
hr = WsOpenChannel( channel, &addr, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsCreateMessageForChannel( channel, NULL, 0, &req, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsCreateMessageForChannel( channel, NULL, 0, &reply, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsInitializeMessage( req, WS_BLANK_MESSAGE, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
body.elementLocalName = &localname;
body.elementNs = &ns;
body.type = WS_INT32_TYPE;
body.typeDescription = NULL;
req_desc.action = &req_action;
req_desc.bodyElementDescription = &body;
reply_desc.action = &reply_action;
reply_desc.bodyElementDescription = &body;
hr = WsRequestReply( channel, req, &req_desc, WS_WRITE_REQUIRED_VALUE, &val_in, sizeof(val_in), reply,
&reply_desc, WS_READ_REQUIRED_VALUE, NULL, &val_out, sizeof(val_out), NULL, NULL );
ok( val_out == -1, "got %d\n", val_out );
hr = WsCloseChannel( channel, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
WsFreeMessage( req );
WsFreeMessage( reply );
WsFreeChannel( channel );
}
static DWORD CALLBACK listener_proc( void *arg )
{
static const WCHAR fmt_tcp[] =
{'n','e','t','.','t','c','p',':','/','/','l','o','c','a','l','h','o','s','t',':','%','u',0};
static const WCHAR fmt_udp[] =
{'s','o','a','p','.','u','d','p',':','/','/','l','o','c','a','l','h','o','s','t',':','%','u',0};
struct listener_info *info = arg;
const WCHAR *fmt = (info->binding == WS_TCP_CHANNEL_BINDING) ? fmt_tcp : fmt_udp;
const WCHAR *fmt = (info->binding == WS_TCP_CHANNEL_BINDING) ? fmt_net_tcp : fmt_soap_udp;
WS_LISTENER *listener;
WS_CHANNEL *channel;
WCHAR buf[64];
@ -803,7 +890,7 @@ static DWORD CALLBACK listener_proc( void *arg )
hr = WsAcceptChannel( listener, channel, NULL, NULL );
ok( hr == S_OK, "got %08x\n", hr );
info->test_func( channel );
info->server_func( channel );
SetEvent( info->wait );
@ -956,6 +1043,22 @@ START_TEST(channel)
struct listener_info info;
HANDLE thread;
HRESULT hr;
unsigned int i;
static const struct test
{
WS_CHANNEL_BINDING binding;
WS_CHANNEL_TYPE type;
void (*server_func)( WS_CHANNEL * );
void (*client_func)( const struct listener_info * );
}
tests[] =
{
{ WS_UDP_CHANNEL_BINDING, WS_CHANNEL_TYPE_DUPLEX, server_message_read_write, client_message_read_write },
{ WS_TCP_CHANNEL_BINDING, WS_CHANNEL_TYPE_DUPLEX_SESSION, server_duplex_session, client_duplex_session },
{ WS_UDP_CHANNEL_BINDING, WS_CHANNEL_TYPE_DUPLEX, server_accept_channel, client_accept_channel },
{ WS_TCP_CHANNEL_BINDING, WS_CHANNEL_TYPE_DUPLEX_SESSION, server_accept_channel, client_accept_channel },
{ WS_TCP_CHANNEL_BINDING, WS_CHANNEL_TYPE_DUPLEX_SESSION, server_request_reply, client_request_reply },
};
if (firewall_enabled)
{
@ -979,42 +1082,20 @@ START_TEST(channel)
test_WsCreateChannelForListener();
test_WsResetListener();
info.port = 7533;
info.wait = CreateEventW( NULL, 0, 0, NULL );
info.type = WS_CHANNEL_TYPE_DUPLEX;
info.binding = WS_UDP_CHANNEL_BINDING;
info.test_func = client_message_read_write;
info.port = 7533;
info.wait = CreateEventW( NULL, 0, 0, NULL );
thread = start_listener( &info );
test_message_read_write( &info );
WaitForSingleObject( thread, 3000 );
CloseHandle(thread);
for (i = 0; i < ARRAY_SIZE(tests); i++)
{
info.binding = tests[i].binding;
info.type = tests[i].type;
info.server_func = tests[i].server_func;
info.type = WS_CHANNEL_TYPE_DUPLEX_SESSION;
info.binding = WS_TCP_CHANNEL_BINDING;
info.test_func = client_duplex_session;
thread = start_listener( &info );
test_duplex_session( &info );
WaitForSingleObject( thread, 3000 );
CloseHandle(thread);
info.type = WS_CHANNEL_TYPE_DUPLEX;
info.binding = WS_UDP_CHANNEL_BINDING;
info.test_func = client_accept_channel;
thread = start_listener( &info );
test_WsAcceptChannel( &info );
WaitForSingleObject( thread, 3000 );
CloseHandle(thread);
info.type = WS_CHANNEL_TYPE_DUPLEX_SESSION;
info.binding = WS_TCP_CHANNEL_BINDING;
thread = start_listener( &info );
test_WsAcceptChannel( &info );
WaitForSingleObject( thread, 3000 );
CloseHandle(thread);
thread = start_listener( &info );
tests[i].client_func( &info );
WaitForSingleObject( thread, 3000 );
CloseHandle( thread );
}
if (firewall_enabled) set_firewall( APP_REMOVE );
}

View File

@ -131,7 +131,7 @@
@ stdcall WsRemoveHeader(ptr long ptr)
@ stdcall WsRemoveMappedHeader(ptr ptr ptr)
@ stub WsRemoveNode
@ stub WsRequestReply
@ stdcall WsRequestReply(ptr ptr ptr long ptr long ptr ptr long ptr ptr long ptr ptr)
@ stub WsRequestSecurityToken
@ stdcall WsResetChannel(ptr ptr)
@ stdcall WsResetError(ptr)

View File

@ -1701,6 +1701,9 @@ HRESULT WINAPI WsRemoveCustomHeader(WS_MESSAGE*, const WS_XML_STRING*, const WS_
HRESULT WINAPI WsRemoveHeader(WS_MESSAGE*, WS_HEADER_TYPE, WS_ERROR*);
HRESULT WINAPI WsRemoveMappedHeader(WS_MESSAGE*, const WS_XML_STRING*, WS_ERROR*);
HRESULT WINAPI WsRemoveNode(const WS_XML_NODE_POSITION*, WS_ERROR*);
HRESULT WINAPI WsRequestReply(WS_CHANNEL*, WS_MESSAGE*, const WS_MESSAGE_DESCRIPTION*, WS_WRITE_OPTION,
const void*, ULONG, WS_MESSAGE*, const WS_MESSAGE_DESCRIPTION*, WS_READ_OPTION,
WS_HEAP*, void*, ULONG, const WS_ASYNC_CONTEXT*, WS_ERROR*);
HRESULT WINAPI WsResetChannel(WS_CHANNEL*, WS_ERROR*);
HRESULT WINAPI WsResetMessage(WS_MESSAGE*, WS_ERROR*);
HRESULT WINAPI WsResetError(WS_ERROR*);