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"
32 WINE_DEFAULT_DEBUG_CHANNEL(webservices
);
34 static const struct prop_desc channel_props
[] =
36 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE */
37 { sizeof(UINT64
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_MESSAGE_SIZE */
38 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_START_SIZE */
39 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_FLUSH_SIZE */
40 { sizeof(WS_ENCODING
), TRUE
}, /* WS_CHANNEL_PROPERTY_ENCODING */
41 { sizeof(WS_ENVELOPE_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENVELOPE_VERSION */
42 { sizeof(WS_ADDRESSING_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_ADDRESSING_VERSION */
43 { sizeof(ULONG
), TRUE
}, /* WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE */
44 { sizeof(WS_CHANNEL_STATE
), TRUE
}, /* WS_CHANNEL_PROPERTY_STATE */
45 { sizeof(WS_CALLBACK_MODEL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ASYNC_CALLBACK_MODEL */
46 { sizeof(WS_IP_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_IP_VERSION */
47 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RESOLVE_TIMEOUT */
48 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_CONNECT_TIMEOUT */
49 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_SEND_TIMEOUT */
50 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RECEIVE_RESPONSE_TIMEOUT */
51 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RECEIVE_TIMEOUT */
52 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_CLOSE_TIMEOUT */
53 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENABLE_TIMEOUTS */
54 { sizeof(WS_TRANSFER_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_TRANSFER_MODE */
55 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MULTICAST_INTERFACE */
56 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MULTICAST_HOPS */
57 { sizeof(WS_ENDPOINT_ADDRESS
), TRUE
}, /* WS_CHANNEL_PROPERTY_REMOTE_ADDRESS */
58 { sizeof(SOCKADDR_STORAGE
), TRUE
}, /* WS_CHANNEL_PROPERTY_REMOTE_IP_ADDRESS */
59 { sizeof(ULONGLONG
), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_CONNECTION_ID */
60 { sizeof(WS_CUSTOM_CHANNEL_CALLBACKS
), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_CALLBACKS */
61 { 0, FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_PARAMETERS */
62 { sizeof(void *), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_INSTANCE */
63 { sizeof(WS_STRING
), TRUE
}, /* WS_CHANNEL_PROPERTY_TRANSPORT_URL */
64 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_NO_DELAY */
65 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_SEND_KEEP_ALIVES */
66 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_KEEP_ALIVE_TIME */
67 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_KEEP_ALIVE_INTERVAL */
68 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_HTTP_SERVER_CONNECTIONS */
69 { sizeof(BOOL
), TRUE
}, /* WS_CHANNEL_PROPERTY_IS_SESSION_SHUT_DOWN */
70 { sizeof(WS_CHANNEL_TYPE
), TRUE
}, /* WS_CHANNEL_PROPERTY_CHANNEL_TYPE */
71 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_TRIM_BUFFERED_MESSAGE_SIZE */
72 { sizeof(WS_CHANNEL_ENCODER
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENCODER */
73 { sizeof(WS_CHANNEL_DECODER
), FALSE
}, /* WS_CHANNEL_PROPERTY_DECODER */
74 { sizeof(WS_PROTECTION_LEVEL
), TRUE
}, /* WS_CHANNEL_PROPERTY_PROTECTION_LEVEL */
75 { sizeof(WS_COOKIE_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_COOKIE_MODE */
76 { sizeof(WS_HTTP_PROXY_SETTING_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_PROXY_SETTING_MODE */
77 { sizeof(WS_CUSTOM_HTTP_PROXY
), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_HTTP_PROXY */
78 { sizeof(WS_HTTP_MESSAGE_MAPPING
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING */
79 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENABLE_HTTP_REDIRECT */
80 { sizeof(WS_HTTP_REDIRECT_CALLBACK_CONTEXT
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_REDIRECT_CALLBACK_CONTEXT */
81 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_FAULTS_AS_ERRORS */
82 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ALLOW_UNSECURED_FAULTS */
83 { sizeof(WCHAR
*), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_SERVER_SPN */
84 { sizeof(WCHAR
*), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_PROXY_SPN */
85 { sizeof(ULONG
), FALSE
} /* WS_CHANNEL_PROPERTY_MAX_HTTP_REQUEST_HEADERS_BUFFER_SIZE */
91 void (*proc
)( struct task
* );
103 static struct task
*dequeue_task( struct queue
*queue
)
107 EnterCriticalSection( &queue
->cs
);
108 TRACE( "%u tasks queued\n", list_count( &queue
->tasks
) );
109 task
= LIST_ENTRY( list_head( &queue
->tasks
), struct task
, entry
);
110 if (task
) list_remove( &task
->entry
);
111 LeaveCriticalSection( &queue
->cs
);
113 TRACE( "returning task %p\n", task
);
117 static void CALLBACK
queue_runner( TP_CALLBACK_INSTANCE
*instance
, void *ctx
)
119 struct queue
*queue
= ctx
;
120 HANDLE handles
[] = { queue
->wait
, queue
->cancel
};
122 SetEvent( queue
->ready
);
125 DWORD err
= WaitForMultipleObjects( 2, handles
, FALSE
, INFINITE
);
131 while ((task
= dequeue_task( queue
)))
138 case WAIT_OBJECT_0
+ 1:
139 TRACE( "cancelled\n" );
140 SetEvent( queue
->ready
);
144 ERR( "wait failed %lu\n", err
);
150 static HRESULT
start_queue( struct queue
*queue
)
152 HRESULT hr
= E_OUTOFMEMORY
;
154 if (queue
->wait
) return S_OK
;
155 list_init( &queue
->tasks
);
156 if (!(queue
->wait
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
))) goto error
;
157 if (!(queue
->cancel
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
))) goto error
;
158 if (!(queue
->ready
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
))) goto error
;
159 if (!TrySubmitThreadpoolCallback( queue_runner
, queue
, NULL
)) hr
= HRESULT_FROM_WIN32( GetLastError() );
162 WaitForSingleObject( queue
->ready
, INFINITE
);
167 CloseHandle( queue
->wait
);
169 CloseHandle( queue
->cancel
);
170 queue
->cancel
= NULL
;
171 CloseHandle( queue
->ready
);
176 static HRESULT
queue_task( struct queue
*queue
, struct task
*task
)
179 if ((hr
= start_queue( queue
)) != S_OK
) return hr
;
181 EnterCriticalSection( &queue
->cs
);
182 TRACE( "queueing task %p\n", task
);
183 list_add_tail( &queue
->tasks
, &task
->entry
);
184 LeaveCriticalSection( &queue
->cs
);
186 SetEvent( queue
->wait
);
192 SESSION_STATE_UNINITIALIZED
,
193 SESSION_STATE_SETUP_COMPLETE
,
194 SESSION_STATE_SHUTDOWN
,
201 WS_CHANNEL_TYPE type
;
202 WS_CHANNEL_BINDING binding
;
203 WS_CHANNEL_STATE state
;
204 WS_ENDPOINT_ADDRESS addr
;
205 WS_XML_WRITER
*writer
;
206 WS_XML_READER
*reader
;
208 WS_ENCODING encoding
;
209 enum session_state session_state
;
210 struct dictionary dict_send
;
211 struct dictionary dict_recv
;
241 struct prop prop
[ARRAY_SIZE( channel_props
)];
244 #define CHANNEL_MAGIC (('C' << 24) | ('H' << 16) | ('A' << 8) | 'N')
246 static struct channel
*alloc_channel(void)
248 static const ULONG count
= ARRAY_SIZE( channel_props
);
250 ULONG size
= sizeof(*ret
) + prop_size( channel_props
, count
);
252 if (!(ret
= calloc( 1, size
))) return NULL
;
254 ret
->magic
= CHANNEL_MAGIC
;
255 InitializeCriticalSection( &ret
->cs
);
256 InitializeCriticalSection( &ret
->send_q
.cs
);
257 InitializeCriticalSection( &ret
->recv_q
.cs
);
258 ret
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": channel.cs");
259 ret
->send_q
.cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": channel.send_q.cs");
260 ret
->recv_q
.cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": channel.recv_q.cs");
262 prop_init( channel_props
, count
, ret
->prop
, &ret
[1] );
263 ret
->prop_count
= count
;
267 static void clear_addr( WS_ENDPOINT_ADDRESS
*addr
)
269 free( addr
->url
.chars
);
270 addr
->url
.chars
= NULL
;
271 addr
->url
.length
= 0;
274 static void clear_queue( struct queue
*queue
)
278 SetEvent( queue
->cancel
);
279 WaitForSingleObject( queue
->ready
, INFINITE
);
281 while ((ptr
= list_head( &queue
->tasks
)))
283 struct task
*task
= LIST_ENTRY( ptr
, struct task
, entry
);
284 list_remove( &task
->entry
);
288 CloseHandle( queue
->wait
);
290 CloseHandle( queue
->cancel
);
291 queue
->cancel
= NULL
;
292 CloseHandle( queue
->ready
);
296 static void abort_channel( struct channel
*channel
)
298 clear_queue( &channel
->send_q
);
299 clear_queue( &channel
->recv_q
);
302 /**************************************************************************
303 * WsAbortChannel [webservices.@]
305 HRESULT WINAPI
WsAbortChannel( WS_CHANNEL
*handle
, WS_ERROR
*error
)
307 struct channel
*channel
= (struct channel
*)handle
;
309 TRACE( "%p %p\n", handle
, error
);
311 EnterCriticalSection( &channel
->cs
);
313 if (channel
->magic
!= CHANNEL_MAGIC
)
315 LeaveCriticalSection( &channel
->cs
);
319 abort_channel( channel
);
321 LeaveCriticalSection( &channel
->cs
);
325 static void reset_channel( struct channel
*channel
)
327 channel
->state
= WS_CHANNEL_STATE_CREATED
;
328 channel
->session_state
= SESSION_STATE_UNINITIALIZED
;
329 clear_addr( &channel
->addr
);
330 clear_dict( &channel
->dict_send
);
331 clear_dict( &channel
->dict_recv
);
333 channel
->read_size
= 0;
334 channel
->send_size
= 0;
336 switch (channel
->binding
)
338 case WS_HTTP_CHANNEL_BINDING
:
339 WinHttpCloseHandle( channel
->u
.http
.request
);
340 channel
->u
.http
.request
= NULL
;
341 WinHttpCloseHandle( channel
->u
.http
.connect
);
342 channel
->u
.http
.connect
= NULL
;
343 WinHttpCloseHandle( channel
->u
.http
.session
);
344 channel
->u
.http
.session
= NULL
;
345 free( channel
->u
.http
.path
);
346 channel
->u
.http
.path
= NULL
;
347 channel
->u
.http
.flags
= 0;
350 case WS_TCP_CHANNEL_BINDING
:
351 closesocket( channel
->u
.tcp
.socket
);
352 channel
->u
.tcp
.socket
= -1;
355 case WS_UDP_CHANNEL_BINDING
:
356 closesocket( channel
->u
.udp
.socket
);
357 channel
->u
.udp
.socket
= -1;
364 static void free_header_mappings( WS_HTTP_HEADER_MAPPING
**mappings
, ULONG count
)
367 for (i
= 0; i
< count
; i
++) free( mappings
[i
] );
371 static void free_message_mapping( const WS_HTTP_MESSAGE_MAPPING
*mapping
)
373 free_header_mappings( mapping
->requestHeaderMappings
, mapping
->requestHeaderMappingCount
);
374 free_header_mappings( mapping
->responseHeaderMappings
, mapping
->responseHeaderMappingCount
);
377 static void free_props( struct channel
*channel
)
379 struct prop
*prop
= &channel
->prop
[WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING
];
380 WS_HTTP_MESSAGE_MAPPING
*mapping
= (WS_HTTP_MESSAGE_MAPPING
*)prop
->value
;
381 free_message_mapping( mapping
);
384 static void free_channel( struct channel
*channel
)
386 abort_channel( channel
);
387 reset_channel( channel
);
389 WsFreeWriter( channel
->writer
);
390 WsFreeReader( channel
->reader
);
392 free( channel
->read_buf
);
393 free( channel
->send_buf
);
394 free_props( channel
);
396 channel
->send_q
.cs
.DebugInfo
->Spare
[0] = 0;
397 channel
->recv_q
.cs
.DebugInfo
->Spare
[0] = 0;
398 channel
->cs
.DebugInfo
->Spare
[0] = 0;
399 DeleteCriticalSection( &channel
->send_q
.cs
);
400 DeleteCriticalSection( &channel
->recv_q
.cs
);
401 DeleteCriticalSection( &channel
->cs
);
405 static WS_HTTP_HEADER_MAPPING
*dup_header_mapping( const WS_HTTP_HEADER_MAPPING
*src
)
407 WS_HTTP_HEADER_MAPPING
*dst
;
409 if (!(dst
= malloc( sizeof(*dst
) + src
->headerName
.length
))) return NULL
;
411 dst
->headerName
.bytes
= (BYTE
*)(dst
+ 1);
412 memcpy( dst
->headerName
.bytes
, src
->headerName
.bytes
, src
->headerName
.length
);
413 dst
->headerName
.length
= src
->headerName
.length
;
414 dst
->headerMappingOptions
= src
->headerMappingOptions
;
418 static HRESULT
dup_message_mapping( const WS_HTTP_MESSAGE_MAPPING
*src
, WS_HTTP_MESSAGE_MAPPING
*dst
)
422 size
= src
->requestHeaderMappingCount
* sizeof(*dst
->responseHeaderMappings
);
423 if (!(dst
->requestHeaderMappings
= malloc( size
))) return E_OUTOFMEMORY
;
425 for (i
= 0; i
< src
->requestHeaderMappingCount
; i
++)
427 if (!(dst
->requestHeaderMappings
[i
] = dup_header_mapping( src
->requestHeaderMappings
[i
] )))
429 free_header_mappings( dst
->requestHeaderMappings
, i
);
430 return E_OUTOFMEMORY
;
434 size
= src
->responseHeaderMappingCount
* sizeof(*dst
->responseHeaderMappings
);
435 if (!(dst
->responseHeaderMappings
= malloc( size
)))
437 free( dst
->responseHeaderMappings
);
438 return E_OUTOFMEMORY
;
441 for (i
= 0; i
< src
->responseHeaderMappingCount
; i
++)
443 if (!(dst
->responseHeaderMappings
[i
] = dup_header_mapping( src
->responseHeaderMappings
[i
] )))
445 free_header_mappings( dst
->responseHeaderMappings
, i
);
446 return E_OUTOFMEMORY
;
450 dst
->requestMappingOptions
= src
->requestMappingOptions
;
451 dst
->responseMappingOptions
= src
->responseMappingOptions
;
452 dst
->requestHeaderMappingCount
= src
->requestHeaderMappingCount
;
453 dst
->responseHeaderMappingCount
= src
->responseHeaderMappingCount
;
457 static HRESULT
create_channel( WS_CHANNEL_TYPE type
, WS_CHANNEL_BINDING binding
,
458 const WS_CHANNEL_PROPERTY
*properties
, ULONG count
, struct channel
**ret
)
460 struct channel
*channel
;
461 ULONG i
, msg_size
= 65536;
462 WS_ENVELOPE_VERSION env_version
= WS_ENVELOPE_VERSION_SOAP_1_2
;
463 WS_ADDRESSING_VERSION addr_version
= WS_ADDRESSING_VERSION_1_0
;
466 if (!(channel
= alloc_channel())) return E_OUTOFMEMORY
;
468 prop_set( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE
,
469 &msg_size
, sizeof(msg_size
) );
470 prop_set( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION
,
471 &env_version
, sizeof(env_version
) );
472 prop_set( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_ADDRESSING_VERSION
,
473 &addr_version
, sizeof(addr_version
) );
475 channel
->type
= type
;
476 channel
->binding
= binding
;
478 switch (channel
->binding
)
480 case WS_HTTP_CHANNEL_BINDING
:
481 channel
->encoding
= WS_ENCODING_XML_UTF8
;
484 case WS_TCP_CHANNEL_BINDING
:
485 channel
->u
.tcp
.socket
= -1;
486 channel
->encoding
= WS_ENCODING_XML_BINARY_SESSION_1
;
487 channel
->dict_size
= 2048;
490 case WS_UDP_CHANNEL_BINDING
:
491 channel
->u
.udp
.socket
= -1;
492 channel
->encoding
= WS_ENCODING_XML_UTF8
;
498 for (i
= 0; i
< count
; i
++)
500 const WS_CHANNEL_PROPERTY
*prop
= &properties
[i
];
502 TRACE( "property id %u value %p size %lu\n", prop
->id
, prop
->value
, prop
->valueSize
);
503 if (prop
->valueSize
== sizeof(ULONG
) && prop
->value
) TRACE( " value %#lx\n", *(ULONG
*)prop
->value
);
507 case WS_CHANNEL_PROPERTY_ENCODING
:
508 if (!prop
->value
|| prop
->valueSize
!= sizeof(channel
->encoding
))
510 free_channel( channel
);
513 channel
->encoding
= *(WS_ENCODING
*)prop
->value
;
516 case WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING
:
518 const WS_HTTP_MESSAGE_MAPPING
*src
= (WS_HTTP_MESSAGE_MAPPING
*)prop
->value
;
519 WS_HTTP_MESSAGE_MAPPING dst
;
521 if (!prop
->value
|| prop
->valueSize
!= sizeof(*src
))
523 free_channel( channel
);
527 if ((hr
= dup_message_mapping( src
, &dst
)) != S_OK
) return hr
;
529 if ((hr
= prop_set( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING
, &dst
,
530 sizeof(dst
) )) != S_OK
)
532 free_message_mapping( &dst
);
533 free_channel( channel
);
539 case WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE
:
540 if (channel
->binding
!= WS_TCP_CHANNEL_BINDING
|| !prop
->value
|| prop
->valueSize
!= sizeof(channel
->dict_size
))
542 free_channel( channel
);
546 channel
->dict_size
= *(ULONG
*)prop
->value
;
550 if ((hr
= prop_set( channel
->prop
, channel
->prop_count
, prop
->id
, prop
->value
, prop
->valueSize
)) != S_OK
)
552 free_channel( channel
);
563 /**************************************************************************
564 * WsCreateChannel [webservices.@]
566 HRESULT WINAPI
WsCreateChannel( WS_CHANNEL_TYPE type
, WS_CHANNEL_BINDING binding
,
567 const WS_CHANNEL_PROPERTY
*properties
, ULONG count
,
568 const WS_SECURITY_DESCRIPTION
*desc
, WS_CHANNEL
**handle
,
571 struct channel
*channel
;
574 TRACE( "%u %u %p %lu %p %p %p\n", type
, binding
, properties
, count
, desc
, handle
, error
);
575 if (error
) FIXME( "ignoring error parameter\n" );
576 if (desc
) FIXME( "ignoring security description\n" );
578 if (!handle
) return E_INVALIDARG
;
580 if (type
!= WS_CHANNEL_TYPE_REQUEST
&& type
!= WS_CHANNEL_TYPE_DUPLEX
&&
581 type
!= WS_CHANNEL_TYPE_DUPLEX_SESSION
)
583 FIXME( "channel type %u not implemented\n", type
);
586 if (binding
!= WS_HTTP_CHANNEL_BINDING
&& binding
!= WS_TCP_CHANNEL_BINDING
&&
587 binding
!= WS_UDP_CHANNEL_BINDING
)
589 FIXME( "channel binding %u not implemented\n", binding
);
593 if ((hr
= create_channel( type
, binding
, properties
, count
, &channel
)) != S_OK
) return hr
;
595 TRACE( "created %p\n", channel
);
596 *handle
= (WS_CHANNEL
*)channel
;
600 /**************************************************************************
601 * WsCreateChannelForListener [webservices.@]
603 HRESULT WINAPI
WsCreateChannelForListener( WS_LISTENER
*listener_handle
, const WS_CHANNEL_PROPERTY
*properties
,
604 ULONG count
, WS_CHANNEL
**handle
, WS_ERROR
*error
)
606 struct channel
*channel
;
607 WS_CHANNEL_TYPE type
;
608 WS_CHANNEL_BINDING binding
;
611 TRACE( "%p %p %lu %p %p\n", listener_handle
, properties
, count
, handle
, error
);
612 if (error
) FIXME( "ignoring error parameter\n" );
614 if (!listener_handle
|| !handle
) return E_INVALIDARG
;
616 if ((hr
= WsGetListenerProperty( listener_handle
, WS_LISTENER_PROPERTY_CHANNEL_TYPE
, &type
,
617 sizeof(type
), NULL
)) != S_OK
) return hr
;
619 if ((hr
= WsGetListenerProperty( listener_handle
, WS_LISTENER_PROPERTY_CHANNEL_BINDING
, &binding
,
620 sizeof(binding
), NULL
)) != S_OK
) return hr
;
622 if ((hr
= create_channel( type
, binding
, properties
, count
, &channel
)) != S_OK
) return hr
;
624 TRACE( "created %p\n", channel
);
625 *handle
= (WS_CHANNEL
*)channel
;
629 /**************************************************************************
630 * WsFreeChannel [webservices.@]
632 void WINAPI
WsFreeChannel( WS_CHANNEL
*handle
)
634 struct channel
*channel
= (struct channel
*)handle
;
636 TRACE( "%p\n", handle
);
638 if (!channel
) return;
640 EnterCriticalSection( &channel
->cs
);
642 if (channel
->magic
!= CHANNEL_MAGIC
)
644 LeaveCriticalSection( &channel
->cs
);
650 LeaveCriticalSection( &channel
->cs
);
651 free_channel( channel
);
654 /**************************************************************************
655 * WsResetChannel [webservices.@]
657 HRESULT WINAPI
WsResetChannel( WS_CHANNEL
*handle
, WS_ERROR
*error
)
659 struct channel
*channel
= (struct channel
*)handle
;
662 TRACE( "%p %p\n", handle
, error
);
663 if (error
) FIXME( "ignoring error parameter\n" );
665 if (!channel
) return E_INVALIDARG
;
667 EnterCriticalSection( &channel
->cs
);
669 if (channel
->magic
!= CHANNEL_MAGIC
)
671 LeaveCriticalSection( &channel
->cs
);
675 if (channel
->state
!= WS_CHANNEL_STATE_CREATED
&& channel
->state
!= WS_CHANNEL_STATE_CLOSED
)
676 hr
= WS_E_INVALID_OPERATION
;
679 abort_channel( channel
);
680 reset_channel( channel
);
683 LeaveCriticalSection( &channel
->cs
);
684 TRACE( "returning %#lx\n", hr
);
688 /**************************************************************************
689 * WsGetChannelProperty [webservices.@]
691 HRESULT WINAPI
WsGetChannelProperty( WS_CHANNEL
*handle
, WS_CHANNEL_PROPERTY_ID id
, void *buf
,
692 ULONG size
, WS_ERROR
*error
)
694 struct channel
*channel
= (struct channel
*)handle
;
697 TRACE( "%p %u %p %lu %p\n", handle
, id
, buf
, size
, error
);
698 if (error
) FIXME( "ignoring error parameter\n" );
700 if (!channel
) return E_INVALIDARG
;
702 EnterCriticalSection( &channel
->cs
);
704 if (channel
->magic
!= CHANNEL_MAGIC
)
706 LeaveCriticalSection( &channel
->cs
);
712 case WS_CHANNEL_PROPERTY_CHANNEL_TYPE
:
713 if (!buf
|| size
!= sizeof(channel
->type
)) hr
= E_INVALIDARG
;
714 else *(WS_CHANNEL_TYPE
*)buf
= channel
->type
;
717 case WS_CHANNEL_PROPERTY_ENCODING
:
718 if (!buf
|| size
!= sizeof(channel
->encoding
)) hr
= E_INVALIDARG
;
719 else *(WS_ENCODING
*)buf
= channel
->encoding
;
722 case WS_CHANNEL_PROPERTY_STATE
:
723 if (!buf
|| size
!= sizeof(channel
->state
)) hr
= E_INVALIDARG
;
724 else *(WS_CHANNEL_STATE
*)buf
= channel
->state
;
727 case WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE
:
728 if (channel
->binding
!= WS_TCP_CHANNEL_BINDING
|| !buf
|| size
!= sizeof(channel
->dict_size
))
731 *(ULONG
*)buf
= channel
->dict_size
;
735 hr
= prop_get( channel
->prop
, channel
->prop_count
, id
, buf
, size
);
738 LeaveCriticalSection( &channel
->cs
);
739 TRACE( "returning %#lx\n", hr
);
743 /**************************************************************************
744 * WsSetChannelProperty [webservices.@]
746 HRESULT WINAPI
WsSetChannelProperty( WS_CHANNEL
*handle
, WS_CHANNEL_PROPERTY_ID id
, const void *value
,
747 ULONG size
, WS_ERROR
*error
)
749 struct channel
*channel
= (struct channel
*)handle
;
752 TRACE( "%p %u %p %lu %p\n", handle
, id
, value
, size
, error
);
753 if (error
) FIXME( "ignoring error parameter\n" );
755 if (!channel
) return E_INVALIDARG
;
757 EnterCriticalSection( &channel
->cs
);
759 if (channel
->magic
!= CHANNEL_MAGIC
)
761 LeaveCriticalSection( &channel
->cs
);
765 hr
= prop_set( channel
->prop
, channel
->prop_count
, id
, value
, size
);
767 LeaveCriticalSection( &channel
->cs
);
768 TRACE( "returning %#lx\n", hr
);
772 enum frame_record_type
774 FRAME_RECORD_TYPE_VERSION
,
775 FRAME_RECORD_TYPE_MODE
,
776 FRAME_RECORD_TYPE_VIA
,
777 FRAME_RECORD_TYPE_KNOWN_ENCODING
,
778 FRAME_RECORD_TYPE_EXTENSIBLE_ENCODING
,
779 FRAME_RECORD_TYPE_UNSIZED_ENVELOPE
,
780 FRAME_RECORD_TYPE_SIZED_ENVELOPE
,
781 FRAME_RECORD_TYPE_END
,
782 FRAME_RECORD_TYPE_FAULT
,
783 FRAME_RECORD_TYPE_UPGRADE_REQUEST
,
784 FRAME_RECORD_TYPE_UPGRADE_RESPONSE
,
785 FRAME_RECORD_TYPE_PREAMBLE_ACK
,
786 FRAME_RECORD_TYPE_PREAMBLE_END
,
789 static HRESULT
send_byte( SOCKET socket
, BYTE byte
)
791 int count
= send( socket
, (char *)&byte
, 1, 0 );
792 if (count
< 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
793 if (count
!= 1) return WS_E_OTHER
;
803 static void CALLBACK
async_callback( HRESULT hr
, WS_CALLBACK_MODEL model
, void *state
)
805 struct async
*async
= state
;
807 SetEvent( async
->done
);
810 static void async_init( struct async
*async
, WS_ASYNC_CONTEXT
*ctx
)
812 async
->done
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
814 ctx
->callback
= async_callback
;
815 ctx
->callbackState
= async
;
818 static HRESULT
async_wait( struct async
*async
)
821 if ((err
= WaitForSingleObject( async
->done
, INFINITE
)) == WAIT_OBJECT_0
) return async
->hr
;
822 return HRESULT_FROM_WIN32( err
);
825 static HRESULT
shutdown_session( struct channel
*channel
)
829 if ((channel
->type
!= WS_CHANNEL_TYPE_OUTPUT_SESSION
&&
830 channel
->type
!= WS_CHANNEL_TYPE_DUPLEX_SESSION
) ||
831 channel
->session_state
>= SESSION_STATE_SHUTDOWN
) return WS_E_INVALID_OPERATION
;
833 switch (channel
->binding
)
835 case WS_TCP_CHANNEL_BINDING
:
836 if ((hr
= send_byte( channel
->u
.tcp
.socket
, FRAME_RECORD_TYPE_END
)) != S_OK
) return hr
;
837 channel
->session_state
= SESSION_STATE_SHUTDOWN
;
841 FIXME( "unhandled binding %u\n", channel
->binding
);
846 struct shutdown_session
849 struct channel
*channel
;
850 WS_ASYNC_CONTEXT ctx
;
853 static void shutdown_session_proc( struct task
*task
)
855 struct shutdown_session
*s
= (struct shutdown_session
*)task
;
858 hr
= shutdown_session( s
->channel
);
860 TRACE( "calling %p(%#lx)\n", s
->ctx
.callback
, hr
);
861 s
->ctx
.callback( hr
, WS_LONG_CALLBACK
, s
->ctx
.callbackState
);
862 TRACE( "%p returned\n", s
->ctx
.callback
);
865 static HRESULT
queue_shutdown_session( struct channel
*channel
, const WS_ASYNC_CONTEXT
*ctx
)
867 struct shutdown_session
*s
;
869 if (!(s
= malloc( sizeof(*s
) ))) return E_OUTOFMEMORY
;
870 s
->task
.proc
= shutdown_session_proc
;
871 s
->channel
= channel
;
873 return queue_task( &channel
->send_q
, &s
->task
);
876 HRESULT WINAPI
WsShutdownSessionChannel( WS_CHANNEL
*handle
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
878 struct channel
*channel
= (struct channel
*)handle
;
879 WS_ASYNC_CONTEXT ctx_local
;
883 TRACE( "%p %p %p\n", handle
, ctx
, error
);
884 if (error
) FIXME( "ignoring error parameter\n" );
886 if (!channel
) return E_INVALIDARG
;
888 EnterCriticalSection( &channel
->cs
);
890 if (channel
->magic
!= CHANNEL_MAGIC
)
892 LeaveCriticalSection( &channel
->cs
);
895 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
897 LeaveCriticalSection( &channel
->cs
);
898 return WS_E_INVALID_OPERATION
;
901 if (!ctx
) async_init( &async
, &ctx_local
);
902 hr
= queue_shutdown_session( channel
, ctx
? ctx
: &ctx_local
);
905 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
906 CloseHandle( async
.done
);
909 LeaveCriticalSection( &channel
->cs
);
910 TRACE( "returning %#lx\n", hr
);
914 static void close_channel( struct channel
*channel
)
916 reset_channel( channel
);
917 channel
->state
= WS_CHANNEL_STATE_CLOSED
;
923 struct channel
*channel
;
924 WS_ASYNC_CONTEXT ctx
;
927 static void close_channel_proc( struct task
*task
)
929 struct close_channel
*c
= (struct close_channel
*)task
;
931 close_channel( c
->channel
);
933 TRACE( "calling %p(S_OK)\n", c
->ctx
.callback
);
934 c
->ctx
.callback( S_OK
, WS_LONG_CALLBACK
, c
->ctx
.callbackState
);
935 TRACE( "%p returned\n", c
->ctx
.callback
);
938 static HRESULT
queue_close_channel( struct channel
*channel
, const WS_ASYNC_CONTEXT
*ctx
)
940 struct close_channel
*c
;
942 if (!(c
= malloc( sizeof(*c
) ))) return E_OUTOFMEMORY
;
943 c
->task
.proc
= close_channel_proc
;
944 c
->channel
= channel
;
946 return queue_task( &channel
->send_q
, &c
->task
);
949 /**************************************************************************
950 * WsCloseChannel [webservices.@]
952 HRESULT WINAPI
WsCloseChannel( WS_CHANNEL
*handle
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
954 struct channel
*channel
= (struct channel
*)handle
;
955 WS_ASYNC_CONTEXT ctx_local
;
959 TRACE( "%p %p %p\n", handle
, ctx
, error
);
960 if (error
) FIXME( "ignoring error parameter\n" );
962 if (!channel
) return E_INVALIDARG
;
964 EnterCriticalSection( &channel
->cs
);
966 if (channel
->magic
!= CHANNEL_MAGIC
)
968 LeaveCriticalSection( &channel
->cs
);
972 if (!ctx
) async_init( &async
, &ctx_local
);
973 hr
= queue_close_channel( channel
, ctx
? ctx
: &ctx_local
);
976 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
977 CloseHandle( async
.done
);
980 LeaveCriticalSection( &channel
->cs
);
981 TRACE( "returning %#lx\n", hr
);
985 static HRESULT
parse_http_url( const WCHAR
*url
, ULONG len
, URL_COMPONENTS
*uc
)
987 HRESULT hr
= E_OUTOFMEMORY
;
991 memset( uc
, 0, sizeof(*uc
) );
992 uc
->dwStructSize
= sizeof(*uc
);
993 uc
->dwHostNameLength
= 128;
994 uc
->lpszHostName
= malloc( uc
->dwHostNameLength
* sizeof(WCHAR
) );
995 uc
->dwUrlPathLength
= 128;
996 uc
->lpszUrlPath
= malloc( uc
->dwUrlPathLength
* sizeof(WCHAR
) );
997 uc
->dwExtraInfoLength
= 128;
998 uc
->lpszExtraInfo
= malloc( uc
->dwExtraInfoLength
* sizeof(WCHAR
) );
999 if (!uc
->lpszHostName
|| !uc
->lpszUrlPath
|| !uc
->lpszExtraInfo
) goto error
;
1001 if (!WinHttpCrackUrl( url
, len
, ICU_DECODE
, uc
))
1003 if ((err
= GetLastError()) != ERROR_INSUFFICIENT_BUFFER
)
1005 hr
= HRESULT_FROM_WIN32( err
);
1008 if (!(tmp
= realloc( uc
->lpszHostName
, uc
->dwHostNameLength
* sizeof(WCHAR
) ))) goto error
;
1009 uc
->lpszHostName
= tmp
;
1010 if (!(tmp
= realloc( uc
->lpszUrlPath
, uc
->dwUrlPathLength
* sizeof(WCHAR
) ))) goto error
;
1011 uc
->lpszUrlPath
= tmp
;
1012 if (!(tmp
= realloc( uc
->lpszExtraInfo
, uc
->dwExtraInfoLength
* sizeof(WCHAR
) ))) goto error
;
1013 uc
->lpszExtraInfo
= tmp
;
1014 WinHttpCrackUrl( url
, len
, ICU_DECODE
, uc
);
1020 free( uc
->lpszHostName
);
1021 free( uc
->lpszUrlPath
);
1022 free( uc
->lpszExtraInfo
);
1026 static HRESULT
open_channel_http( struct channel
*channel
)
1028 HINTERNET ses
= NULL
, con
= NULL
;
1032 if (channel
->u
.http
.connect
) return S_OK
;
1034 if ((hr
= parse_http_url( channel
->addr
.url
.chars
, channel
->addr
.url
.length
, &uc
)) != S_OK
) return hr
;
1035 if (!(channel
->u
.http
.path
= malloc( (uc
.dwUrlPathLength
+ uc
.dwExtraInfoLength
+ 1) * sizeof(WCHAR
) )))
1042 lstrcpyW( channel
->u
.http
.path
, uc
.lpszUrlPath
);
1043 if (uc
.dwExtraInfoLength
) lstrcatW( channel
->u
.http
.path
, uc
.lpszExtraInfo
);
1046 channel
->u
.http
.flags
= WINHTTP_FLAG_REFRESH
;
1049 case INTERNET_SCHEME_HTTP
: break;
1050 case INTERNET_SCHEME_HTTPS
:
1051 channel
->u
.http
.flags
|= WINHTTP_FLAG_SECURE
;
1055 hr
= WS_E_INVALID_ENDPOINT_URL
;
1059 if (!(ses
= WinHttpOpen( L
"MS-WebServices/1.0", 0, NULL
, NULL
, 0 )))
1061 hr
= HRESULT_FROM_WIN32( GetLastError() );
1064 if (!(con
= WinHttpConnect( ses
, uc
.lpszHostName
, uc
.nPort
, 0 )))
1066 hr
= HRESULT_FROM_WIN32( GetLastError() );
1070 channel
->u
.http
.session
= ses
;
1071 channel
->u
.http
.connect
= con
;
1076 WinHttpCloseHandle( con
);
1077 WinHttpCloseHandle( ses
);
1079 free( uc
.lpszHostName
);
1080 free( uc
.lpszUrlPath
);
1081 free( uc
.lpszExtraInfo
);
1085 static HRESULT
open_channel_tcp( struct channel
*channel
)
1087 struct sockaddr_storage storage
;
1088 struct sockaddr
*addr
= (struct sockaddr
*)&storage
;
1089 BOOL nodelay
= FALSE
;
1091 WS_URL_SCHEME_TYPE scheme
;
1096 if (channel
->u
.tcp
.socket
!= -1) return S_OK
;
1098 if ((hr
= parse_url( &channel
->addr
.url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
1099 if (scheme
!= WS_URL_NETTCP_SCHEME_TYPE
)
1102 return WS_E_INVALID_ENDPOINT_URL
;
1107 hr
= resolve_hostname( host
, port
, addr
, &addr_len
, 0 );
1109 if (hr
!= S_OK
) return hr
;
1111 if ((channel
->u
.tcp
.socket
= socket( addr
->sa_family
, SOCK_STREAM
, 0 )) == -1)
1112 return HRESULT_FROM_WIN32( WSAGetLastError() );
1114 if (connect( channel
->u
.tcp
.socket
, addr
, addr_len
) < 0)
1116 closesocket( channel
->u
.tcp
.socket
);
1117 channel
->u
.tcp
.socket
= -1;
1118 return HRESULT_FROM_WIN32( WSAGetLastError() );
1121 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_NO_DELAY
, &nodelay
, sizeof(nodelay
) );
1122 setsockopt( channel
->u
.tcp
.socket
, IPPROTO_TCP
, TCP_NODELAY
, (const char *)&nodelay
, sizeof(nodelay
) );
1126 static HRESULT
open_channel_udp( struct channel
*channel
)
1128 struct sockaddr_storage storage
;
1129 struct sockaddr
*addr
= (struct sockaddr
*)&storage
;
1131 WS_URL_SCHEME_TYPE scheme
;
1136 if (channel
->u
.udp
.socket
!= -1) return S_OK
;
1138 if ((hr
= parse_url( &channel
->addr
.url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
1139 if (scheme
!= WS_URL_SOAPUDP_SCHEME_TYPE
)
1142 return WS_E_INVALID_ENDPOINT_URL
;
1147 hr
= resolve_hostname( host
, port
, addr
, &addr_len
, 0 );
1149 if (hr
!= S_OK
) return hr
;
1151 if ((channel
->u
.udp
.socket
= socket( addr
->sa_family
, SOCK_DGRAM
, 0 )) == -1)
1152 return HRESULT_FROM_WIN32( WSAGetLastError() );
1154 if (connect( channel
->u
.udp
.socket
, addr
, addr_len
) < 0)
1156 closesocket( channel
->u
.udp
.socket
);
1157 channel
->u
.udp
.socket
= -1;
1158 return HRESULT_FROM_WIN32( WSAGetLastError() );
1164 static HRESULT
open_channel( struct channel
*channel
, const WS_ENDPOINT_ADDRESS
*endpoint
)
1168 if (endpoint
->headers
|| endpoint
->extensions
|| endpoint
->identity
)
1170 FIXME( "headers, extensions or identity not supported\n" );
1174 TRACE( "endpoint %s\n", debugstr_wn(endpoint
->url
.chars
, endpoint
->url
.length
) );
1176 if (!(channel
->addr
.url
.chars
= malloc( endpoint
->url
.length
* sizeof(WCHAR
) ))) return E_OUTOFMEMORY
;
1177 memcpy( channel
->addr
.url
.chars
, endpoint
->url
.chars
, endpoint
->url
.length
* sizeof(WCHAR
) );
1178 channel
->addr
.url
.length
= endpoint
->url
.length
;
1180 switch (channel
->binding
)
1182 case WS_HTTP_CHANNEL_BINDING
:
1183 hr
= open_channel_http( channel
);
1186 case WS_TCP_CHANNEL_BINDING
:
1187 hr
= open_channel_tcp( channel
);
1190 case WS_UDP_CHANNEL_BINDING
:
1191 hr
= open_channel_udp( channel
);
1195 ERR( "unhandled binding %u\n", channel
->binding
);
1199 if (hr
== S_OK
) channel
->state
= WS_CHANNEL_STATE_OPEN
;
1206 struct channel
*channel
;
1207 const WS_ENDPOINT_ADDRESS
*endpoint
;
1208 WS_ASYNC_CONTEXT ctx
;
1211 static void open_channel_proc( struct task
*task
)
1213 struct open_channel
*o
= (struct open_channel
*)task
;
1216 hr
= open_channel( o
->channel
, o
->endpoint
);
1218 TRACE( "calling %p(%#lx)\n", o
->ctx
.callback
, hr
);
1219 o
->ctx
.callback( hr
, WS_LONG_CALLBACK
, o
->ctx
.callbackState
);
1220 TRACE( "%p returned\n", o
->ctx
.callback
);
1223 static HRESULT
queue_open_channel( struct channel
*channel
, const WS_ENDPOINT_ADDRESS
*endpoint
,
1224 const WS_ASYNC_CONTEXT
*ctx
)
1226 struct open_channel
*o
;
1228 if (!(o
= malloc( sizeof(*o
) ))) return E_OUTOFMEMORY
;
1229 o
->task
.proc
= open_channel_proc
;
1230 o
->channel
= channel
;
1231 o
->endpoint
= endpoint
;
1233 return queue_task( &channel
->send_q
, &o
->task
);
1236 /**************************************************************************
1237 * WsOpenChannel [webservices.@]
1239 HRESULT WINAPI
WsOpenChannel( WS_CHANNEL
*handle
, const WS_ENDPOINT_ADDRESS
*endpoint
, const WS_ASYNC_CONTEXT
*ctx
,
1242 struct channel
*channel
= (struct channel
*)handle
;
1243 WS_ASYNC_CONTEXT ctx_local
;
1247 TRACE( "%p %p %p %p\n", handle
, endpoint
, ctx
, error
);
1248 if (error
) FIXME( "ignoring error parameter\n" );
1250 if (!channel
|| !endpoint
) return E_INVALIDARG
;
1252 EnterCriticalSection( &channel
->cs
);
1254 if (channel
->magic
!= CHANNEL_MAGIC
)
1256 LeaveCriticalSection( &channel
->cs
);
1257 return E_INVALIDARG
;
1259 if (channel
->state
!= WS_CHANNEL_STATE_CREATED
)
1261 LeaveCriticalSection( &channel
->cs
);
1262 return WS_E_INVALID_OPERATION
;
1265 if (!ctx
) async_init( &async
, &ctx_local
);
1266 hr
= queue_open_channel( channel
, endpoint
, ctx
? ctx
: &ctx_local
);
1269 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
1270 CloseHandle( async
.done
);
1273 LeaveCriticalSection( &channel
->cs
);
1274 TRACE( "returning %#lx\n", hr
);
1278 static HRESULT
send_message_http( HINTERNET request
, BYTE
*data
, ULONG len
)
1280 if (!WinHttpSendRequest( request
, NULL
, 0, data
, len
, len
, 0 ))
1281 return HRESULT_FROM_WIN32( GetLastError() );
1283 if (!WinHttpReceiveResponse( request
, NULL
))
1284 return HRESULT_FROM_WIN32( GetLastError() );
1288 static ULONG
get_max_buffer_size( struct channel
*channel
)
1291 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE
, &size
, sizeof(size
) );
1295 static HRESULT
write_bytes( struct channel
*channel
, BYTE
*bytes
, ULONG len
)
1297 if (!channel
->send_buf
)
1299 channel
->send_buflen
= get_max_buffer_size( channel
);
1300 if (!(channel
->send_buf
= malloc( channel
->send_buflen
))) return E_OUTOFMEMORY
;
1302 if (channel
->send_size
+ len
>= channel
->send_buflen
) return WS_E_QUOTA_EXCEEDED
;
1304 memcpy( channel
->send_buf
+ channel
->send_size
, bytes
, len
);
1305 channel
->send_size
+= len
;
1309 static inline HRESULT
write_byte( struct channel
*channel
, BYTE byte
)
1311 return write_bytes( channel
, &byte
, 1 );
1314 static HRESULT
write_size( struct channel
*channel
, ULONG size
)
1317 if (size
< 0x80) return write_byte( channel
, size
);
1318 if ((hr
= write_byte( channel
, (size
& 0x7f) | 0x80 )) != S_OK
) return hr
;
1319 if ((size
>>= 7) < 0x80) return write_byte( channel
, size
);
1320 if ((hr
= write_byte( channel
, (size
& 0x7f) | 0x80 )) != S_OK
) return hr
;
1321 if ((size
>>= 7) < 0x80) return write_byte( channel
, size
);
1322 if ((hr
= write_byte( channel
, (size
& 0x7f) | 0x80 )) != S_OK
) return hr
;
1323 if ((size
>>= 7) < 0x80) return write_byte( channel
, size
);
1324 if ((hr
= write_byte( channel
, (size
& 0x7f) | 0x80 )) != S_OK
) return hr
;
1325 if ((size
>>= 7) < 0x08) return write_byte( channel
, size
);
1326 return E_INVALIDARG
;
1329 static inline ULONG
size_length( ULONG size
)
1331 if (size
< 0x80) return 1;
1332 if (size
< 0x4000) return 2;
1333 if (size
< 0x200000) return 3;
1334 if (size
< 0x10000000) return 4;
1338 static ULONG
string_table_size( const struct dictionary
*dict
)
1341 for (i
= 0; i
< dict
->dict
.stringCount
; i
++)
1343 if (dict
->sequence
[i
] == dict
->current_sequence
)
1344 size
+= size_length( dict
->dict
.strings
[i
].length
) + dict
->dict
.strings
[i
].length
;
1349 static HRESULT
write_string_table( struct channel
*channel
, const struct dictionary
*dict
)
1353 for (i
= 0; i
< dict
->dict
.stringCount
; i
++)
1355 if (dict
->sequence
[i
] != dict
->current_sequence
) continue;
1356 if ((hr
= write_size( channel
, dict
->dict
.strings
[i
].length
)) != S_OK
) return hr
;
1357 if ((hr
= write_bytes( channel
, dict
->dict
.strings
[i
].bytes
, dict
->dict
.strings
[i
].length
)) != S_OK
) return hr
;
1362 static HRESULT
string_to_utf8( const WS_STRING
*str
, unsigned char **ret
, int *len
)
1364 *len
= WideCharToMultiByte( CP_UTF8
, 0, str
->chars
, str
->length
, NULL
, 0, NULL
, NULL
);
1365 if (!(*ret
= malloc( *len
))) return E_OUTOFMEMORY
;
1366 WideCharToMultiByte( CP_UTF8
, 0, str
->chars
, str
->length
, (char *)*ret
, *len
, NULL
, NULL
);
1372 SESSION_MODE_INVALID
= 0,
1373 SESSION_MODE_SINGLETON
= 1,
1374 SESSION_MODE_DUPLEX
= 2,
1375 SESSION_MODE_SIMPLEX
= 3,
1378 static enum session_mode
map_channel_type( struct channel
*channel
)
1380 switch (channel
->type
)
1382 case WS_CHANNEL_TYPE_DUPLEX_SESSION
: return SESSION_MODE_DUPLEX
;
1384 FIXME( "unhandled channel type %#x\n", channel
->type
);
1385 return SESSION_MODE_INVALID
;
1391 KNOWN_ENCODING_SOAP11_UTF8
= 0x00,
1392 KNOWN_ENCODING_SOAP11_UTF16
= 0x01,
1393 KNOWN_ENCODING_SOAP11_UTF16LE
= 0x02,
1394 KNOWN_ENCODING_SOAP12_UTF8
= 0x03,
1395 KNOWN_ENCODING_SOAP12_UTF16
= 0x04,
1396 KNOWN_ENCODING_SOAP12_UTF16LE
= 0x05,
1397 KNOWN_ENCODING_SOAP12_MTOM
= 0x06,
1398 KNOWN_ENCODING_SOAP12_BINARY
= 0x07,
1399 KNOWN_ENCODING_SOAP12_BINARY_SESSION
= 0x08,
1402 static enum known_encoding
map_channel_encoding( struct channel
*channel
)
1404 WS_ENVELOPE_VERSION version
;
1406 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION
, &version
, sizeof(version
) );
1410 case WS_ENVELOPE_VERSION_SOAP_1_1
:
1411 switch (channel
->encoding
)
1413 case WS_ENCODING_XML_UTF8
: return KNOWN_ENCODING_SOAP11_UTF8
;
1414 case WS_ENCODING_XML_UTF16LE
: return KNOWN_ENCODING_SOAP11_UTF16LE
;
1416 FIXME( "unhandled version/encoding %u/%u\n", version
, channel
->encoding
);
1419 case WS_ENVELOPE_VERSION_SOAP_1_2
:
1420 switch (channel
->encoding
)
1422 case WS_ENCODING_XML_UTF8
: return KNOWN_ENCODING_SOAP12_UTF8
;
1423 case WS_ENCODING_XML_UTF16LE
: return KNOWN_ENCODING_SOAP12_UTF16LE
;
1424 case WS_ENCODING_XML_BINARY_1
: return KNOWN_ENCODING_SOAP12_BINARY
;
1425 case WS_ENCODING_XML_BINARY_SESSION_1
: return KNOWN_ENCODING_SOAP12_BINARY_SESSION
;
1427 FIXME( "unhandled version/encoding %u/%u\n", version
, channel
->encoding
);
1431 ERR( "unhandled version %u\n", version
);
1436 #define FRAME_VERSION_MAJOR 1
1437 #define FRAME_VERSION_MINOR 0
1439 static HRESULT
write_preamble( struct channel
*channel
)
1445 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_VERSION
)) != S_OK
) return hr
;
1446 if ((hr
= write_byte( channel
, FRAME_VERSION_MAJOR
)) != S_OK
) return hr
;
1447 if ((hr
= write_byte( channel
, FRAME_VERSION_MINOR
)) != S_OK
) return hr
;
1449 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_MODE
)) != S_OK
) return hr
;
1450 if ((hr
= write_byte( channel
, map_channel_type(channel
) )) != S_OK
) return hr
;
1452 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_VIA
)) != S_OK
) return hr
;
1453 if ((hr
= string_to_utf8( &channel
->addr
.url
, &url
, &len
)) != S_OK
) return hr
;
1454 if ((hr
= write_size( channel
, len
)) != S_OK
) goto done
;
1455 if ((hr
= write_bytes( channel
, url
, len
)) != S_OK
) goto done
;
1457 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_KNOWN_ENCODING
)) != S_OK
) goto done
;
1458 if ((hr
= write_byte( channel
, map_channel_encoding(channel
) )) != S_OK
) goto done
;
1459 hr
= write_byte( channel
, FRAME_RECORD_TYPE_PREAMBLE_END
);
1466 static HRESULT
send_bytes( SOCKET socket
, char *bytes
, int len
)
1468 int count
= send( socket
, bytes
, len
, 0 );
1469 if (count
< 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
1470 if (count
!= len
) return WS_E_OTHER
;
1474 static HRESULT
send_preamble( struct channel
*channel
)
1477 if ((hr
= write_preamble( channel
)) != S_OK
) return hr
;
1478 if ((hr
= send_bytes( channel
->u
.tcp
.socket
, channel
->send_buf
, channel
->send_size
)) != S_OK
) return hr
;
1479 channel
->send_size
= 0;
1483 static HRESULT
receive_bytes( struct channel
*channel
, unsigned char *bytes
, int len
)
1485 int count
= recv( channel
->u
.tcp
.socket
, (char *)bytes
, len
, 0 );
1486 if (count
< 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
1487 if (count
!= len
) return WS_E_INVALID_FORMAT
;
1491 static HRESULT
receive_preamble_ack( struct channel
*channel
)
1496 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
1497 if (byte
!= FRAME_RECORD_TYPE_PREAMBLE_ACK
) return WS_E_INVALID_FORMAT
;
1498 channel
->session_state
= SESSION_STATE_SETUP_COMPLETE
;
1502 static HRESULT
write_sized_envelope( struct channel
*channel
, BYTE
*data
, ULONG len
)
1504 ULONG table_size
= string_table_size( &channel
->dict_send
);
1507 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_SIZED_ENVELOPE
)) != S_OK
) return hr
;
1508 if ((hr
= write_size( channel
, size_length(table_size
) + table_size
+ len
)) != S_OK
) return hr
;
1509 if ((hr
= write_size( channel
, table_size
)) != S_OK
) return hr
;
1510 if ((hr
= write_string_table( channel
, &channel
->dict_send
)) != S_OK
) return hr
;
1511 return write_bytes( channel
, data
, len
);
1514 static HRESULT
send_sized_envelope( struct channel
*channel
, BYTE
*data
, ULONG len
)
1517 if ((hr
= write_sized_envelope( channel
, data
, len
)) != S_OK
) return hr
;
1518 if ((hr
= send_bytes( channel
->u
.tcp
.socket
, channel
->send_buf
, channel
->send_size
)) != S_OK
) return hr
;
1519 channel
->send_size
= 0;
1523 static HRESULT
open_http_request( struct channel
*channel
, HINTERNET
*req
)
1525 if ((*req
= WinHttpOpenRequest( channel
->u
.http
.connect
, L
"POST", channel
->u
.http
.path
,
1526 NULL
, NULL
, NULL
, channel
->u
.http
.flags
))) return S_OK
;
1527 return HRESULT_FROM_WIN32( GetLastError() );
1530 static HRESULT
send_message_bytes( struct channel
*channel
, WS_MESSAGE
*msg
)
1532 WS_XML_WRITER
*writer
;
1537 WsGetMessageProperty( channel
->msg
, WS_MESSAGE_PROPERTY_BODY_WRITER
, &writer
, sizeof(writer
), NULL
);
1538 WsGetWriterProperty( writer
, WS_XML_WRITER_PROPERTY_BYTES
, &buf
, sizeof(buf
), NULL
);
1540 switch (channel
->binding
)
1542 case WS_HTTP_CHANNEL_BINDING
:
1543 if (channel
->u
.http
.request
)
1545 WinHttpCloseHandle( channel
->u
.http
.request
);
1546 channel
->u
.http
.request
= NULL
;
1548 if ((hr
= open_http_request( channel
, &channel
->u
.http
.request
)) != S_OK
) return hr
;
1549 if ((hr
= message_insert_http_headers( msg
, channel
->u
.http
.request
)) != S_OK
) return hr
;
1550 return send_message_http( channel
->u
.http
.request
, buf
.bytes
, buf
.length
);
1552 case WS_TCP_CHANNEL_BINDING
:
1553 if (channel
->type
& WS_CHANNEL_TYPE_SESSION
)
1555 switch (channel
->session_state
)
1557 case SESSION_STATE_UNINITIALIZED
:
1558 if ((hr
= send_preamble( channel
)) != S_OK
) return hr
;
1559 if ((hr
= receive_preamble_ack( channel
)) != S_OK
) return hr
;
1562 case SESSION_STATE_SETUP_COMPLETE
:
1563 return send_sized_envelope( channel
, buf
.bytes
, buf
.length
);
1566 ERR( "unhandled session state %u\n", channel
->session_state
);
1572 case WS_UDP_CHANNEL_BINDING
:
1573 return WsFlushWriter( writer
, 0, NULL
, NULL
);
1576 ERR( "unhandled binding %u\n", channel
->binding
);
1581 HRESULT
channel_send_message( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
)
1583 struct channel
*channel
= (struct channel
*)handle
;
1586 EnterCriticalSection( &channel
->cs
);
1588 if (channel
->magic
!= CHANNEL_MAGIC
)
1590 LeaveCriticalSection( &channel
->cs
);
1591 return E_INVALIDARG
;
1593 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
1595 LeaveCriticalSection( &channel
->cs
);
1596 return WS_E_INVALID_OPERATION
;
1599 hr
= send_message_bytes( channel
, msg
);
1601 LeaveCriticalSection( &channel
->cs
);
1605 static HRESULT CALLBACK
dict_cb( void *state
, const WS_XML_STRING
*str
, BOOL
*found
, ULONG
*id
, WS_ERROR
*error
)
1607 struct dictionary
*dict
= state
;
1612 if ((index
= find_string( dict
, str
->bytes
, str
->length
, id
)) == -1)
1618 if (!(bytes
= malloc( str
->length
))) return E_OUTOFMEMORY
;
1619 memcpy( bytes
, str
->bytes
, str
->length
);
1620 if ((hr
= insert_string( dict
, bytes
, str
->length
, index
, id
)) == S_OK
)
1631 static CALLBACK HRESULT
write_callback( void *state
, const WS_BYTES
*buf
, ULONG count
, const WS_ASYNC_CONTEXT
*ctx
,
1634 SOCKET socket
= *(SOCKET
*)state
;
1635 if (send( socket
, (const char *)buf
->bytes
, buf
->length
, 0 ) < 0)
1637 TRACE( "send failed %u\n", WSAGetLastError() );
1642 static HRESULT
init_writer( struct channel
*channel
)
1644 WS_XML_WRITER_BUFFER_OUTPUT buf
= {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER
}};
1645 WS_XML_WRITER_STREAM_OUTPUT stream
= {{WS_XML_WRITER_OUTPUT_TYPE_STREAM
}};
1646 WS_XML_WRITER_TEXT_ENCODING text
= {{WS_XML_WRITER_ENCODING_TYPE_TEXT
}, WS_CHARSET_UTF8
};
1647 WS_XML_WRITER_BINARY_ENCODING bin
= {{WS_XML_WRITER_ENCODING_TYPE_BINARY
}};
1648 const WS_XML_WRITER_ENCODING
*encoding
;
1649 const WS_XML_WRITER_OUTPUT
*output
;
1650 WS_XML_WRITER_PROPERTY prop
;
1651 ULONG max_size
= (1 << 17);
1654 prop
.id
= WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE
;
1655 prop
.value
= &max_size
;
1656 prop
.valueSize
= sizeof(max_size
);
1657 if (!channel
->writer
&& (hr
= WsCreateWriter( &prop
, 1, &channel
->writer
, NULL
)) != S_OK
) return hr
;
1659 switch (channel
->encoding
)
1661 case WS_ENCODING_XML_UTF8
:
1662 encoding
= &text
.encoding
;
1663 if (channel
->binding
== WS_UDP_CHANNEL_BINDING
||
1664 (channel
->binding
== WS_TCP_CHANNEL_BINDING
&& !(channel
->type
& WS_CHANNEL_TYPE_SESSION
)))
1666 stream
.writeCallback
= write_callback
;
1667 stream
.writeCallbackState
= (channel
->binding
== WS_UDP_CHANNEL_BINDING
) ?
1668 &channel
->u
.udp
.socket
: &channel
->u
.tcp
.socket
;
1669 output
= &stream
.output
;
1671 else output
= &buf
.output
;
1674 case WS_ENCODING_XML_BINARY_SESSION_1
:
1675 bin
.staticDictionary
= (WS_XML_DICTIONARY
*)&dict_builtin_static
.dict
;
1678 case WS_ENCODING_XML_BINARY_1
:
1679 encoding
= &bin
.encoding
;
1680 output
= &buf
.output
;
1684 FIXME( "unhandled encoding %u\n", channel
->encoding
);
1685 return WS_E_NOT_SUPPORTED
;
1688 return WsSetOutput( channel
->writer
, encoding
, output
, NULL
, 0, NULL
);
1691 static HRESULT
write_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ELEMENT_DESCRIPTION
*desc
,
1692 WS_WRITE_OPTION option
, const void *body
, ULONG size
)
1695 if ((hr
= writer_set_lookup( channel
->writer
, TRUE
)) != S_OK
) return hr
;
1696 if ((hr
= WsWriteEnvelopeStart( msg
, channel
->writer
, NULL
, NULL
, NULL
)) != S_OK
) return hr
;
1697 if ((hr
= writer_set_lookup( channel
->writer
, FALSE
)) != S_OK
) return hr
;
1698 channel
->dict_send
.current_sequence
++;
1699 if ((hr
= writer_set_dict_callback( channel
->writer
, dict_cb
, &channel
->dict_send
)) != S_OK
) return hr
;
1700 if ((hr
= WsWriteBody( msg
, desc
, option
, body
, size
, NULL
)) != S_OK
) return hr
;
1701 return WsWriteEnvelopeEnd( msg
, NULL
);
1704 static HRESULT
send_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
1705 WS_WRITE_OPTION option
, const void *body
, ULONG size
)
1708 if ((hr
= WsAddressMessage( msg
, &channel
->addr
, NULL
)) != S_OK
) return hr
;
1709 if ((hr
= message_set_action( msg
, desc
->action
)) != S_OK
) return hr
;
1710 if ((hr
= init_writer( channel
)) != S_OK
) return hr
;
1711 if ((hr
= write_message( channel
, msg
, desc
->bodyElementDescription
, option
, body
, size
)) != S_OK
) return hr
;
1712 return send_message_bytes( channel
, msg
);
1718 struct channel
*channel
;
1720 const WS_MESSAGE_DESCRIPTION
*desc
;
1721 WS_WRITE_OPTION option
;
1724 WS_ASYNC_CONTEXT ctx
;
1727 static void send_message_proc( struct task
*task
)
1729 struct send_message
*s
= (struct send_message
*)task
;
1732 hr
= send_message( s
->channel
, s
->msg
, s
->desc
, s
->option
, s
->body
, s
->size
);
1734 TRACE( "calling %p(%#lx)\n", s
->ctx
.callback
, hr
);
1735 s
->ctx
.callback( hr
, WS_LONG_CALLBACK
, s
->ctx
.callbackState
);
1736 TRACE( "%p returned\n", s
->ctx
.callback
);
1739 static HRESULT
queue_send_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
1740 WS_WRITE_OPTION option
, const void *body
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
)
1742 struct send_message
*s
;
1744 if (!(s
= malloc( sizeof(*s
) ))) return E_OUTOFMEMORY
;
1745 s
->task
.proc
= send_message_proc
;
1746 s
->channel
= channel
;
1753 return queue_task( &channel
->send_q
, &s
->task
);
1756 /**************************************************************************
1757 * WsSendMessage [webservices.@]
1759 HRESULT WINAPI
WsSendMessage( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
1760 WS_WRITE_OPTION option
, const void *body
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
,
1763 struct channel
*channel
= (struct channel
*)handle
;
1764 WS_ASYNC_CONTEXT ctx_local
;
1768 TRACE( "%p %p %p %u %p %lu %p %p\n", handle
, msg
, desc
, option
, body
, size
, ctx
, error
);
1769 if (error
) FIXME( "ignoring error parameter\n" );
1771 if (!channel
|| !msg
|| !desc
) return E_INVALIDARG
;
1773 EnterCriticalSection( &channel
->cs
);
1775 if (channel
->magic
!= CHANNEL_MAGIC
)
1777 LeaveCriticalSection( &channel
->cs
);
1778 return E_INVALIDARG
;
1780 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
1782 LeaveCriticalSection( &channel
->cs
);
1783 return WS_E_INVALID_OPERATION
;
1786 WsInitializeMessage( msg
, WS_BLANK_MESSAGE
, NULL
, NULL
);
1788 if (!ctx
) async_init( &async
, &ctx_local
);
1789 hr
= queue_send_message( channel
, msg
, desc
, option
, body
, size
, ctx
? ctx
: &ctx_local
);
1792 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
1793 CloseHandle( async
.done
);
1796 LeaveCriticalSection( &channel
->cs
);
1797 TRACE( "returning %#lx\n", hr
);
1801 /**************************************************************************
1802 * WsSendReplyMessage [webservices.@]
1804 HRESULT WINAPI
WsSendReplyMessage( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
1805 WS_WRITE_OPTION option
, const void *body
, ULONG size
, WS_MESSAGE
*request
,
1806 const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
1808 struct channel
*channel
= (struct channel
*)handle
;
1809 WS_ASYNC_CONTEXT ctx_local
;
1814 TRACE( "%p %p %p %u %p %lu %p %p %p\n", handle
, msg
, desc
, option
, body
, size
, request
, ctx
, error
);
1815 if (error
) FIXME( "ignoring error parameter\n" );
1817 if (!channel
|| !msg
|| !desc
|| !request
) return E_INVALIDARG
;
1819 EnterCriticalSection( &channel
->cs
);
1821 if (channel
->magic
!= CHANNEL_MAGIC
)
1823 LeaveCriticalSection( &channel
->cs
);
1824 return E_INVALIDARG
;
1826 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
1828 LeaveCriticalSection( &channel
->cs
);
1829 return WS_E_INVALID_OPERATION
;
1832 WsInitializeMessage( msg
, WS_REPLY_MESSAGE
, NULL
, NULL
);
1833 if ((hr
= message_get_id( request
, &id
)) != S_OK
) goto done
;
1834 if ((hr
= message_set_request_id( msg
, &id
)) != S_OK
) goto done
;
1836 if (!ctx
) async_init( &async
, &ctx_local
);
1837 hr
= queue_send_message( channel
, msg
, desc
, option
, body
, size
, ctx
? ctx
: &ctx_local
);
1840 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
1841 CloseHandle( async
.done
);
1845 LeaveCriticalSection( &channel
->cs
);
1846 TRACE( "returning %#lx\n", hr
);
1850 static HRESULT
resize_read_buffer( struct channel
*channel
, ULONG size
)
1852 if (!channel
->read_buf
)
1854 if (!(channel
->read_buf
= malloc( size
))) return E_OUTOFMEMORY
;
1855 channel
->read_buflen
= size
;
1858 if (channel
->read_buflen
< size
)
1861 ULONG new_size
= max( size
, channel
->read_buflen
* 2 );
1862 if (!(tmp
= realloc( channel
->read_buf
, new_size
))) return E_OUTOFMEMORY
;
1863 channel
->read_buf
= tmp
;
1864 channel
->read_buflen
= new_size
;
1869 static CALLBACK HRESULT
read_callback( void *state
, void *buf
, ULONG buflen
, ULONG
*retlen
,
1870 const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
1872 SOCKET socket
= *(SOCKET
*)state
;
1875 if ((ret
= recv( socket
, buf
, buflen
, 0 )) >= 0) *retlen
= ret
;
1878 TRACE( "recv failed %u\n", WSAGetLastError() );
1884 static HRESULT
init_reader( struct channel
*channel
)
1886 WS_XML_READER_BUFFER_INPUT buf
= {{WS_XML_READER_INPUT_TYPE_BUFFER
}};
1887 WS_XML_READER_STREAM_INPUT stream
= {{WS_XML_READER_INPUT_TYPE_STREAM
}};
1888 WS_XML_READER_TEXT_ENCODING text
= {{WS_XML_READER_ENCODING_TYPE_TEXT
}};
1889 WS_XML_READER_BINARY_ENCODING bin
= {{WS_XML_READER_ENCODING_TYPE_BINARY
}};
1890 const WS_XML_READER_ENCODING
*encoding
;
1891 const WS_XML_READER_INPUT
*input
;
1894 if (!channel
->reader
&& (hr
= WsCreateReader( NULL
, 0, &channel
->reader
, NULL
)) != S_OK
) return hr
;
1896 switch (channel
->encoding
)
1898 case WS_ENCODING_XML_UTF8
:
1899 text
.charSet
= WS_CHARSET_UTF8
;
1900 encoding
= &text
.encoding
;
1902 if (channel
->binding
== WS_UDP_CHANNEL_BINDING
||
1903 (channel
->binding
== WS_TCP_CHANNEL_BINDING
&& !(channel
->type
& WS_CHANNEL_TYPE_SESSION
)))
1905 stream
.readCallback
= read_callback
;
1906 stream
.readCallbackState
= (channel
->binding
== WS_UDP_CHANNEL_BINDING
) ?
1907 &channel
->u
.udp
.socket
: &channel
->u
.tcp
.socket
;
1908 input
= &stream
.input
;
1912 buf
.encodedData
= channel
->read_buf
;
1913 buf
.encodedDataSize
= channel
->read_size
;
1918 case WS_ENCODING_XML_BINARY_SESSION_1
:
1919 bin
.staticDictionary
= (WS_XML_DICTIONARY
*)&dict_builtin_static
.dict
;
1920 bin
.dynamicDictionary
= &channel
->dict_recv
.dict
;
1923 case WS_ENCODING_XML_BINARY_1
:
1924 encoding
= &bin
.encoding
;
1926 buf
.encodedData
= channel
->read_buf
;
1927 buf
.encodedDataSize
= channel
->read_size
;
1932 FIXME( "unhandled encoding %u\n", channel
->encoding
);
1933 return WS_E_NOT_SUPPORTED
;
1936 return WsSetInput( channel
->reader
, encoding
, input
, NULL
, 0, NULL
);
1939 static const WS_HTTP_MESSAGE_MAPPING
*get_http_message_mapping( struct channel
*channel
)
1941 const struct prop
*prop
= &channel
->prop
[WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING
];
1942 return (const WS_HTTP_MESSAGE_MAPPING
*)prop
->value
;
1945 static HRESULT
map_http_response_headers( struct channel
*channel
, WS_MESSAGE
*msg
)
1947 const WS_HTTP_MESSAGE_MAPPING
*mapping
= get_http_message_mapping( channel
);
1948 return message_map_http_response_headers( msg
, channel
->u
.http
.request
, mapping
);
1951 #define INITIAL_READ_BUFFER_SIZE 4096
1952 static HRESULT
receive_message_bytes_http( struct channel
*channel
, WS_MESSAGE
*msg
)
1954 DWORD len
, bytes_read
, offset
= 0, size
= INITIAL_READ_BUFFER_SIZE
;
1955 ULONG max_len
= get_max_buffer_size( channel
);
1958 if ((hr
= map_http_response_headers( channel
, msg
)) != S_OK
) return hr
;
1960 if ((hr
= resize_read_buffer( channel
, size
)) != S_OK
) return hr
;
1961 channel
->read_size
= 0;
1964 if (!WinHttpQueryDataAvailable( channel
->u
.http
.request
, &len
))
1966 return HRESULT_FROM_WIN32( GetLastError() );
1969 if (channel
->read_size
+ len
> max_len
) return WS_E_QUOTA_EXCEEDED
;
1970 if ((hr
= resize_read_buffer( channel
, channel
->read_size
+ len
)) != S_OK
) return hr
;
1972 if (!WinHttpReadData( channel
->u
.http
.request
, channel
->read_buf
+ offset
, len
, &bytes_read
))
1974 return HRESULT_FROM_WIN32( GetLastError() );
1976 if (!bytes_read
) break;
1977 channel
->read_size
+= bytes_read
;
1978 offset
+= bytes_read
;
1984 static HRESULT
receive_message_sized( struct channel
*channel
, unsigned int size
)
1986 unsigned int offset
= 0, to_read
= size
;
1990 if ((hr
= resize_read_buffer( channel
, size
)) != S_OK
) return hr
;
1992 channel
->read_size
= 0;
1993 while (channel
->read_size
< size
)
1995 if ((bytes_read
= recv( channel
->u
.tcp
.socket
, channel
->read_buf
+ offset
, to_read
, 0 )) < 0)
1997 return HRESULT_FROM_WIN32( WSAGetLastError() );
1999 if (!bytes_read
) break;
2000 channel
->read_size
+= bytes_read
;
2001 to_read
-= bytes_read
;
2002 offset
+= bytes_read
;
2004 if (channel
->read_size
!= size
) return WS_E_INVALID_FORMAT
;
2008 static HRESULT
receive_size( struct channel
*channel
, unsigned int *size
)
2013 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2014 *size
= byte
& 0x7f;
2015 if (!(byte
& 0x80)) return S_OK
;
2017 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2018 *size
+= (byte
& 0x7f) << 7;
2019 if (!(byte
& 0x80)) return S_OK
;
2021 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2022 *size
+= (byte
& 0x7f) << 14;
2023 if (!(byte
& 0x80)) return S_OK
;
2025 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2026 *size
+= (byte
& 0x7f) << 21;
2027 if (!(byte
& 0x80)) return S_OK
;
2029 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2030 if (byte
& ~0x0f) return WS_E_INVALID_FORMAT
;
2031 *size
+= byte
<< 28;
2035 static WS_ENCODING
map_known_encoding( enum known_encoding encoding
)
2039 case KNOWN_ENCODING_SOAP11_UTF8
:
2040 case KNOWN_ENCODING_SOAP12_UTF8
: return WS_ENCODING_XML_UTF8
;
2041 case KNOWN_ENCODING_SOAP11_UTF16
:
2042 case KNOWN_ENCODING_SOAP12_UTF16
: return WS_ENCODING_XML_UTF16BE
;
2043 case KNOWN_ENCODING_SOAP11_UTF16LE
:
2044 case KNOWN_ENCODING_SOAP12_UTF16LE
: return WS_ENCODING_XML_UTF16LE
;
2045 case KNOWN_ENCODING_SOAP12_BINARY
: return WS_ENCODING_XML_BINARY_1
;
2046 case KNOWN_ENCODING_SOAP12_BINARY_SESSION
: return WS_ENCODING_XML_BINARY_SESSION_1
;
2048 WARN( "unhandled encoding %u, assuming UTF8\n", encoding
);
2049 return WS_ENCODING_XML_UTF8
;
2053 static HRESULT
receive_preamble( struct channel
*channel
)
2060 if ((hr
= receive_bytes( channel
, &type
, 1 )) != S_OK
) return hr
;
2061 if (type
== FRAME_RECORD_TYPE_PREAMBLE_END
) break;
2064 case FRAME_RECORD_TYPE_VERSION
:
2066 unsigned char major
, minor
;
2067 if ((hr
= receive_bytes( channel
, &major
, 1 )) != S_OK
) return hr
;
2068 if ((hr
= receive_bytes( channel
, &minor
, 1 )) != S_OK
) return hr
;
2069 TRACE( "major %u minor %u\n", major
, major
);
2072 case FRAME_RECORD_TYPE_MODE
:
2075 if ((hr
= receive_bytes( channel
, &mode
, 1 )) != S_OK
) return hr
;
2076 TRACE( "mode %u\n", mode
);
2079 case FRAME_RECORD_TYPE_VIA
:
2084 if ((hr
= receive_size( channel
, &size
)) != S_OK
) return hr
;
2085 if (!(url
= malloc( size
))) return E_OUTOFMEMORY
;
2086 if ((hr
= receive_bytes( channel
, url
, size
)) != S_OK
)
2091 TRACE( "transport URL %s\n", debugstr_an((char *)url
, size
) );
2092 free( url
); /* FIXME: verify */
2095 case FRAME_RECORD_TYPE_KNOWN_ENCODING
:
2097 unsigned char encoding
;
2098 if ((hr
= receive_bytes( channel
, &encoding
, 1 )) != S_OK
) return hr
;
2099 TRACE( "encoding %u\n", encoding
);
2100 channel
->encoding
= map_known_encoding( encoding
);
2104 WARN( "unhandled record type %u\n", type
);
2105 return WS_E_INVALID_FORMAT
;
2112 static HRESULT
receive_sized_envelope( struct channel
*channel
)
2118 if ((hr
= receive_bytes( channel
, &type
, 1 )) != S_OK
) return hr
;
2119 if (type
== FRAME_RECORD_TYPE_END
) return WS_S_END
;
2120 if (type
!= FRAME_RECORD_TYPE_SIZED_ENVELOPE
) return WS_E_INVALID_FORMAT
;
2121 if ((hr
= receive_size( channel
, &size
)) != S_OK
) return hr
;
2122 if ((hr
= receive_message_sized( channel
, size
)) != S_OK
) return hr
;
2126 static HRESULT
read_size( const BYTE
**ptr
, ULONG len
, ULONG
*size
)
2128 const BYTE
*buf
= *ptr
;
2130 if (len
< 1) return WS_E_INVALID_FORMAT
;
2131 *size
= buf
[0] & 0x7f;
2132 if (!(buf
[0] & 0x80))
2137 if (len
< 2) return WS_E_INVALID_FORMAT
;
2138 *size
+= (buf
[1] & 0x7f) << 7;
2139 if (!(buf
[1] & 0x80))
2144 if (len
< 3) return WS_E_INVALID_FORMAT
;
2145 *size
+= (buf
[2] & 0x7f) << 14;
2146 if (!(buf
[2] & 0x80))
2151 if (len
< 4) return WS_E_INVALID_FORMAT
;
2152 *size
+= (buf
[3] & 0x7f) << 21;
2153 if (!(buf
[3] & 0x80))
2158 if (len
< 5 || (buf
[4] & ~0x07)) return WS_E_INVALID_FORMAT
;
2159 *size
+= buf
[4] << 28;
2164 static HRESULT
build_dict( const BYTE
*buf
, ULONG buflen
, struct dictionary
*dict
, ULONG
*used
)
2166 ULONG size
, strings_size
, strings_offset
;
2167 const BYTE
*ptr
= buf
;
2172 if ((hr
= read_size( &ptr
, buflen
, &strings_size
)) != S_OK
) return hr
;
2173 strings_offset
= ptr
- buf
;
2174 if (buflen
< strings_offset
+ strings_size
) return WS_E_INVALID_FORMAT
;
2175 *used
= strings_offset
+ strings_size
;
2176 if (!strings_size
) return S_OK
;
2178 UuidCreate( &dict
->dict
.guid
);
2179 dict
->dict
.isConst
= FALSE
;
2181 buflen
-= strings_offset
;
2182 ptr
= buf
+ strings_offset
;
2183 while (ptr
< buf
+ strings_size
)
2185 if ((hr
= read_size( &ptr
, buflen
, &size
)) != S_OK
)
2193 return WS_E_INVALID_FORMAT
;
2196 if (!(bytes
= malloc( size
)))
2201 memcpy( bytes
, ptr
, size
);
2202 if ((index
= find_string( dict
, bytes
, size
, NULL
)) == -1) /* duplicate */
2208 if ((hr
= insert_string( dict
, bytes
, size
, index
, NULL
)) != S_OK
)
2223 static HRESULT
send_preamble_ack( struct channel
*channel
)
2226 if ((hr
= send_byte( channel
->u
.tcp
.socket
, FRAME_RECORD_TYPE_PREAMBLE_ACK
)) != S_OK
) return hr
;
2227 channel
->session_state
= SESSION_STATE_SETUP_COMPLETE
;
2231 static HRESULT
receive_message_bytes_session( struct channel
*channel
)
2235 if ((hr
= receive_sized_envelope( channel
)) != S_OK
) return hr
;
2236 if (channel
->encoding
== WS_ENCODING_XML_BINARY_SESSION_1
)
2239 if ((hr
= build_dict( (const BYTE
*)channel
->read_buf
, channel
->read_size
, &channel
->dict_recv
,
2240 &size
)) != S_OK
) return hr
;
2241 channel
->read_size
-= size
;
2242 memmove( channel
->read_buf
, channel
->read_buf
+ size
, channel
->read_size
);
2248 static HRESULT
receive_message_bytes( struct channel
*channel
, WS_MESSAGE
*msg
)
2250 switch (channel
->binding
)
2252 case WS_HTTP_CHANNEL_BINDING
:
2253 return receive_message_bytes_http( channel
, msg
);
2255 case WS_TCP_CHANNEL_BINDING
:
2256 if (channel
->type
& WS_CHANNEL_TYPE_SESSION
)
2259 switch (channel
->session_state
)
2261 case SESSION_STATE_UNINITIALIZED
:
2262 if ((hr
= receive_preamble( channel
)) != S_OK
) return hr
;
2263 if ((hr
= send_preamble_ack( channel
)) != S_OK
) return hr
;
2266 case SESSION_STATE_SETUP_COMPLETE
:
2267 return receive_message_bytes_session( channel
);
2270 ERR( "unhandled session state %u\n", channel
->session_state
);
2274 return S_OK
; /* nothing to do, data is read through stream callback */
2276 case WS_UDP_CHANNEL_BINDING
:
2280 ERR( "unhandled binding %u\n", channel
->binding
);
2285 HRESULT
channel_receive_message( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
)
2287 struct channel
*channel
= (struct channel
*)handle
;
2290 EnterCriticalSection( &channel
->cs
);
2292 if (channel
->magic
!= CHANNEL_MAGIC
)
2294 LeaveCriticalSection( &channel
->cs
);
2295 return E_INVALIDARG
;
2297 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2299 LeaveCriticalSection( &channel
->cs
);
2300 return WS_E_INVALID_OPERATION
;
2303 if ((hr
= receive_message_bytes( channel
, msg
)) == S_OK
) hr
= init_reader( channel
);
2305 LeaveCriticalSection( &channel
->cs
);
2309 HRESULT
channel_get_reader( WS_CHANNEL
*handle
, WS_XML_READER
**reader
)
2311 struct channel
*channel
= (struct channel
*)handle
;
2313 EnterCriticalSection( &channel
->cs
);
2315 if (channel
->magic
!= CHANNEL_MAGIC
)
2317 LeaveCriticalSection( &channel
->cs
);
2318 return E_INVALIDARG
;
2321 *reader
= channel
->reader
;
2323 LeaveCriticalSection( &channel
->cs
);
2327 static HRESULT
read_message( WS_MESSAGE
*handle
, WS_XML_READER
*reader
, const WS_ELEMENT_DESCRIPTION
*desc
,
2328 WS_READ_OPTION option
, WS_HEAP
*heap
, void *body
, ULONG size
)
2331 if ((hr
= WsReadEnvelopeStart( handle
, reader
, NULL
, NULL
, NULL
)) != S_OK
) return hr
;
2332 if ((hr
= WsReadBody( handle
, desc
, option
, heap
, body
, size
, NULL
)) != S_OK
) return hr
;
2333 return WsReadEnvelopeEnd( handle
, NULL
);
2336 static HRESULT
receive_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
**desc
,
2337 ULONG count
, WS_RECEIVE_OPTION option
, WS_READ_OPTION read_option
, WS_HEAP
*heap
,
2338 void *value
, ULONG size
, ULONG
*index
)
2343 if ((hr
= receive_message_bytes( channel
, msg
)) != S_OK
) return hr
;
2344 if ((hr
= init_reader( channel
)) != S_OK
) return hr
;
2346 for (i
= 0; i
< count
; i
++)
2348 const WS_ELEMENT_DESCRIPTION
*body
= desc
[i
]->bodyElementDescription
;
2349 if ((hr
= read_message( msg
, channel
->reader
, body
, read_option
, heap
, value
, size
)) == S_OK
)
2351 if (index
) *index
= i
;
2354 if ((hr
= WsResetMessage( msg
, NULL
)) != S_OK
) return hr
;
2355 if ((hr
= init_reader( channel
)) != S_OK
) return hr
;
2357 return (i
== count
) ? WS_E_INVALID_FORMAT
: S_OK
;
2360 struct receive_message
2363 struct channel
*channel
;
2365 const WS_MESSAGE_DESCRIPTION
**desc
;
2367 WS_RECEIVE_OPTION option
;
2368 WS_READ_OPTION read_option
;
2373 WS_ASYNC_CONTEXT ctx
;
2376 static void receive_message_proc( struct task
*task
)
2378 struct receive_message
*r
= (struct receive_message
*)task
;
2381 hr
= receive_message( r
->channel
, r
->msg
, r
->desc
, r
->count
, r
->option
, r
->read_option
, r
->heap
, r
->value
,
2382 r
->size
, r
->index
);
2384 TRACE( "calling %p(%#lx)\n", r
->ctx
.callback
, hr
);
2385 r
->ctx
.callback( hr
, WS_LONG_CALLBACK
, r
->ctx
.callbackState
);
2386 TRACE( "%p returned\n", r
->ctx
.callback
);
2389 static HRESULT
queue_receive_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
**desc
,
2390 ULONG count
, WS_RECEIVE_OPTION option
, WS_READ_OPTION read_option
,
2391 WS_HEAP
*heap
, void *value
, ULONG size
, ULONG
*index
,
2392 const WS_ASYNC_CONTEXT
*ctx
)
2394 struct receive_message
*r
;
2396 if (!(r
= malloc( sizeof(*r
) ))) return E_OUTOFMEMORY
;
2397 r
->task
.proc
= receive_message_proc
;
2398 r
->channel
= channel
;
2403 r
->read_option
= read_option
;
2409 return queue_task( &channel
->recv_q
, &r
->task
);
2412 /**************************************************************************
2413 * WsReceiveMessage [webservices.@]
2415 HRESULT WINAPI
WsReceiveMessage( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
**desc
,
2416 ULONG count
, WS_RECEIVE_OPTION option
, WS_READ_OPTION read_option
, WS_HEAP
*heap
,
2417 void *value
, ULONG size
, ULONG
*index
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2419 struct channel
*channel
= (struct channel
*)handle
;
2420 WS_ASYNC_CONTEXT ctx_local
;
2424 TRACE( "%p %p %p %lu %u %u %p %p %lu %p %p %p\n", handle
, msg
, desc
, count
, option
, read_option
, heap
,
2425 value
, size
, index
, ctx
, error
);
2426 if (error
) FIXME( "ignoring error parameter\n" );
2428 if (!channel
|| !msg
|| !desc
|| !count
) return E_INVALIDARG
;
2430 EnterCriticalSection( &channel
->cs
);
2432 if (channel
->magic
!= CHANNEL_MAGIC
)
2434 LeaveCriticalSection( &channel
->cs
);
2435 return E_INVALIDARG
;
2437 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2439 LeaveCriticalSection( &channel
->cs
);
2440 return WS_E_INVALID_OPERATION
;
2443 if (!ctx
) async_init( &async
, &ctx_local
);
2444 hr
= queue_receive_message( channel
, msg
, desc
, count
, option
, read_option
, heap
, value
, size
, index
,
2445 ctx
? ctx
: &ctx_local
);
2448 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2449 CloseHandle( async
.done
);
2452 LeaveCriticalSection( &channel
->cs
);
2453 TRACE( "returning %#lx\n", hr
);
2457 static HRESULT
request_reply( struct channel
*channel
, WS_MESSAGE
*request
,
2458 const WS_MESSAGE_DESCRIPTION
*request_desc
, WS_WRITE_OPTION write_option
,
2459 const void *request_body
, ULONG request_size
, WS_MESSAGE
*reply
,
2460 const WS_MESSAGE_DESCRIPTION
*reply_desc
, WS_READ_OPTION read_option
,
2461 WS_HEAP
*heap
, void *value
, ULONG size
)
2465 if ((hr
= send_message( channel
, request
, request_desc
, write_option
, request_body
, request_size
)) != S_OK
)
2468 return receive_message( channel
, reply
, &reply_desc
, 1, WS_RECEIVE_OPTIONAL_MESSAGE
, read_option
, heap
,
2469 value
, size
, NULL
);
2472 struct request_reply
2475 struct channel
*channel
;
2476 WS_MESSAGE
*request
;
2477 const WS_MESSAGE_DESCRIPTION
*request_desc
;
2478 WS_WRITE_OPTION write_option
;
2479 const void *request_body
;
2482 const WS_MESSAGE_DESCRIPTION
*reply_desc
;
2483 WS_READ_OPTION read_option
;
2487 WS_ASYNC_CONTEXT ctx
;
2490 static void request_reply_proc( struct task
*task
)
2492 struct request_reply
*r
= (struct request_reply
*)task
;
2495 hr
= request_reply( r
->channel
, r
->request
, r
->request_desc
, r
->write_option
, r
->request_body
, r
->request_size
,
2496 r
->reply
, r
->reply_desc
, r
->read_option
, r
->heap
, r
->value
, r
->size
);
2498 TRACE( "calling %p(%#lx)\n", r
->ctx
.callback
, hr
);
2499 r
->ctx
.callback( hr
, WS_LONG_CALLBACK
, r
->ctx
.callbackState
);
2500 TRACE( "%p returned\n", r
->ctx
.callback
);
2503 static HRESULT
queue_request_reply( struct channel
*channel
, WS_MESSAGE
*request
,
2504 const WS_MESSAGE_DESCRIPTION
*request_desc
, WS_WRITE_OPTION write_option
,
2505 const void *request_body
, ULONG request_size
, WS_MESSAGE
*reply
,
2506 const WS_MESSAGE_DESCRIPTION
*reply_desc
, WS_READ_OPTION read_option
,
2507 WS_HEAP
*heap
, void *value
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
)
2509 struct request_reply
*r
;
2511 if (!(r
= malloc( sizeof(*r
) ))) return E_OUTOFMEMORY
;
2512 r
->task
.proc
= request_reply_proc
;
2513 r
->channel
= channel
;
2514 r
->request
= request
;
2515 r
->request_desc
= request_desc
;
2516 r
->write_option
= write_option
;
2517 r
->request_body
= request_body
;
2518 r
->request_size
= request_size
;
2520 r
->reply_desc
= reply_desc
;
2521 r
->read_option
= read_option
;
2526 return queue_task( &channel
->recv_q
, &r
->task
);
2529 /**************************************************************************
2530 * WsRequestReply [webservices.@]
2532 HRESULT WINAPI
WsRequestReply( WS_CHANNEL
*handle
, WS_MESSAGE
*request
, const WS_MESSAGE_DESCRIPTION
*request_desc
,
2533 WS_WRITE_OPTION write_option
, const void *request_body
, ULONG request_size
,
2534 WS_MESSAGE
*reply
, const WS_MESSAGE_DESCRIPTION
*reply_desc
, WS_READ_OPTION read_option
,
2535 WS_HEAP
*heap
, void *value
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2537 struct channel
*channel
= (struct channel
*)handle
;
2538 WS_ASYNC_CONTEXT ctx_local
;
2542 TRACE( "%p %p %p %u %p %lu %p %p %u %p %p %lu %p %p\n", handle
, request
, request_desc
, write_option
,
2543 request_body
, request_size
, reply
, reply_desc
, read_option
, heap
, value
, size
, ctx
, error
);
2544 if (error
) FIXME( "ignoring error parameter\n" );
2546 if (!channel
|| !request
|| !reply
) return E_INVALIDARG
;
2548 EnterCriticalSection( &channel
->cs
);
2550 if (channel
->magic
!= CHANNEL_MAGIC
)
2552 LeaveCriticalSection( &channel
->cs
);
2553 return E_INVALIDARG
;
2555 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2557 LeaveCriticalSection( &channel
->cs
);
2558 return WS_E_INVALID_OPERATION
;
2561 WsInitializeMessage( request
, WS_REQUEST_MESSAGE
, NULL
, NULL
);
2563 if (!ctx
) async_init( &async
, &ctx_local
);
2564 hr
= queue_request_reply( channel
, request
, request_desc
, write_option
, request_body
, request_size
, reply
,
2565 reply_desc
, read_option
, heap
, value
, size
, ctx
? ctx
: &ctx_local
);
2568 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2569 CloseHandle( async
.done
);
2572 LeaveCriticalSection( &channel
->cs
);
2573 TRACE( "returning %#lx\n", hr
);
2577 static HRESULT
read_message_start( struct channel
*channel
, WS_MESSAGE
*msg
)
2580 if ((hr
= receive_message_bytes( channel
, msg
)) == S_OK
&& (hr
= init_reader( channel
)) == S_OK
)
2581 hr
= WsReadEnvelopeStart( msg
, channel
->reader
, NULL
, NULL
, NULL
);
2585 struct read_message_start
2588 struct channel
*channel
;
2590 WS_ASYNC_CONTEXT ctx
;
2593 static void read_message_start_proc( struct task
*task
)
2595 struct read_message_start
*r
= (struct read_message_start
*)task
;
2598 hr
= read_message_start( r
->channel
, r
->msg
);
2600 TRACE( "calling %p(%#lx)\n", r
->ctx
.callback
, hr
);
2601 r
->ctx
.callback( hr
, WS_LONG_CALLBACK
, r
->ctx
.callbackState
);
2602 TRACE( "%p returned\n", r
->ctx
.callback
);
2605 static HRESULT
queue_read_message_start( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
)
2607 struct read_message_start
*r
;
2609 if (!(r
= malloc( sizeof(*r
) ))) return E_OUTOFMEMORY
;
2610 r
->task
.proc
= read_message_start_proc
;
2611 r
->channel
= channel
;
2614 return queue_task( &channel
->recv_q
, &r
->task
);
2617 /**************************************************************************
2618 * WsReadMessageStart [webservices.@]
2620 HRESULT WINAPI
WsReadMessageStart( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2622 struct channel
*channel
= (struct channel
*)handle
;
2623 WS_ASYNC_CONTEXT ctx_local
;
2627 TRACE( "%p %p %p %p\n", handle
, msg
, ctx
, error
);
2628 if (error
) FIXME( "ignoring error parameter\n" );
2630 if (!channel
|| !msg
) return E_INVALIDARG
;
2632 EnterCriticalSection( &channel
->cs
);
2634 if (channel
->magic
!= CHANNEL_MAGIC
)
2636 LeaveCriticalSection( &channel
->cs
);
2637 return E_INVALIDARG
;
2639 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2641 LeaveCriticalSection( &channel
->cs
);
2642 return WS_E_INVALID_OPERATION
;
2645 if (!ctx
) async_init( &async
, &ctx_local
);
2646 hr
= queue_read_message_start( channel
, msg
, ctx
? ctx
: &ctx_local
);
2649 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2650 CloseHandle( async
.done
);
2653 LeaveCriticalSection( &channel
->cs
);
2654 TRACE( "returning %#lx\n", hr
);
2658 static HRESULT
read_message_end( WS_MESSAGE
*msg
)
2660 return WsReadEnvelopeEnd( msg
, NULL
);
2663 struct read_message_end
2667 WS_ASYNC_CONTEXT ctx
;
2670 static void read_message_end_proc( struct task
*task
)
2672 struct read_message_end
*r
= (struct read_message_end
*)task
;
2675 hr
= read_message_end( r
->msg
);
2677 TRACE( "calling %p(%#lx)\n", r
->ctx
.callback
, hr
);
2678 r
->ctx
.callback( hr
, WS_LONG_CALLBACK
, r
->ctx
.callbackState
);
2679 TRACE( "%p returned\n", r
->ctx
.callback
);
2682 static HRESULT
queue_read_message_end( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
)
2684 struct read_message_end
*r
;
2686 if (!(r
= malloc( sizeof(*r
) ))) return E_OUTOFMEMORY
;
2687 r
->task
.proc
= read_message_end_proc
;
2690 return queue_task( &channel
->recv_q
, &r
->task
);
2693 /**************************************************************************
2694 * WsReadMessageEnd [webservices.@]
2696 HRESULT WINAPI
WsReadMessageEnd( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2698 struct channel
*channel
= (struct channel
*)handle
;
2699 WS_ASYNC_CONTEXT ctx_local
;
2703 TRACE( "%p %p %p %p\n", handle
, msg
, ctx
, error
);
2704 if (error
) FIXME( "ignoring error parameter\n" );
2706 if (!channel
|| !msg
) return E_INVALIDARG
;
2708 EnterCriticalSection( &channel
->cs
);
2710 if (channel
->magic
!= CHANNEL_MAGIC
)
2712 LeaveCriticalSection( &channel
->cs
);
2713 return E_INVALIDARG
;
2716 if (!ctx
) async_init( &async
, &ctx_local
);
2717 hr
= queue_read_message_end( channel
, msg
, ctx
? ctx
: &ctx_local
);
2720 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2721 CloseHandle( async
.done
);
2724 LeaveCriticalSection( &channel
->cs
);
2725 TRACE( "returning %#lx\n", hr
);
2729 static HRESULT
write_message_start( struct channel
*channel
, WS_MESSAGE
*msg
)
2732 if ((hr
= init_writer( channel
)) != S_OK
) return hr
;
2733 if ((hr
= WsAddressMessage( msg
, &channel
->addr
, NULL
)) != S_OK
) return hr
;
2734 return WsWriteEnvelopeStart( msg
, channel
->writer
, NULL
, NULL
, NULL
);
2737 struct write_message_start
2740 struct channel
*channel
;
2742 WS_ASYNC_CONTEXT ctx
;
2745 static void write_message_start_proc( struct task
*task
)
2747 struct write_message_start
*w
= (struct write_message_start
*)task
;
2750 hr
= write_message_start( w
->channel
, w
->msg
);
2752 TRACE( "calling %p(%#lx)\n", w
->ctx
.callback
, hr
);
2753 w
->ctx
.callback( hr
, WS_LONG_CALLBACK
, w
->ctx
.callbackState
);
2754 TRACE( "%p returned\n", w
->ctx
.callback
);
2757 static HRESULT
queue_write_message_start( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
)
2759 struct write_message_start
*w
;
2761 if (!(w
= malloc( sizeof(*w
) ))) return E_OUTOFMEMORY
;
2762 w
->task
.proc
= write_message_start_proc
;
2763 w
->channel
= channel
;
2766 return queue_task( &channel
->send_q
, &w
->task
);
2769 /**************************************************************************
2770 * WsWriteMessageStart [webservices.@]
2772 HRESULT WINAPI
WsWriteMessageStart( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2774 struct channel
*channel
= (struct channel
*)handle
;
2775 WS_ASYNC_CONTEXT ctx_local
;
2779 TRACE( "%p %p %p %p\n", handle
, msg
, ctx
, error
);
2780 if (error
) FIXME( "ignoring error parameter\n" );
2782 if (!channel
|| !msg
) return E_INVALIDARG
;
2784 EnterCriticalSection( &channel
->cs
);
2786 if (channel
->magic
!= CHANNEL_MAGIC
)
2788 LeaveCriticalSection( &channel
->cs
);
2789 return E_INVALIDARG
;
2791 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2793 LeaveCriticalSection( &channel
->cs
);
2794 return WS_E_INVALID_OPERATION
;
2797 if (!ctx
) async_init( &async
, &ctx_local
);
2798 hr
= queue_write_message_start( channel
, msg
, ctx
? ctx
: &ctx_local
);
2801 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2802 CloseHandle( async
.done
);
2805 LeaveCriticalSection( &channel
->cs
);
2806 TRACE( "returning %#lx\n", hr
);
2810 static HRESULT
write_message_end( struct channel
*channel
, WS_MESSAGE
*msg
)
2813 if ((hr
= WsWriteEnvelopeEnd( msg
, NULL
)) == S_OK
) hr
= send_message_bytes( channel
, msg
);
2817 struct write_message_end
2820 struct channel
*channel
;
2822 WS_ASYNC_CONTEXT ctx
;
2825 static void write_message_end_proc( struct task
*task
)
2827 struct write_message_end
*w
= (struct write_message_end
*)task
;
2830 hr
= write_message_end( w
->channel
, w
->msg
);
2832 TRACE( "calling %p(%#lx)\n", w
->ctx
.callback
, hr
);
2833 w
->ctx
.callback( hr
, WS_LONG_CALLBACK
, w
->ctx
.callbackState
);
2834 TRACE( "%p returned\n", w
->ctx
.callback
);
2837 static HRESULT
queue_write_message_end( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
)
2839 struct write_message_start
*w
;
2841 if (!(w
= malloc( sizeof(*w
) ))) return E_OUTOFMEMORY
;
2842 w
->task
.proc
= write_message_end_proc
;
2843 w
->channel
= channel
;
2846 return queue_task( &channel
->send_q
, &w
->task
);
2849 /**************************************************************************
2850 * WsWriteMessageEnd [webservices.@]
2852 HRESULT WINAPI
WsWriteMessageEnd( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2854 struct channel
*channel
= (struct channel
*)handle
;
2855 WS_ASYNC_CONTEXT ctx_local
;
2859 TRACE( "%p %p %p %p\n", handle
, msg
, ctx
, error
);
2860 if (error
) FIXME( "ignoring error parameter\n" );
2862 if (!channel
|| !msg
) return E_INVALIDARG
;
2864 EnterCriticalSection( &channel
->cs
);
2866 if (channel
->magic
!= CHANNEL_MAGIC
)
2868 LeaveCriticalSection( &channel
->cs
);
2869 return E_INVALIDARG
;
2871 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2873 LeaveCriticalSection( &channel
->cs
);
2874 return WS_E_INVALID_OPERATION
;
2877 if (!ctx
) async_init( &async
, &ctx_local
);
2878 hr
= queue_write_message_end( channel
, msg
, ctx
? ctx
: &ctx_local
);
2881 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2882 CloseHandle( async
.done
);
2885 LeaveCriticalSection( &channel
->cs
);
2886 TRACE( "returning %#lx\n", hr
);
2890 static void set_blocking( SOCKET socket
, BOOL blocking
)
2892 ULONG state
= !blocking
;
2893 ioctlsocket( socket
, FIONBIO
, &state
);
2896 static HRESULT
sock_accept( SOCKET socket
, HANDLE wait
, HANDLE cancel
, SOCKET
*ret
)
2898 HANDLE handles
[] = { wait
, cancel
};
2901 if (WSAEventSelect( socket
, handles
[0], FD_ACCEPT
)) return HRESULT_FROM_WIN32( WSAGetLastError() );
2903 switch (WSAWaitForMultipleEvents( 2, handles
, FALSE
, WSA_INFINITE
, FALSE
))
2906 if ((*ret
= accept( socket
, NULL
, NULL
)) != -1)
2908 WSAEventSelect( *ret
, NULL
, 0 );
2909 set_blocking( *ret
, TRUE
);
2912 hr
= HRESULT_FROM_WIN32( WSAGetLastError() );
2916 hr
= WS_E_OPERATION_ABORTED
;
2920 hr
= HRESULT_FROM_WIN32( WSAGetLastError() );
2927 HRESULT
channel_accept_tcp( SOCKET socket
, HANDLE wait
, HANDLE cancel
, WS_CHANNEL
*handle
)
2929 struct channel
*channel
= (struct channel
*)handle
;
2932 EnterCriticalSection( &channel
->cs
);
2934 if (channel
->magic
!= CHANNEL_MAGIC
)
2936 LeaveCriticalSection( &channel
->cs
);
2937 return E_INVALIDARG
;
2940 if ((hr
= sock_accept( socket
, wait
, cancel
, &channel
->u
.tcp
.socket
)) == S_OK
)
2942 BOOL nodelay
= FALSE
;
2943 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_NO_DELAY
, &nodelay
, sizeof(nodelay
) );
2944 setsockopt( channel
->u
.tcp
.socket
, IPPROTO_TCP
, TCP_NODELAY
, (const char *)&nodelay
, sizeof(nodelay
) );
2945 channel
->state
= WS_CHANNEL_STATE_OPEN
;
2948 LeaveCriticalSection( &channel
->cs
);
2952 static HRESULT
sock_wait( SOCKET socket
, HANDLE wait
, HANDLE cancel
)
2954 HANDLE handles
[] = { wait
, cancel
};
2957 if (WSAEventSelect( socket
, handles
[0], FD_READ
)) return HRESULT_FROM_WIN32( WSAGetLastError() );
2959 switch (WSAWaitForMultipleEvents( 2, handles
, FALSE
, WSA_INFINITE
, FALSE
))
2966 hr
= WS_E_OPERATION_ABORTED
;
2970 hr
= HRESULT_FROM_WIN32( WSAGetLastError() );
2974 WSAEventSelect( socket
, NULL
, 0 );
2975 set_blocking( socket
, TRUE
);
2979 HRESULT
channel_accept_udp( SOCKET socket
, HANDLE wait
, HANDLE cancel
, WS_CHANNEL
*handle
)
2981 struct channel
*channel
= (struct channel
*)handle
;
2984 EnterCriticalSection( &channel
->cs
);
2986 if (channel
->magic
!= CHANNEL_MAGIC
)
2988 LeaveCriticalSection( &channel
->cs
);
2989 return E_INVALIDARG
;
2992 if ((hr
= sock_wait( socket
, wait
, cancel
)) == S_OK
)
2994 channel
->u
.udp
.socket
= socket
;
2995 channel
->state
= WS_CHANNEL_STATE_OPEN
;
2998 LeaveCriticalSection( &channel
->cs
);