2 * Copyright 2016 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "webservices.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
29 #include "webservices_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(webservices
);
33 static const struct prop_desc proxy_props
[] =
35 { sizeof(ULONG
), FALSE
, TRUE
}, /* WS_PROXY_PROPERTY_CALL_TIMEOUT */
36 { sizeof(WS_MESSAGE_PROPERTIES
), FALSE
}, /* WS_PROXY_PROPERTY_MESSAGE_PROPERTIES */
37 { sizeof(USHORT
), FALSE
, TRUE
}, /* WS_PROXY_PROPERTY_MAX_CALL_POOL_SIZE */
38 { sizeof(WS_SERVICE_PROXY_STATE
), TRUE
}, /* WS_PROXY_PROPERTY_STATE */
39 { sizeof(ULONG
), FALSE
, TRUE
}, /* WS_PROXY_PROPERTY_MAX_PENDING_CALLS */
40 { sizeof(ULONG
), FALSE
, TRUE
}, /* WS_PROXY_PROPERTY_MAX_CLOSE_TIMEOUT */
41 { sizeof(LANGID
), FALSE
, TRUE
}, /* WS_PROXY_FAULT_LANG_ID */
48 WS_SERVICE_PROXY_STATE state
;
51 struct prop prop
[ARRAY_SIZE( proxy_props
)];
54 #define PROXY_MAGIC (('P' << 24) | ('R' << 16) | ('O' << 8) | 'X')
56 static struct proxy
*alloc_proxy(void)
58 static const ULONG count
= ARRAY_SIZE( proxy_props
);
60 ULONG size
= sizeof(*ret
) + prop_size( proxy_props
, count
);
62 if (!(ret
= calloc( 1, size
))) return NULL
;
64 ret
->magic
= PROXY_MAGIC
;
65 InitializeCriticalSection( &ret
->cs
);
66 ret
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": proxy.cs");
68 prop_init( proxy_props
, count
, ret
->prop
, &ret
[1] );
69 ret
->prop_count
= count
;
73 static void reset_proxy( struct proxy
*proxy
)
75 WsResetChannel( proxy
->channel
, NULL
);
76 proxy
->state
= WS_SERVICE_PROXY_STATE_CREATED
;
79 static void free_proxy( struct proxy
*proxy
)
82 WsFreeChannel( proxy
->channel
);
84 proxy
->cs
.DebugInfo
->Spare
[0] = 0;
85 DeleteCriticalSection( &proxy
->cs
);
89 static HRESULT
create_proxy( WS_CHANNEL
*channel
, const WS_PROXY_PROPERTY
*properties
, ULONG count
,
90 WS_SERVICE_PROXY
**handle
)
96 if (!(proxy
= alloc_proxy())) return E_OUTOFMEMORY
;
98 for (i
= 0; i
< count
; i
++)
100 hr
= prop_set( proxy
->prop
, proxy
->prop_count
, properties
[i
].id
, properties
[i
].value
,
101 properties
[i
].valueSize
);
109 proxy
->channel
= channel
;
111 *handle
= (WS_SERVICE_PROXY
*)proxy
;
115 /**************************************************************************
116 * WsCreateServiceProxy [webservices.@]
118 HRESULT WINAPI
WsCreateServiceProxy( const WS_CHANNEL_TYPE type
, const WS_CHANNEL_BINDING binding
,
119 const WS_SECURITY_DESCRIPTION
*desc
,
120 const WS_PROXY_PROPERTY
*proxy_props
, ULONG proxy_props_count
,
121 const WS_CHANNEL_PROPERTY
*channel_props
,
122 const ULONG channel_props_count
, WS_SERVICE_PROXY
**handle
,
128 TRACE( "%u %u %p %p %lu %p %lu %p %p\n", type
, binding
, desc
, proxy_props
, proxy_props_count
,
129 channel_props
, channel_props_count
, handle
, error
);
130 if (error
) FIXME( "ignoring error parameter\n" );
131 if (desc
) FIXME( "ignoring security description\n" );
133 if (!handle
) return E_INVALIDARG
;
135 if ((hr
= WsCreateChannel( type
, binding
, channel_props
, channel_props_count
, NULL
, &channel
,
136 NULL
)) != S_OK
) return hr
;
138 if ((hr
= create_proxy( channel
, proxy_props
, proxy_props_count
, handle
)) != S_OK
)
140 WsFreeChannel( channel
);
144 TRACE( "created %p\n", *handle
);
148 /**************************************************************************
149 * WsCreateServiceProxyFromTemplate [webservices.@]
151 HRESULT WINAPI
WsCreateServiceProxyFromTemplate( WS_CHANNEL_TYPE channel_type
,
152 const WS_PROXY_PROPERTY
*properties
, const ULONG count
,
153 WS_BINDING_TEMPLATE_TYPE type
, void *value
, ULONG size
,
154 const void *desc
, ULONG desc_size
, WS_SERVICE_PROXY
**handle
,
157 const WS_CHANNEL_PROPERTY
*channel_props
= NULL
;
158 ULONG channel_props_count
= 0;
159 WS_CHANNEL_BINDING binding
;
163 TRACE( "%u %p %lu %u %p %lu %p %lu %p %p\n", channel_type
, properties
, count
, type
, value
, size
, desc
,
164 desc_size
, handle
, error
);
165 if (error
) FIXME( "ignoring error parameter\n" );
167 if (!desc
|| !handle
) return E_INVALIDARG
;
168 FIXME( "ignoring description\n" );
172 case WS_HTTP_BINDING_TEMPLATE_TYPE
:
174 WS_HTTP_BINDING_TEMPLATE
*http
= value
;
177 channel_props
= http
->channelProperties
.properties
;
178 channel_props_count
= http
->channelProperties
.propertyCount
;
180 binding
= WS_HTTP_CHANNEL_BINDING
;
183 case WS_HTTP_SSL_BINDING_TEMPLATE_TYPE
:
185 WS_HTTP_SSL_BINDING_TEMPLATE
*https
= value
;
188 channel_props
= https
->channelProperties
.properties
;
189 channel_props_count
= https
->channelProperties
.propertyCount
;
191 binding
= WS_HTTP_CHANNEL_BINDING
;
195 FIXME( "template type %u not implemented\n", type
);
199 if ((hr
= WsCreateChannel( channel_type
, binding
, channel_props
, channel_props_count
, NULL
,
200 &channel
, NULL
)) != S_OK
) return hr
;
202 if ((hr
= create_proxy( channel
, properties
, count
, handle
)) != S_OK
)
204 WsFreeChannel( channel
);
208 TRACE( "created %p\n", *handle
);
212 /**************************************************************************
213 * WsResetServiceProxy [webservices.@]
215 HRESULT WINAPI
WsResetServiceProxy( WS_SERVICE_PROXY
*handle
, WS_ERROR
*error
)
217 struct proxy
*proxy
= (struct proxy
*)handle
;
220 TRACE( "%p %p\n", handle
, error
);
221 if (error
) FIXME( "ignoring error parameter\n" );
223 if (!proxy
) return E_INVALIDARG
;
225 EnterCriticalSection( &proxy
->cs
);
227 if (proxy
->magic
!= PROXY_MAGIC
)
229 LeaveCriticalSection( &proxy
->cs
);
233 if (proxy
->state
!= WS_SERVICE_PROXY_STATE_CREATED
&& proxy
->state
!= WS_SERVICE_PROXY_STATE_CLOSED
)
234 hr
= WS_E_INVALID_OPERATION
;
236 reset_proxy( proxy
);
238 LeaveCriticalSection( &proxy
->cs
);
239 TRACE( "returning %#lx\n", hr
);
243 /**************************************************************************
244 * WsFreeServiceProxy [webservices.@]
246 void WINAPI
WsFreeServiceProxy( WS_SERVICE_PROXY
*handle
)
248 struct proxy
*proxy
= (struct proxy
*)handle
;
250 TRACE( "%p\n", handle
);
254 EnterCriticalSection( &proxy
->cs
);
256 if (proxy
->magic
!= PROXY_MAGIC
)
258 LeaveCriticalSection( &proxy
->cs
);
264 LeaveCriticalSection( &proxy
->cs
);
268 /**************************************************************************
269 * WsGetServiceProxyProperty [webservices.@]
271 HRESULT WINAPI
WsGetServiceProxyProperty( WS_SERVICE_PROXY
*handle
, WS_PROXY_PROPERTY_ID id
,
272 void *buf
, ULONG size
, WS_ERROR
*error
)
274 struct proxy
*proxy
= (struct proxy
*)handle
;
277 TRACE( "%p %u %p %lu %p\n", handle
, id
, buf
, size
, error
);
278 if (error
) FIXME( "ignoring error parameter\n" );
280 if (!proxy
) return E_INVALIDARG
;
282 EnterCriticalSection( &proxy
->cs
);
284 if (proxy
->magic
!= PROXY_MAGIC
)
286 LeaveCriticalSection( &proxy
->cs
);
292 case WS_PROXY_PROPERTY_STATE
:
293 if (!buf
|| size
!= sizeof(proxy
->state
)) hr
= E_INVALIDARG
;
294 else *(WS_SERVICE_PROXY_STATE
*)buf
= proxy
->state
;
298 hr
= prop_get( proxy
->prop
, proxy
->prop_count
, id
, buf
, size
);
301 LeaveCriticalSection( &proxy
->cs
);
302 TRACE( "returning %#lx\n", hr
);
306 /**************************************************************************
307 * WsOpenServiceProxy [webservices.@]
309 HRESULT WINAPI
WsOpenServiceProxy( WS_SERVICE_PROXY
*handle
, const WS_ENDPOINT_ADDRESS
*endpoint
,
310 const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
312 struct proxy
*proxy
= (struct proxy
*)handle
;
315 TRACE( "%p %p %p %p\n", handle
, endpoint
, ctx
, error
);
316 if (error
) FIXME( "ignoring error parameter\n" );
317 if (ctx
) FIXME( "ignoring ctx parameter\n" );
319 if (!proxy
|| !endpoint
) return E_INVALIDARG
;
321 EnterCriticalSection( &proxy
->cs
);
323 if (proxy
->magic
!= PROXY_MAGIC
)
325 LeaveCriticalSection( &proxy
->cs
);
329 if ((hr
= WsOpenChannel( proxy
->channel
, endpoint
, NULL
, NULL
)) == S_OK
)
330 proxy
->state
= WS_SERVICE_PROXY_STATE_OPEN
;
332 LeaveCriticalSection( &proxy
->cs
);
333 TRACE( "returning %#lx\n", hr
);
337 /**************************************************************************
338 * WsCloseServiceProxy [webservices.@]
340 HRESULT WINAPI
WsCloseServiceProxy( WS_SERVICE_PROXY
*handle
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
342 struct proxy
*proxy
= (struct proxy
*)handle
;
345 TRACE( "%p %p %p\n", handle
, ctx
, error
);
346 if (error
) FIXME( "ignoring error parameter\n" );
347 if (ctx
) FIXME( "ignoring ctx parameter\n" );
349 if (!proxy
) return E_INVALIDARG
;
351 EnterCriticalSection( &proxy
->cs
);
353 if (proxy
->magic
!= PROXY_MAGIC
)
355 LeaveCriticalSection( &proxy
->cs
);
359 if ((hr
= WsCloseChannel( proxy
->channel
, NULL
, NULL
)) == S_OK
)
360 proxy
->state
= WS_SERVICE_PROXY_STATE_CLOSED
;
362 LeaveCriticalSection( &proxy
->cs
);
363 TRACE( "returning %#lx\n", hr
);
367 /**************************************************************************
368 * WsAbortServiceProxy [webservices.@]
370 HRESULT WINAPI
WsAbortServiceProxy( WS_SERVICE_PROXY
*handle
, WS_ERROR
*error
)
372 FIXME( "%p %p\n", handle
, error
);
376 static HRESULT
set_send_context( WS_MESSAGE
*msg
, const WS_CALL_PROPERTY
*props
, ULONG count
)
379 for (i
= 0; i
< count
; i
++)
381 if (props
[i
].id
== WS_CALL_PROPERTY_SEND_MESSAGE_CONTEXT
)
383 if (props
[i
].valueSize
!= sizeof(WS_PROXY_MESSAGE_CALLBACK_CONTEXT
)) return E_INVALIDARG
;
384 message_set_send_context( msg
, props
[i
].value
);
391 static HRESULT
set_receive_context( WS_MESSAGE
*msg
, const WS_CALL_PROPERTY
*props
, ULONG count
)
394 for (i
= 0; i
< count
; i
++)
396 if (props
[i
].id
== WS_CALL_PROPERTY_RECEIVE_MESSAGE_CONTEXT
)
398 if (props
[i
].valueSize
!= sizeof(WS_PROXY_MESSAGE_CALLBACK_CONTEXT
)) return E_INVALIDARG
;
399 message_set_receive_context( msg
, props
[i
].value
);
406 static HRESULT
write_message( WS_MESSAGE
*msg
, WS_XML_WRITER
*writer
, const WS_ELEMENT_DESCRIPTION
*desc
,
407 const WS_PARAMETER_DESCRIPTION
*params
, ULONG count
, const void **args
)
410 message_do_send_callback( msg
);
411 if ((hr
= WsWriteEnvelopeStart( msg
, writer
, NULL
, NULL
, NULL
)) != S_OK
) return hr
;
412 if ((hr
= write_input_params( writer
, desc
, params
, count
, args
)) != S_OK
) return hr
;
413 return WsWriteEnvelopeEnd( msg
, NULL
);
416 static HRESULT
set_output( WS_XML_WRITER
*writer
)
418 WS_XML_WRITER_TEXT_ENCODING text
= { {WS_XML_WRITER_ENCODING_TYPE_TEXT
}, WS_CHARSET_UTF8
};
419 WS_XML_WRITER_BUFFER_OUTPUT buf
= { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER
} };
420 return WsSetOutput( writer
, &text
.encoding
, &buf
.output
, NULL
, 0, NULL
);
423 static HRESULT
send_message( WS_CHANNEL
*channel
, WS_MESSAGE
*msg
, WS_MESSAGE_DESCRIPTION
*desc
,
424 WS_PARAMETER_DESCRIPTION
*params
, ULONG count
, const void **args
)
426 WS_XML_WRITER
*writer
;
429 if ((hr
= channel_address_message( channel
, msg
)) != S_OK
) return hr
;
430 if ((hr
= message_set_action( msg
, desc
->action
)) != S_OK
) return hr
;
431 if ((hr
= WsCreateWriter( NULL
, 0, &writer
, NULL
)) != S_OK
) return hr
;
432 if ((hr
= set_output( writer
)) != S_OK
) goto done
;
433 if ((hr
= write_message( msg
, writer
, desc
->bodyElementDescription
, params
, count
, args
)) != S_OK
) goto done
;
434 hr
= channel_send_message( channel
, msg
);
437 WsFreeWriter( writer
);
441 static HRESULT
read_message( WS_MESSAGE
*msg
, WS_XML_READER
*reader
, WS_HEAP
*heap
,
442 const WS_ELEMENT_DESCRIPTION
*desc
, const WS_PARAMETER_DESCRIPTION
*params
,
443 ULONG count
, const void **args
, WS_ERROR
*error
)
446 if ((hr
= WsReadEnvelopeStart( msg
, reader
, NULL
, NULL
, NULL
)) != S_OK
) return hr
;
447 message_do_receive_callback( msg
);
448 if ((hr
= message_read_fault( msg
, heap
, error
)) != S_OK
) return hr
;
449 if ((hr
= read_output_params( reader
, heap
, desc
, params
, count
, args
)) != S_OK
) return hr
;
450 return WsReadEnvelopeEnd( msg
, NULL
);
453 static HRESULT
receive_message( WS_CHANNEL
*channel
, WS_MESSAGE
*msg
, WS_MESSAGE_DESCRIPTION
*desc
,
454 WS_PARAMETER_DESCRIPTION
*params
, ULONG count
,
455 WS_HEAP
*heap
, const void **args
, WS_ERROR
*error
)
457 WS_XML_READER
*reader
;
460 if ((hr
= message_set_action( msg
, desc
->action
)) != S_OK
) return hr
;
461 if ((hr
= channel_receive_message( channel
, msg
)) != S_OK
) return hr
;
462 if ((hr
= channel_get_reader( channel
, &reader
)) != S_OK
) return hr
;
463 return read_message( msg
, reader
, heap
, desc
->bodyElementDescription
, params
, count
, args
, error
);
466 static HRESULT
create_input_message( WS_CHANNEL
*channel
, const WS_CALL_PROPERTY
*properties
,
467 ULONG count
, WS_MESSAGE
**ret
)
472 if ((hr
= WsCreateMessageForChannel( channel
, NULL
, 0, &msg
, NULL
)) != S_OK
) return hr
;
473 if ((hr
= WsInitializeMessage( msg
, WS_REQUEST_MESSAGE
, NULL
, NULL
)) != S_OK
||
474 (hr
= set_send_context( msg
, properties
, count
)) != S_OK
)
476 WsFreeMessage( msg
);
483 static HRESULT
create_output_message( WS_CHANNEL
*channel
, const WS_CALL_PROPERTY
*properties
,
484 ULONG count
, WS_MESSAGE
**ret
)
489 if ((hr
= WsCreateMessageForChannel( channel
, NULL
, 0, &msg
, NULL
)) != S_OK
) return hr
;
490 if ((hr
= set_receive_context( msg
, properties
, count
)) != S_OK
)
492 WsFreeMessage( msg
);
499 /**************************************************************************
500 * WsCall [webservices.@]
502 HRESULT WINAPI
WsCall( WS_SERVICE_PROXY
*handle
, const WS_OPERATION_DESCRIPTION
*desc
, const void **args
,
503 WS_HEAP
*heap
, const WS_CALL_PROPERTY
*properties
, const ULONG count
,
504 const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
506 struct proxy
*proxy
= (struct proxy
*)handle
;
507 WS_MESSAGE
*msg
= NULL
;
511 TRACE( "%p %p %p %p %p %lu %p %p\n", handle
, desc
, args
, heap
, properties
, count
, ctx
, error
);
512 if (ctx
) FIXME( "ignoring ctx parameter\n" );
513 for (i
= 0; i
< count
; i
++)
515 if (properties
[i
].id
!= WS_CALL_PROPERTY_SEND_MESSAGE_CONTEXT
&&
516 properties
[i
].id
!= WS_CALL_PROPERTY_RECEIVE_MESSAGE_CONTEXT
)
518 FIXME( "unimplemented call property %u\n", properties
[i
].id
);
523 if (!proxy
|| !desc
|| (desc
->parameterCount
&& !args
)) return E_INVALIDARG
;
525 EnterCriticalSection( &proxy
->cs
);
527 if (proxy
->magic
!= PROXY_MAGIC
)
529 LeaveCriticalSection( &proxy
->cs
);
533 if ((hr
= create_input_message( proxy
->channel
, properties
, count
, &msg
)) != S_OK
) goto done
;
534 if ((hr
= send_message( proxy
->channel
, msg
, desc
->inputMessageDescription
, desc
->parameterDescription
,
535 desc
->parameterCount
, args
)) != S_OK
) goto done
;
536 WsFreeMessage( msg
);
539 if ((hr
= create_output_message( proxy
->channel
, properties
, count
, &msg
)) != S_OK
) goto done
;
540 hr
= receive_message( proxy
->channel
, msg
, desc
->outputMessageDescription
, desc
->parameterDescription
,
541 desc
->parameterCount
, heap
, args
, error
);
544 WsFreeMessage( msg
);
545 LeaveCriticalSection( &proxy
->cs
);
546 TRACE( "returning %#lx\n", hr
);