[PATCH 6/6] webservices: Implement WsRequestReply.
Hans Leidekker
hans at codeweavers.com
Wed Oct 31 08:21:31 CDT 2018
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/webservices/channel.c | 115 +++++++++++++++++++++
dlls/webservices/tests/channel.c | 205 ++++++++++++++++++++++++++------------
dlls/webservices/webservices.spec | 2 +-
include/webservices.h | 3 +
4 files changed, 262 insertions(+), 63 deletions(-)
diff --git a/dlls/webservices/channel.c b/dlls/webservices/channel.c
index de84b0e66f..94c3dc1e99 100644
--- a/dlls/webservices/channel.c
+++ b/dlls/webservices/channel.c
@@ -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.@]
*/
diff --git a/dlls/webservices/tests/channel.c b/dlls/webservices/tests/channel.c
index db17893138..6a45671057 100644
--- a/dlls/webservices/tests/channel.c
+++ b/dlls/webservices/tests/channel.c
@@ -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;
-
- thread = start_listener( &info );
- test_message_read_write( &info );
- WaitForSingleObject( thread, 3000 );
- CloseHandle(thread);
-
- 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);
+ info.port = 7533;
+ info.wait = CreateEventW( NULL, 0, 0, NULL );
+
+ 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;
+
+ thread = start_listener( &info );
+ tests[i].client_func( &info );
+ WaitForSingleObject( thread, 3000 );
+ CloseHandle( thread );
+ }
if (firewall_enabled) set_firewall( APP_REMOVE );
}
diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec
index 8ba34b4209..30c97e3473 100644
--- a/dlls/webservices/webservices.spec
+++ b/dlls/webservices/webservices.spec
@@ -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)
diff --git a/include/webservices.h b/include/webservices.h
index 928819fc3d..6cafcc63d6 100644
--- a/include/webservices.h
+++ b/include/webservices.h
@@ -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*);
--
2.11.0
More information about the wine-devel
mailing list