[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