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/heap.h"
29 #include "wine/list.h"
30 #include "webservices_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(webservices
);
35 static const struct prop_desc channel_props
[] =
37 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE */
38 { sizeof(UINT64
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_MESSAGE_SIZE */
39 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_START_SIZE */
40 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_STREAMED_FLUSH_SIZE */
41 { sizeof(WS_ENCODING
), TRUE
}, /* WS_CHANNEL_PROPERTY_ENCODING */
42 { sizeof(WS_ENVELOPE_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENVELOPE_VERSION */
43 { sizeof(WS_ADDRESSING_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_ADDRESSING_VERSION */
44 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE */
45 { sizeof(WS_CHANNEL_STATE
), TRUE
}, /* WS_CHANNEL_PROPERTY_STATE */
46 { sizeof(WS_CALLBACK_MODEL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ASYNC_CALLBACK_MODEL */
47 { sizeof(WS_IP_VERSION
), FALSE
}, /* WS_CHANNEL_PROPERTY_IP_VERSION */
48 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RESOLVE_TIMEOUT */
49 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_CONNECT_TIMEOUT */
50 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_SEND_TIMEOUT */
51 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RECEIVE_RESPONSE_TIMEOUT */
52 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_RECEIVE_TIMEOUT */
53 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_CLOSE_TIMEOUT */
54 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENABLE_TIMEOUTS */
55 { sizeof(WS_TRANSFER_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_TRANSFER_MODE */
56 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MULTICAST_INTERFACE */
57 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MULTICAST_HOPS */
58 { sizeof(WS_ENDPOINT_ADDRESS
), TRUE
}, /* WS_CHANNEL_PROPERTY_REMOTE_ADDRESS */
59 { sizeof(SOCKADDR_STORAGE
), TRUE
}, /* WS_CHANNEL_PROPERTY_REMOTE_IP_ADDRESS */
60 { sizeof(ULONGLONG
), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_CONNECTION_ID */
61 { sizeof(WS_CUSTOM_CHANNEL_CALLBACKS
), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_CALLBACKS */
62 { 0, FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_PARAMETERS */
63 { sizeof(void *), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_INSTANCE */
64 { sizeof(WS_STRING
), TRUE
}, /* WS_CHANNEL_PROPERTY_TRANSPORT_URL */
65 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_NO_DELAY */
66 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_SEND_KEEP_ALIVES */
67 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_KEEP_ALIVE_TIME */
68 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_KEEP_ALIVE_INTERVAL */
69 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_MAX_HTTP_SERVER_CONNECTIONS */
70 { sizeof(BOOL
), TRUE
}, /* WS_CHANNEL_PROPERTY_IS_SESSION_SHUT_DOWN */
71 { sizeof(WS_CHANNEL_TYPE
), TRUE
}, /* WS_CHANNEL_PROPERTY_CHANNEL_TYPE */
72 { sizeof(ULONG
), FALSE
}, /* WS_CHANNEL_PROPERTY_TRIM_BUFFERED_MESSAGE_SIZE */
73 { sizeof(WS_CHANNEL_ENCODER
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENCODER */
74 { sizeof(WS_CHANNEL_DECODER
), FALSE
}, /* WS_CHANNEL_PROPERTY_DECODER */
75 { sizeof(WS_PROTECTION_LEVEL
), TRUE
}, /* WS_CHANNEL_PROPERTY_PROTECTION_LEVEL */
76 { sizeof(WS_COOKIE_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_COOKIE_MODE */
77 { sizeof(WS_HTTP_PROXY_SETTING_MODE
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_PROXY_SETTING_MODE */
78 { sizeof(WS_CUSTOM_HTTP_PROXY
), FALSE
}, /* WS_CHANNEL_PROPERTY_CUSTOM_HTTP_PROXY */
79 { sizeof(WS_HTTP_MESSAGE_MAPPING
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING */
80 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ENABLE_HTTP_REDIRECT */
81 { sizeof(WS_HTTP_REDIRECT_CALLBACK_CONTEXT
), FALSE
}, /* WS_CHANNEL_PROPERTY_HTTP_REDIRECT_CALLBACK_CONTEXT */
82 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_FAULTS_AS_ERRORS */
83 { sizeof(BOOL
), FALSE
}, /* WS_CHANNEL_PROPERTY_ALLOW_UNSECURED_FAULTS */
84 { sizeof(WCHAR
*), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_SERVER_SPN */
85 { sizeof(WCHAR
*), TRUE
}, /* WS_CHANNEL_PROPERTY_HTTP_PROXY_SPN */
86 { sizeof(ULONG
), FALSE
} /* WS_CHANNEL_PROPERTY_MAX_HTTP_REQUEST_HEADERS_BUFFER_SIZE */
92 void (*proc
)( struct task
* );
104 static struct task
*dequeue_task( struct queue
*queue
)
108 EnterCriticalSection( &queue
->cs
);
109 TRACE( "%u tasks queued\n", list_count( &queue
->tasks
) );
110 task
= LIST_ENTRY( list_head( &queue
->tasks
), struct task
, entry
);
111 if (task
) list_remove( &task
->entry
);
112 LeaveCriticalSection( &queue
->cs
);
114 TRACE( "returning task %p\n", task
);
118 static void CALLBACK
queue_runner( TP_CALLBACK_INSTANCE
*instance
, void *ctx
)
120 struct queue
*queue
= ctx
;
121 HANDLE handles
[] = { queue
->wait
, queue
->cancel
};
123 SetEvent( queue
->ready
);
126 DWORD err
= WaitForMultipleObjects( 2, handles
, FALSE
, INFINITE
);
132 while ((task
= dequeue_task( queue
)))
139 case WAIT_OBJECT_0
+ 1:
140 TRACE( "cancelled\n" );
141 SetEvent( queue
->ready
);
145 ERR( "wait failed %u\n", err
);
151 static HRESULT
start_queue( struct queue
*queue
)
153 HRESULT hr
= E_OUTOFMEMORY
;
155 if (queue
->wait
) return S_OK
;
156 list_init( &queue
->tasks
);
157 if (!(queue
->wait
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
))) goto error
;
158 if (!(queue
->cancel
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
))) goto error
;
159 if (!(queue
->ready
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
))) goto error
;
160 if (!TrySubmitThreadpoolCallback( queue_runner
, queue
, NULL
)) hr
= HRESULT_FROM_WIN32( GetLastError() );
163 WaitForSingleObject( queue
->ready
, INFINITE
);
168 CloseHandle( queue
->wait
);
170 CloseHandle( queue
->cancel
);
171 queue
->cancel
= NULL
;
172 CloseHandle( queue
->ready
);
177 static HRESULT
queue_task( struct queue
*queue
, struct task
*task
)
180 if ((hr
= start_queue( queue
)) != S_OK
) return hr
;
182 EnterCriticalSection( &queue
->cs
);
183 TRACE( "queueing task %p\n", task
);
184 list_add_tail( &queue
->tasks
, &task
->entry
);
185 LeaveCriticalSection( &queue
->cs
);
187 SetEvent( queue
->wait
);
193 SESSION_STATE_UNINITIALIZED
,
194 SESSION_STATE_SETUP_COMPLETE
,
195 SESSION_STATE_SHUTDOWN
,
202 WS_CHANNEL_TYPE type
;
203 WS_CHANNEL_BINDING binding
;
204 WS_CHANNEL_STATE state
;
205 WS_ENDPOINT_ADDRESS addr
;
206 WS_XML_WRITER
*writer
;
207 WS_XML_READER
*reader
;
209 WS_ENCODING encoding
;
210 enum session_state session_state
;
211 struct dictionary dict_send
;
212 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
= heap_alloc_zero( 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 heap_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 heap_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
++) heap_free( mappings
[i
] );
368 heap_free( mappings
);
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 heap_free( channel
->read_buf
);
393 heap_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
);
402 heap_free( channel
);
405 static WS_HTTP_HEADER_MAPPING
*dup_header_mapping( const WS_HTTP_HEADER_MAPPING
*src
)
407 WS_HTTP_HEADER_MAPPING
*dst
;
409 if (!(dst
= heap_alloc( 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
= heap_alloc( 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
= heap_alloc( size
)))
437 heap_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
;
489 case WS_UDP_CHANNEL_BINDING
:
490 channel
->u
.udp
.socket
= -1;
491 channel
->encoding
= WS_ENCODING_XML_UTF8
;
497 for (i
= 0; i
< count
; i
++)
499 const WS_CHANNEL_PROPERTY
*prop
= &properties
[i
];
501 TRACE( "property id %u value %p size %u\n", prop
->id
, prop
->value
, prop
->valueSize
);
502 if (prop
->valueSize
== sizeof(ULONG
) && prop
->value
) TRACE( " value %08x\n", *(ULONG
*)prop
->value
);
506 case WS_CHANNEL_PROPERTY_ENCODING
:
507 if (!prop
->value
|| prop
->valueSize
!= sizeof(channel
->encoding
))
509 free_channel( channel
);
512 channel
->encoding
= *(WS_ENCODING
*)prop
->value
;
515 case WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING
:
517 const WS_HTTP_MESSAGE_MAPPING
*src
= (WS_HTTP_MESSAGE_MAPPING
*)prop
->value
;
518 WS_HTTP_MESSAGE_MAPPING dst
;
520 if (!prop
->value
|| prop
->valueSize
!= sizeof(*src
))
522 free_channel( channel
);
526 if ((hr
= dup_message_mapping( src
, &dst
)) != S_OK
) return hr
;
528 if ((hr
= prop_set( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING
, &dst
,
529 sizeof(dst
) )) != S_OK
)
531 free_message_mapping( &dst
);
532 free_channel( channel
);
539 if ((hr
= prop_set( channel
->prop
, channel
->prop_count
, prop
->id
, prop
->value
, prop
->valueSize
)) != S_OK
)
541 free_channel( channel
);
552 /**************************************************************************
553 * WsCreateChannel [webservices.@]
555 HRESULT WINAPI
WsCreateChannel( WS_CHANNEL_TYPE type
, WS_CHANNEL_BINDING binding
,
556 const WS_CHANNEL_PROPERTY
*properties
, ULONG count
,
557 const WS_SECURITY_DESCRIPTION
*desc
, WS_CHANNEL
**handle
,
560 struct channel
*channel
;
563 TRACE( "%u %u %p %u %p %p %p\n", type
, binding
, properties
, count
, desc
, handle
, error
);
564 if (error
) FIXME( "ignoring error parameter\n" );
565 if (desc
) FIXME( "ignoring security description\n" );
567 if (!handle
) return E_INVALIDARG
;
569 if (type
!= WS_CHANNEL_TYPE_REQUEST
&& type
!= WS_CHANNEL_TYPE_DUPLEX
&&
570 type
!= WS_CHANNEL_TYPE_DUPLEX_SESSION
)
572 FIXME( "channel type %u not implemented\n", type
);
575 if (binding
!= WS_HTTP_CHANNEL_BINDING
&& binding
!= WS_TCP_CHANNEL_BINDING
&&
576 binding
!= WS_UDP_CHANNEL_BINDING
)
578 FIXME( "channel binding %u not implemented\n", binding
);
582 if ((hr
= create_channel( type
, binding
, properties
, count
, &channel
)) != S_OK
) return hr
;
584 TRACE( "created %p\n", channel
);
585 *handle
= (WS_CHANNEL
*)channel
;
589 /**************************************************************************
590 * WsCreateChannelForListener [webservices.@]
592 HRESULT WINAPI
WsCreateChannelForListener( WS_LISTENER
*listener_handle
, const WS_CHANNEL_PROPERTY
*properties
,
593 ULONG count
, WS_CHANNEL
**handle
, WS_ERROR
*error
)
595 struct channel
*channel
;
596 WS_CHANNEL_TYPE type
;
597 WS_CHANNEL_BINDING binding
;
600 TRACE( "%p %p %u %p %p\n", listener_handle
, properties
, count
, handle
, error
);
601 if (error
) FIXME( "ignoring error parameter\n" );
603 if (!listener_handle
|| !handle
) return E_INVALIDARG
;
605 if ((hr
= WsGetListenerProperty( listener_handle
, WS_LISTENER_PROPERTY_CHANNEL_TYPE
, &type
,
606 sizeof(type
), NULL
)) != S_OK
) return hr
;
608 if ((hr
= WsGetListenerProperty( listener_handle
, WS_LISTENER_PROPERTY_CHANNEL_BINDING
, &binding
,
609 sizeof(binding
), NULL
)) != S_OK
) return hr
;
611 if ((hr
= create_channel( type
, binding
, properties
, count
, &channel
)) != S_OK
) return hr
;
613 TRACE( "created %p\n", channel
);
614 *handle
= (WS_CHANNEL
*)channel
;
618 /**************************************************************************
619 * WsFreeChannel [webservices.@]
621 void WINAPI
WsFreeChannel( WS_CHANNEL
*handle
)
623 struct channel
*channel
= (struct channel
*)handle
;
625 TRACE( "%p\n", handle
);
627 if (!channel
) return;
629 EnterCriticalSection( &channel
->cs
);
631 if (channel
->magic
!= CHANNEL_MAGIC
)
633 LeaveCriticalSection( &channel
->cs
);
639 LeaveCriticalSection( &channel
->cs
);
640 free_channel( channel
);
643 /**************************************************************************
644 * WsResetChannel [webservices.@]
646 HRESULT WINAPI
WsResetChannel( WS_CHANNEL
*handle
, WS_ERROR
*error
)
648 struct channel
*channel
= (struct channel
*)handle
;
651 TRACE( "%p %p\n", handle
, error
);
652 if (error
) FIXME( "ignoring error parameter\n" );
654 if (!channel
) return E_INVALIDARG
;
656 EnterCriticalSection( &channel
->cs
);
658 if (channel
->magic
!= CHANNEL_MAGIC
)
660 LeaveCriticalSection( &channel
->cs
);
664 if (channel
->state
!= WS_CHANNEL_STATE_CREATED
&& channel
->state
!= WS_CHANNEL_STATE_CLOSED
)
665 hr
= WS_E_INVALID_OPERATION
;
668 abort_channel( channel
);
669 reset_channel( channel
);
672 LeaveCriticalSection( &channel
->cs
);
673 TRACE( "returning %08x\n", hr
);
677 /**************************************************************************
678 * WsGetChannelProperty [webservices.@]
680 HRESULT WINAPI
WsGetChannelProperty( WS_CHANNEL
*handle
, WS_CHANNEL_PROPERTY_ID id
, void *buf
,
681 ULONG size
, WS_ERROR
*error
)
683 struct channel
*channel
= (struct channel
*)handle
;
686 TRACE( "%p %u %p %u %p\n", handle
, id
, buf
, size
, error
);
687 if (error
) FIXME( "ignoring error parameter\n" );
689 if (!channel
) return E_INVALIDARG
;
691 EnterCriticalSection( &channel
->cs
);
693 if (channel
->magic
!= CHANNEL_MAGIC
)
695 LeaveCriticalSection( &channel
->cs
);
701 case WS_CHANNEL_PROPERTY_CHANNEL_TYPE
:
702 if (!buf
|| size
!= sizeof(channel
->type
)) hr
= E_INVALIDARG
;
703 else *(WS_CHANNEL_TYPE
*)buf
= channel
->type
;
706 case WS_CHANNEL_PROPERTY_ENCODING
:
707 if (!buf
|| size
!= sizeof(channel
->encoding
)) hr
= E_INVALIDARG
;
708 else *(WS_ENCODING
*)buf
= channel
->encoding
;
711 case WS_CHANNEL_PROPERTY_STATE
:
712 if (!buf
|| size
!= sizeof(channel
->state
)) hr
= E_INVALIDARG
;
713 else *(WS_CHANNEL_STATE
*)buf
= channel
->state
;
717 hr
= prop_get( channel
->prop
, channel
->prop_count
, id
, buf
, size
);
720 LeaveCriticalSection( &channel
->cs
);
721 TRACE( "returning %08x\n", hr
);
725 /**************************************************************************
726 * WsSetChannelProperty [webservices.@]
728 HRESULT WINAPI
WsSetChannelProperty( WS_CHANNEL
*handle
, WS_CHANNEL_PROPERTY_ID id
, const void *value
,
729 ULONG size
, WS_ERROR
*error
)
731 struct channel
*channel
= (struct channel
*)handle
;
734 TRACE( "%p %u %p %u\n", handle
, id
, value
, size
);
735 if (error
) FIXME( "ignoring error parameter\n" );
737 if (!channel
) return E_INVALIDARG
;
739 EnterCriticalSection( &channel
->cs
);
741 if (channel
->magic
!= CHANNEL_MAGIC
)
743 LeaveCriticalSection( &channel
->cs
);
747 hr
= prop_set( channel
->prop
, channel
->prop_count
, id
, value
, size
);
749 LeaveCriticalSection( &channel
->cs
);
750 TRACE( "returning %08x\n", hr
);
754 enum frame_record_type
756 FRAME_RECORD_TYPE_VERSION
,
757 FRAME_RECORD_TYPE_MODE
,
758 FRAME_RECORD_TYPE_VIA
,
759 FRAME_RECORD_TYPE_KNOWN_ENCODING
,
760 FRAME_RECORD_TYPE_EXTENSIBLE_ENCODING
,
761 FRAME_RECORD_TYPE_UNSIZED_ENVELOPE
,
762 FRAME_RECORD_TYPE_SIZED_ENVELOPE
,
763 FRAME_RECORD_TYPE_END
,
764 FRAME_RECORD_TYPE_FAULT
,
765 FRAME_RECORD_TYPE_UPGRADE_REQUEST
,
766 FRAME_RECORD_TYPE_UPGRADE_RESPONSE
,
767 FRAME_RECORD_TYPE_PREAMBLE_ACK
,
768 FRAME_RECORD_TYPE_PREAMBLE_END
,
771 static HRESULT
send_byte( SOCKET socket
, BYTE byte
)
773 int count
= send( socket
, (char *)&byte
, 1, 0 );
774 if (count
< 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
775 if (count
!= 1) return WS_E_OTHER
;
785 static void CALLBACK
async_callback( HRESULT hr
, WS_CALLBACK_MODEL model
, void *state
)
787 struct async
*async
= state
;
789 SetEvent( async
->done
);
792 static void async_init( struct async
*async
, WS_ASYNC_CONTEXT
*ctx
)
794 async
->done
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
796 ctx
->callback
= async_callback
;
797 ctx
->callbackState
= async
;
800 static HRESULT
async_wait( struct async
*async
)
803 if ((err
= WaitForSingleObject( async
->done
, INFINITE
)) == WAIT_OBJECT_0
) return async
->hr
;
804 return HRESULT_FROM_WIN32( err
);
807 static HRESULT
shutdown_session( struct channel
*channel
)
811 if ((channel
->type
!= WS_CHANNEL_TYPE_OUTPUT_SESSION
&&
812 channel
->type
!= WS_CHANNEL_TYPE_DUPLEX_SESSION
) ||
813 channel
->session_state
>= SESSION_STATE_SHUTDOWN
) return WS_E_INVALID_OPERATION
;
815 switch (channel
->binding
)
817 case WS_TCP_CHANNEL_BINDING
:
818 if ((hr
= send_byte( channel
->u
.tcp
.socket
, FRAME_RECORD_TYPE_END
)) != S_OK
) return hr
;
819 channel
->session_state
= SESSION_STATE_SHUTDOWN
;
823 FIXME( "unhandled binding %u\n", channel
->binding
);
828 struct shutdown_session
831 struct channel
*channel
;
832 WS_ASYNC_CONTEXT ctx
;
835 static void shutdown_session_proc( struct task
*task
)
837 struct shutdown_session
*s
= (struct shutdown_session
*)task
;
840 hr
= shutdown_session( s
->channel
);
842 TRACE( "calling %p(%08x)\n", s
->ctx
.callback
, hr
);
843 s
->ctx
.callback( hr
, WS_LONG_CALLBACK
, s
->ctx
.callbackState
);
844 TRACE( "%p returned\n", s
->ctx
.callback
);
847 static HRESULT
queue_shutdown_session( struct channel
*channel
, const WS_ASYNC_CONTEXT
*ctx
)
849 struct shutdown_session
*s
;
851 if (!(s
= heap_alloc( sizeof(*s
) ))) return E_OUTOFMEMORY
;
852 s
->task
.proc
= shutdown_session_proc
;
853 s
->channel
= channel
;
855 return queue_task( &channel
->send_q
, &s
->task
);
858 HRESULT WINAPI
WsShutdownSessionChannel( WS_CHANNEL
*handle
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
860 struct channel
*channel
= (struct channel
*)handle
;
861 WS_ASYNC_CONTEXT ctx_local
;
865 TRACE( "%p %p %p\n", handle
, ctx
, error
);
866 if (error
) FIXME( "ignoring error parameter\n" );
868 if (!channel
) return E_INVALIDARG
;
870 EnterCriticalSection( &channel
->cs
);
872 if (channel
->magic
!= CHANNEL_MAGIC
)
874 LeaveCriticalSection( &channel
->cs
);
877 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
879 LeaveCriticalSection( &channel
->cs
);
880 return WS_E_INVALID_OPERATION
;
883 if (!ctx
) async_init( &async
, &ctx_local
);
884 hr
= queue_shutdown_session( channel
, ctx
? ctx
: &ctx_local
);
887 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
888 CloseHandle( async
.done
);
891 LeaveCriticalSection( &channel
->cs
);
892 TRACE( "returning %08x\n", hr
);
896 static void close_channel( struct channel
*channel
)
898 reset_channel( channel
);
899 channel
->state
= WS_CHANNEL_STATE_CLOSED
;
905 struct channel
*channel
;
906 WS_ASYNC_CONTEXT ctx
;
909 static void close_channel_proc( struct task
*task
)
911 struct close_channel
*c
= (struct close_channel
*)task
;
913 close_channel( c
->channel
);
915 TRACE( "calling %p(S_OK)\n", c
->ctx
.callback
);
916 c
->ctx
.callback( S_OK
, WS_LONG_CALLBACK
, c
->ctx
.callbackState
);
917 TRACE( "%p returned\n", c
->ctx
.callback
);
920 static HRESULT
queue_close_channel( struct channel
*channel
, const WS_ASYNC_CONTEXT
*ctx
)
922 struct close_channel
*c
;
924 if (!(c
= heap_alloc( sizeof(*c
) ))) return E_OUTOFMEMORY
;
925 c
->task
.proc
= close_channel_proc
;
926 c
->channel
= channel
;
928 return queue_task( &channel
->send_q
, &c
->task
);
931 /**************************************************************************
932 * WsCloseChannel [webservices.@]
934 HRESULT WINAPI
WsCloseChannel( WS_CHANNEL
*handle
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
936 struct channel
*channel
= (struct channel
*)handle
;
937 WS_ASYNC_CONTEXT ctx_local
;
941 TRACE( "%p %p %p\n", handle
, ctx
, error
);
942 if (error
) FIXME( "ignoring error parameter\n" );
944 if (!channel
) return E_INVALIDARG
;
946 EnterCriticalSection( &channel
->cs
);
948 if (channel
->magic
!= CHANNEL_MAGIC
)
950 LeaveCriticalSection( &channel
->cs
);
954 if (!ctx
) async_init( &async
, &ctx_local
);
955 hr
= queue_close_channel( channel
, ctx
? ctx
: &ctx_local
);
958 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
959 CloseHandle( async
.done
);
962 LeaveCriticalSection( &channel
->cs
);
963 TRACE( "returning %08x\n", hr
);
967 static HRESULT
parse_http_url( const WCHAR
*url
, ULONG len
, URL_COMPONENTS
*uc
)
969 HRESULT hr
= E_OUTOFMEMORY
;
973 memset( uc
, 0, sizeof(*uc
) );
974 uc
->dwStructSize
= sizeof(*uc
);
975 uc
->dwHostNameLength
= 128;
976 uc
->lpszHostName
= heap_alloc( uc
->dwHostNameLength
* sizeof(WCHAR
) );
977 uc
->dwUrlPathLength
= 128;
978 uc
->lpszUrlPath
= heap_alloc( uc
->dwUrlPathLength
* sizeof(WCHAR
) );
979 uc
->dwExtraInfoLength
= 128;
980 uc
->lpszExtraInfo
= heap_alloc( uc
->dwExtraInfoLength
* sizeof(WCHAR
) );
981 if (!uc
->lpszHostName
|| !uc
->lpszUrlPath
|| !uc
->lpszExtraInfo
) goto error
;
983 if (!WinHttpCrackUrl( url
, len
, ICU_DECODE
, uc
))
985 if ((err
= GetLastError()) != ERROR_INSUFFICIENT_BUFFER
)
987 hr
= HRESULT_FROM_WIN32( err
);
990 if (!(tmp
= heap_realloc( uc
->lpszHostName
, uc
->dwHostNameLength
* sizeof(WCHAR
) ))) goto error
;
991 uc
->lpszHostName
= tmp
;
992 if (!(tmp
= heap_realloc( uc
->lpszUrlPath
, uc
->dwUrlPathLength
* sizeof(WCHAR
) ))) goto error
;
993 uc
->lpszUrlPath
= tmp
;
994 if (!(tmp
= heap_realloc( uc
->lpszExtraInfo
, uc
->dwExtraInfoLength
* sizeof(WCHAR
) ))) goto error
;
995 uc
->lpszExtraInfo
= tmp
;
996 WinHttpCrackUrl( url
, len
, ICU_DECODE
, uc
);
1002 heap_free( uc
->lpszHostName
);
1003 heap_free( uc
->lpszUrlPath
);
1004 heap_free( uc
->lpszExtraInfo
);
1008 static HRESULT
open_channel_http( struct channel
*channel
)
1010 HINTERNET ses
= NULL
, con
= NULL
;
1014 if (channel
->u
.http
.connect
) return S_OK
;
1016 if ((hr
= parse_http_url( channel
->addr
.url
.chars
, channel
->addr
.url
.length
, &uc
)) != S_OK
) return hr
;
1017 if (!(channel
->u
.http
.path
= heap_alloc( (uc
.dwUrlPathLength
+ uc
.dwExtraInfoLength
+ 1) * sizeof(WCHAR
) )))
1024 lstrcpyW( channel
->u
.http
.path
, uc
.lpszUrlPath
);
1025 if (uc
.dwExtraInfoLength
) lstrcatW( channel
->u
.http
.path
, uc
.lpszExtraInfo
);
1028 channel
->u
.http
.flags
= WINHTTP_FLAG_REFRESH
;
1031 case INTERNET_SCHEME_HTTP
: break;
1032 case INTERNET_SCHEME_HTTPS
:
1033 channel
->u
.http
.flags
|= WINHTTP_FLAG_SECURE
;
1037 hr
= WS_E_INVALID_ENDPOINT_URL
;
1041 if (!(ses
= WinHttpOpen( L
"MS-WebServices/1.0", 0, NULL
, NULL
, 0 )))
1043 hr
= HRESULT_FROM_WIN32( GetLastError() );
1046 if (!(con
= WinHttpConnect( ses
, uc
.lpszHostName
, uc
.nPort
, 0 )))
1048 hr
= HRESULT_FROM_WIN32( GetLastError() );
1052 channel
->u
.http
.session
= ses
;
1053 channel
->u
.http
.connect
= con
;
1058 WinHttpCloseHandle( con
);
1059 WinHttpCloseHandle( ses
);
1061 heap_free( uc
.lpszHostName
);
1062 heap_free( uc
.lpszUrlPath
);
1063 heap_free( uc
.lpszExtraInfo
);
1067 static HRESULT
open_channel_tcp( struct channel
*channel
)
1069 struct sockaddr_storage storage
;
1070 struct sockaddr
*addr
= (struct sockaddr
*)&storage
;
1071 BOOL nodelay
= FALSE
;
1073 WS_URL_SCHEME_TYPE scheme
;
1078 if (channel
->u
.tcp
.socket
!= -1) return S_OK
;
1080 if ((hr
= parse_url( &channel
->addr
.url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
1081 if (scheme
!= WS_URL_NETTCP_SCHEME_TYPE
)
1084 return WS_E_INVALID_ENDPOINT_URL
;
1089 hr
= resolve_hostname( host
, port
, addr
, &addr_len
, 0 );
1091 if (hr
!= S_OK
) return hr
;
1093 if ((channel
->u
.tcp
.socket
= socket( addr
->sa_family
, SOCK_STREAM
, 0 )) == -1)
1094 return HRESULT_FROM_WIN32( WSAGetLastError() );
1096 if (connect( channel
->u
.tcp
.socket
, addr
, addr_len
) < 0)
1098 closesocket( channel
->u
.tcp
.socket
);
1099 channel
->u
.tcp
.socket
= -1;
1100 return HRESULT_FROM_WIN32( WSAGetLastError() );
1103 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_NO_DELAY
, &nodelay
, sizeof(nodelay
) );
1104 setsockopt( channel
->u
.tcp
.socket
, IPPROTO_TCP
, TCP_NODELAY
, (const char *)&nodelay
, sizeof(nodelay
) );
1108 static HRESULT
open_channel_udp( struct channel
*channel
)
1110 struct sockaddr_storage storage
;
1111 struct sockaddr
*addr
= (struct sockaddr
*)&storage
;
1113 WS_URL_SCHEME_TYPE scheme
;
1118 if (channel
->u
.udp
.socket
!= -1) return S_OK
;
1120 if ((hr
= parse_url( &channel
->addr
.url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
1121 if (scheme
!= WS_URL_SOAPUDP_SCHEME_TYPE
)
1124 return WS_E_INVALID_ENDPOINT_URL
;
1129 hr
= resolve_hostname( host
, port
, addr
, &addr_len
, 0 );
1131 if (hr
!= S_OK
) return hr
;
1133 if ((channel
->u
.udp
.socket
= socket( addr
->sa_family
, SOCK_DGRAM
, 0 )) == -1)
1134 return HRESULT_FROM_WIN32( WSAGetLastError() );
1136 if (connect( channel
->u
.udp
.socket
, addr
, addr_len
) < 0)
1138 closesocket( channel
->u
.udp
.socket
);
1139 channel
->u
.udp
.socket
= -1;
1140 return HRESULT_FROM_WIN32( WSAGetLastError() );
1146 static HRESULT
open_channel( struct channel
*channel
, const WS_ENDPOINT_ADDRESS
*endpoint
)
1150 if (endpoint
->headers
|| endpoint
->extensions
|| endpoint
->identity
)
1152 FIXME( "headers, extensions or identity not supported\n" );
1156 TRACE( "endpoint %s\n", debugstr_wn(endpoint
->url
.chars
, endpoint
->url
.length
) );
1158 if (!(channel
->addr
.url
.chars
= heap_alloc( endpoint
->url
.length
* sizeof(WCHAR
) ))) return E_OUTOFMEMORY
;
1159 memcpy( channel
->addr
.url
.chars
, endpoint
->url
.chars
, endpoint
->url
.length
* sizeof(WCHAR
) );
1160 channel
->addr
.url
.length
= endpoint
->url
.length
;
1162 switch (channel
->binding
)
1164 case WS_HTTP_CHANNEL_BINDING
:
1165 hr
= open_channel_http( channel
);
1168 case WS_TCP_CHANNEL_BINDING
:
1169 hr
= open_channel_tcp( channel
);
1172 case WS_UDP_CHANNEL_BINDING
:
1173 hr
= open_channel_udp( channel
);
1177 ERR( "unhandled binding %u\n", channel
->binding
);
1181 if (hr
== S_OK
) channel
->state
= WS_CHANNEL_STATE_OPEN
;
1188 struct channel
*channel
;
1189 const WS_ENDPOINT_ADDRESS
*endpoint
;
1190 WS_ASYNC_CONTEXT ctx
;
1193 static void open_channel_proc( struct task
*task
)
1195 struct open_channel
*o
= (struct open_channel
*)task
;
1198 hr
= open_channel( o
->channel
, o
->endpoint
);
1200 TRACE( "calling %p(%08x)\n", o
->ctx
.callback
, hr
);
1201 o
->ctx
.callback( hr
, WS_LONG_CALLBACK
, o
->ctx
.callbackState
);
1202 TRACE( "%p returned\n", o
->ctx
.callback
);
1205 static HRESULT
queue_open_channel( struct channel
*channel
, const WS_ENDPOINT_ADDRESS
*endpoint
,
1206 const WS_ASYNC_CONTEXT
*ctx
)
1208 struct open_channel
*o
;
1210 if (!(o
= heap_alloc( sizeof(*o
) ))) return E_OUTOFMEMORY
;
1211 o
->task
.proc
= open_channel_proc
;
1212 o
->channel
= channel
;
1213 o
->endpoint
= endpoint
;
1215 return queue_task( &channel
->send_q
, &o
->task
);
1218 /**************************************************************************
1219 * WsOpenChannel [webservices.@]
1221 HRESULT WINAPI
WsOpenChannel( WS_CHANNEL
*handle
, const WS_ENDPOINT_ADDRESS
*endpoint
, const WS_ASYNC_CONTEXT
*ctx
,
1224 struct channel
*channel
= (struct channel
*)handle
;
1225 WS_ASYNC_CONTEXT ctx_local
;
1229 TRACE( "%p %p %p %p\n", handle
, endpoint
, ctx
, error
);
1230 if (error
) FIXME( "ignoring error parameter\n" );
1232 if (!channel
|| !endpoint
) return E_INVALIDARG
;
1234 EnterCriticalSection( &channel
->cs
);
1236 if (channel
->magic
!= CHANNEL_MAGIC
)
1238 LeaveCriticalSection( &channel
->cs
);
1239 return E_INVALIDARG
;
1241 if (channel
->state
!= WS_CHANNEL_STATE_CREATED
)
1243 LeaveCriticalSection( &channel
->cs
);
1244 return WS_E_INVALID_OPERATION
;
1247 if (!ctx
) async_init( &async
, &ctx_local
);
1248 hr
= queue_open_channel( channel
, endpoint
, ctx
? ctx
: &ctx_local
);
1251 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
1252 CloseHandle( async
.done
);
1255 LeaveCriticalSection( &channel
->cs
);
1256 TRACE( "returning %08x\n", hr
);
1260 static HRESULT
send_message_http( HINTERNET request
, BYTE
*data
, ULONG len
)
1262 if (!WinHttpSendRequest( request
, NULL
, 0, data
, len
, len
, 0 ))
1263 return HRESULT_FROM_WIN32( GetLastError() );
1265 if (!WinHttpReceiveResponse( request
, NULL
))
1266 return HRESULT_FROM_WIN32( GetLastError() );
1270 static ULONG
get_max_buffer_size( struct channel
*channel
)
1273 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE
, &size
, sizeof(size
) );
1277 static HRESULT
write_bytes( struct channel
*channel
, BYTE
*bytes
, ULONG len
)
1279 if (!channel
->send_buf
)
1281 channel
->send_buflen
= get_max_buffer_size( channel
);
1282 if (!(channel
->send_buf
= heap_alloc( channel
->send_buflen
))) return E_OUTOFMEMORY
;
1284 if (channel
->send_size
+ len
>= channel
->send_buflen
) return WS_E_QUOTA_EXCEEDED
;
1286 memcpy( channel
->send_buf
+ channel
->send_size
, bytes
, len
);
1287 channel
->send_size
+= len
;
1291 static inline HRESULT
write_byte( struct channel
*channel
, BYTE byte
)
1293 return write_bytes( channel
, &byte
, 1 );
1296 static HRESULT
write_size( struct channel
*channel
, ULONG size
)
1299 if (size
< 0x80) return write_byte( channel
, size
);
1300 if ((hr
= write_byte( channel
, (size
& 0x7f) | 0x80 )) != S_OK
) return hr
;
1301 if ((size
>>= 7) < 0x80) return write_byte( channel
, size
);
1302 if ((hr
= write_byte( channel
, (size
& 0x7f) | 0x80 )) != S_OK
) return hr
;
1303 if ((size
>>= 7) < 0x80) return write_byte( channel
, size
);
1304 if ((hr
= write_byte( channel
, (size
& 0x7f) | 0x80 )) != S_OK
) return hr
;
1305 if ((size
>>= 7) < 0x80) return write_byte( channel
, size
);
1306 if ((hr
= write_byte( channel
, (size
& 0x7f) | 0x80 )) != S_OK
) return hr
;
1307 if ((size
>>= 7) < 0x08) return write_byte( channel
, size
);
1308 return E_INVALIDARG
;
1311 static inline ULONG
size_length( ULONG size
)
1313 if (size
< 0x80) return 1;
1314 if (size
< 0x4000) return 2;
1315 if (size
< 0x200000) return 3;
1316 if (size
< 0x10000000) return 4;
1320 static ULONG
string_table_size( const struct dictionary
*dict
)
1323 for (i
= 0; i
< dict
->dict
.stringCount
; i
++)
1325 if (dict
->sequence
[i
] == dict
->current_sequence
)
1326 size
+= size_length( dict
->dict
.strings
[i
].length
) + dict
->dict
.strings
[i
].length
;
1331 static HRESULT
write_string_table( struct channel
*channel
, const struct dictionary
*dict
)
1335 for (i
= 0; i
< dict
->dict
.stringCount
; i
++)
1337 if (dict
->sequence
[i
] != dict
->current_sequence
) continue;
1338 if ((hr
= write_size( channel
, dict
->dict
.strings
[i
].length
)) != S_OK
) return hr
;
1339 if ((hr
= write_bytes( channel
, dict
->dict
.strings
[i
].bytes
, dict
->dict
.strings
[i
].length
)) != S_OK
) return hr
;
1344 static HRESULT
string_to_utf8( const WS_STRING
*str
, unsigned char **ret
, int *len
)
1346 *len
= WideCharToMultiByte( CP_UTF8
, 0, str
->chars
, str
->length
, NULL
, 0, NULL
, NULL
);
1347 if (!(*ret
= heap_alloc( *len
))) return E_OUTOFMEMORY
;
1348 WideCharToMultiByte( CP_UTF8
, 0, str
->chars
, str
->length
, (char *)*ret
, *len
, NULL
, NULL
);
1354 SESSION_MODE_INVALID
= 0,
1355 SESSION_MODE_SINGLETON
= 1,
1356 SESSION_MODE_DUPLEX
= 2,
1357 SESSION_MODE_SIMPLEX
= 3,
1360 static enum session_mode
map_channel_type( struct channel
*channel
)
1362 switch (channel
->type
)
1364 case WS_CHANNEL_TYPE_DUPLEX_SESSION
: return SESSION_MODE_DUPLEX
;
1366 FIXME( "unhandled channel type %08x\n", channel
->type
);
1367 return SESSION_MODE_INVALID
;
1373 KNOWN_ENCODING_SOAP11_UTF8
= 0x00,
1374 KNOWN_ENCODING_SOAP11_UTF16
= 0x01,
1375 KNOWN_ENCODING_SOAP11_UTF16LE
= 0x02,
1376 KNOWN_ENCODING_SOAP12_UTF8
= 0x03,
1377 KNOWN_ENCODING_SOAP12_UTF16
= 0x04,
1378 KNOWN_ENCODING_SOAP12_UTF16LE
= 0x05,
1379 KNOWN_ENCODING_SOAP12_MTOM
= 0x06,
1380 KNOWN_ENCODING_SOAP12_BINARY
= 0x07,
1381 KNOWN_ENCODING_SOAP12_BINARY_SESSION
= 0x08,
1384 static enum known_encoding
map_channel_encoding( struct channel
*channel
)
1386 WS_ENVELOPE_VERSION version
;
1388 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION
, &version
, sizeof(version
) );
1392 case WS_ENVELOPE_VERSION_SOAP_1_1
:
1393 switch (channel
->encoding
)
1395 case WS_ENCODING_XML_UTF8
: return KNOWN_ENCODING_SOAP11_UTF8
;
1396 case WS_ENCODING_XML_UTF16LE
: return KNOWN_ENCODING_SOAP11_UTF16LE
;
1398 FIXME( "unhandled version/encoding %u/%u\n", version
, channel
->encoding
);
1401 case WS_ENVELOPE_VERSION_SOAP_1_2
:
1402 switch (channel
->encoding
)
1404 case WS_ENCODING_XML_UTF8
: return KNOWN_ENCODING_SOAP12_UTF8
;
1405 case WS_ENCODING_XML_UTF16LE
: return KNOWN_ENCODING_SOAP12_UTF16LE
;
1406 case WS_ENCODING_XML_BINARY_1
: return KNOWN_ENCODING_SOAP12_BINARY
;
1407 case WS_ENCODING_XML_BINARY_SESSION_1
: return KNOWN_ENCODING_SOAP12_BINARY_SESSION
;
1409 FIXME( "unhandled version/encoding %u/%u\n", version
, channel
->encoding
);
1413 ERR( "unhandled version %u\n", version
);
1418 #define FRAME_VERSION_MAJOR 1
1419 #define FRAME_VERSION_MINOR 1
1421 static HRESULT
write_preamble( struct channel
*channel
)
1427 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_VERSION
)) != S_OK
) return hr
;
1428 if ((hr
= write_byte( channel
, FRAME_VERSION_MAJOR
)) != S_OK
) return hr
;
1429 if ((hr
= write_byte( channel
, FRAME_VERSION_MINOR
)) != S_OK
) return hr
;
1431 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_MODE
)) != S_OK
) return hr
;
1432 if ((hr
= write_byte( channel
, map_channel_type(channel
) )) != S_OK
) return hr
;
1434 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_VIA
)) != S_OK
) return hr
;
1435 if ((hr
= string_to_utf8( &channel
->addr
.url
, &url
, &len
)) != S_OK
) return hr
;
1436 if ((hr
= write_size( channel
, len
)) != S_OK
) goto done
;
1437 if ((hr
= write_bytes( channel
, url
, len
)) != S_OK
) goto done
;
1439 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_KNOWN_ENCODING
)) != S_OK
) goto done
;
1440 if ((hr
= write_byte( channel
, map_channel_encoding(channel
) )) != S_OK
) goto done
;
1441 hr
= write_byte( channel
, FRAME_RECORD_TYPE_PREAMBLE_END
);
1448 static HRESULT
send_bytes( SOCKET socket
, char *bytes
, int len
)
1450 int count
= send( socket
, bytes
, len
, 0 );
1451 if (count
< 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
1452 if (count
!= len
) return WS_E_OTHER
;
1456 static HRESULT
send_preamble( struct channel
*channel
)
1459 if ((hr
= write_preamble( channel
)) != S_OK
) return hr
;
1460 if ((hr
= send_bytes( channel
->u
.tcp
.socket
, channel
->send_buf
, channel
->send_size
)) != S_OK
) return hr
;
1461 channel
->send_size
= 0;
1465 static HRESULT
receive_bytes( struct channel
*channel
, unsigned char *bytes
, int len
)
1467 int count
= recv( channel
->u
.tcp
.socket
, (char *)bytes
, len
, 0 );
1468 if (count
< 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
1469 if (count
!= len
) return WS_E_INVALID_FORMAT
;
1473 static HRESULT
receive_preamble_ack( struct channel
*channel
)
1478 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
1479 if (byte
!= FRAME_RECORD_TYPE_PREAMBLE_ACK
) return WS_E_INVALID_FORMAT
;
1480 channel
->session_state
= SESSION_STATE_SETUP_COMPLETE
;
1484 static HRESULT
write_sized_envelope( struct channel
*channel
, BYTE
*data
, ULONG len
)
1486 ULONG table_size
= string_table_size( &channel
->dict_send
);
1489 if ((hr
= write_byte( channel
, FRAME_RECORD_TYPE_SIZED_ENVELOPE
)) != S_OK
) return hr
;
1490 if ((hr
= write_size( channel
, size_length(table_size
) + table_size
+ len
)) != S_OK
) return hr
;
1491 if ((hr
= write_size( channel
, table_size
)) != S_OK
) return hr
;
1492 if ((hr
= write_string_table( channel
, &channel
->dict_send
)) != S_OK
) return hr
;
1493 return write_bytes( channel
, data
, len
);
1496 static HRESULT
send_sized_envelope( struct channel
*channel
, BYTE
*data
, ULONG len
)
1499 if ((hr
= write_sized_envelope( channel
, data
, len
)) != S_OK
) return hr
;
1500 if ((hr
= send_bytes( channel
->u
.tcp
.socket
, channel
->send_buf
, channel
->send_size
)) != S_OK
) return hr
;
1501 channel
->send_size
= 0;
1505 static HRESULT
open_http_request( struct channel
*channel
, HINTERNET
*req
)
1507 if ((*req
= WinHttpOpenRequest( channel
->u
.http
.connect
, L
"POST", channel
->u
.http
.path
,
1508 NULL
, NULL
, NULL
, channel
->u
.http
.flags
))) return S_OK
;
1509 return HRESULT_FROM_WIN32( GetLastError() );
1512 static HRESULT
send_message_bytes( struct channel
*channel
, WS_MESSAGE
*msg
)
1514 WS_XML_WRITER
*writer
;
1519 WsGetMessageProperty( channel
->msg
, WS_MESSAGE_PROPERTY_BODY_WRITER
, &writer
, sizeof(writer
), NULL
);
1520 WsGetWriterProperty( writer
, WS_XML_WRITER_PROPERTY_BYTES
, &buf
, sizeof(buf
), NULL
);
1522 switch (channel
->binding
)
1524 case WS_HTTP_CHANNEL_BINDING
:
1525 if (channel
->u
.http
.request
)
1527 WinHttpCloseHandle( channel
->u
.http
.request
);
1528 channel
->u
.http
.request
= NULL
;
1530 if ((hr
= open_http_request( channel
, &channel
->u
.http
.request
)) != S_OK
) return hr
;
1531 if ((hr
= message_insert_http_headers( msg
, channel
->u
.http
.request
)) != S_OK
) return hr
;
1532 return send_message_http( channel
->u
.http
.request
, buf
.bytes
, buf
.length
);
1534 case WS_TCP_CHANNEL_BINDING
:
1535 if (channel
->type
& WS_CHANNEL_TYPE_SESSION
)
1537 switch (channel
->session_state
)
1539 case SESSION_STATE_UNINITIALIZED
:
1540 if ((hr
= send_preamble( channel
)) != S_OK
) return hr
;
1541 if ((hr
= receive_preamble_ack( channel
)) != S_OK
) return hr
;
1544 case SESSION_STATE_SETUP_COMPLETE
:
1545 return send_sized_envelope( channel
, buf
.bytes
, buf
.length
);
1548 ERR( "unhandled session state %u\n", channel
->session_state
);
1554 case WS_UDP_CHANNEL_BINDING
:
1555 return WsFlushWriter( writer
, 0, NULL
, NULL
);
1558 ERR( "unhandled binding %u\n", channel
->binding
);
1563 HRESULT
channel_send_message( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
)
1565 struct channel
*channel
= (struct channel
*)handle
;
1568 EnterCriticalSection( &channel
->cs
);
1570 if (channel
->magic
!= CHANNEL_MAGIC
)
1572 LeaveCriticalSection( &channel
->cs
);
1573 return E_INVALIDARG
;
1575 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
1577 LeaveCriticalSection( &channel
->cs
);
1578 return WS_E_INVALID_OPERATION
;
1581 hr
= send_message_bytes( channel
, msg
);
1583 LeaveCriticalSection( &channel
->cs
);
1587 static HRESULT CALLBACK
dict_cb( void *state
, const WS_XML_STRING
*str
, BOOL
*found
, ULONG
*id
, WS_ERROR
*error
)
1589 struct dictionary
*dict
= state
;
1594 if ((index
= find_string( dict
, str
->bytes
, str
->length
, id
)) == -1)
1600 if (!(bytes
= heap_alloc( str
->length
))) return E_OUTOFMEMORY
;
1601 memcpy( bytes
, str
->bytes
, str
->length
);
1602 if ((hr
= insert_string( dict
, bytes
, str
->length
, index
, id
)) == S_OK
)
1613 static CALLBACK HRESULT
write_callback( void *state
, const WS_BYTES
*buf
, ULONG count
, const WS_ASYNC_CONTEXT
*ctx
,
1616 SOCKET socket
= *(SOCKET
*)state
;
1617 if (send( socket
, (const char *)buf
->bytes
, buf
->length
, 0 ) < 0)
1619 TRACE( "send failed %u\n", WSAGetLastError() );
1624 static HRESULT
init_writer( struct channel
*channel
)
1626 WS_XML_WRITER_BUFFER_OUTPUT buf
= {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER
}};
1627 WS_XML_WRITER_STREAM_OUTPUT stream
= {{WS_XML_WRITER_OUTPUT_TYPE_STREAM
}};
1628 WS_XML_WRITER_TEXT_ENCODING text
= {{WS_XML_WRITER_ENCODING_TYPE_TEXT
}, WS_CHARSET_UTF8
};
1629 WS_XML_WRITER_BINARY_ENCODING bin
= {{WS_XML_WRITER_ENCODING_TYPE_BINARY
}};
1630 const WS_XML_WRITER_ENCODING
*encoding
;
1631 const WS_XML_WRITER_OUTPUT
*output
;
1632 WS_XML_WRITER_PROPERTY prop
;
1633 ULONG max_size
= (1 << 17);
1636 prop
.id
= WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE
;
1637 prop
.value
= &max_size
;
1638 prop
.valueSize
= sizeof(max_size
);
1639 if (!channel
->writer
&& (hr
= WsCreateWriter( &prop
, 1, &channel
->writer
, NULL
)) != S_OK
) return hr
;
1641 switch (channel
->encoding
)
1643 case WS_ENCODING_XML_UTF8
:
1644 encoding
= &text
.encoding
;
1645 if (channel
->binding
== WS_UDP_CHANNEL_BINDING
||
1646 (channel
->binding
== WS_TCP_CHANNEL_BINDING
&& !(channel
->type
& WS_CHANNEL_TYPE_SESSION
)))
1648 stream
.writeCallback
= write_callback
;
1649 stream
.writeCallbackState
= (channel
->binding
== WS_UDP_CHANNEL_BINDING
) ?
1650 &channel
->u
.udp
.socket
: &channel
->u
.tcp
.socket
;
1651 output
= &stream
.output
;
1653 else output
= &buf
.output
;
1656 case WS_ENCODING_XML_BINARY_SESSION_1
:
1657 bin
.staticDictionary
= (WS_XML_DICTIONARY
*)&dict_builtin_static
.dict
;
1660 case WS_ENCODING_XML_BINARY_1
:
1661 encoding
= &bin
.encoding
;
1662 output
= &buf
.output
;
1666 FIXME( "unhandled encoding %u\n", channel
->encoding
);
1667 return WS_E_NOT_SUPPORTED
;
1670 return WsSetOutput( channel
->writer
, encoding
, output
, NULL
, 0, NULL
);
1673 static HRESULT
write_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ELEMENT_DESCRIPTION
*desc
,
1674 WS_WRITE_OPTION option
, const void *body
, ULONG size
)
1677 if ((hr
= writer_set_lookup( channel
->writer
, TRUE
)) != S_OK
) return hr
;
1678 if ((hr
= WsWriteEnvelopeStart( msg
, channel
->writer
, NULL
, NULL
, NULL
)) != S_OK
) return hr
;
1679 if ((hr
= writer_set_lookup( channel
->writer
, FALSE
)) != S_OK
) return hr
;
1680 channel
->dict_send
.current_sequence
++;
1681 if ((hr
= writer_set_dict_callback( channel
->writer
, dict_cb
, &channel
->dict_send
)) != S_OK
) return hr
;
1682 if ((hr
= WsWriteBody( msg
, desc
, option
, body
, size
, NULL
)) != S_OK
) return hr
;
1683 return WsWriteEnvelopeEnd( msg
, NULL
);
1686 static HRESULT
send_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
1687 WS_WRITE_OPTION option
, const void *body
, ULONG size
)
1690 if ((hr
= WsAddressMessage( msg
, &channel
->addr
, NULL
)) != S_OK
) return hr
;
1691 if ((hr
= message_set_action( msg
, desc
->action
)) != S_OK
) return hr
;
1692 if ((hr
= init_writer( channel
)) != S_OK
) return hr
;
1693 if ((hr
= write_message( channel
, msg
, desc
->bodyElementDescription
, option
, body
, size
)) != S_OK
) return hr
;
1694 return send_message_bytes( channel
, msg
);
1700 struct channel
*channel
;
1702 const WS_MESSAGE_DESCRIPTION
*desc
;
1703 WS_WRITE_OPTION option
;
1706 WS_ASYNC_CONTEXT ctx
;
1709 static void send_message_proc( struct task
*task
)
1711 struct send_message
*s
= (struct send_message
*)task
;
1714 hr
= send_message( s
->channel
, s
->msg
, s
->desc
, s
->option
, s
->body
, s
->size
);
1716 TRACE( "calling %p(%08x)\n", s
->ctx
.callback
, hr
);
1717 s
->ctx
.callback( hr
, WS_LONG_CALLBACK
, s
->ctx
.callbackState
);
1718 TRACE( "%p returned\n", s
->ctx
.callback
);
1721 static HRESULT
queue_send_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
1722 WS_WRITE_OPTION option
, const void *body
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
)
1724 struct send_message
*s
;
1726 if (!(s
= heap_alloc( sizeof(*s
) ))) return E_OUTOFMEMORY
;
1727 s
->task
.proc
= send_message_proc
;
1728 s
->channel
= channel
;
1735 return queue_task( &channel
->send_q
, &s
->task
);
1738 /**************************************************************************
1739 * WsSendMessage [webservices.@]
1741 HRESULT WINAPI
WsSendMessage( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
1742 WS_WRITE_OPTION option
, const void *body
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
,
1745 struct channel
*channel
= (struct channel
*)handle
;
1746 WS_ASYNC_CONTEXT ctx_local
;
1750 TRACE( "%p %p %p %08x %p %u %p %p\n", handle
, msg
, desc
, option
, body
, size
, ctx
, error
);
1751 if (error
) FIXME( "ignoring error parameter\n" );
1753 if (!channel
|| !msg
|| !desc
) return E_INVALIDARG
;
1755 EnterCriticalSection( &channel
->cs
);
1757 if (channel
->magic
!= CHANNEL_MAGIC
)
1759 LeaveCriticalSection( &channel
->cs
);
1760 return E_INVALIDARG
;
1762 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
1764 LeaveCriticalSection( &channel
->cs
);
1765 return WS_E_INVALID_OPERATION
;
1768 WsInitializeMessage( msg
, WS_BLANK_MESSAGE
, NULL
, NULL
);
1770 if (!ctx
) async_init( &async
, &ctx_local
);
1771 hr
= queue_send_message( channel
, msg
, desc
, option
, body
, size
, ctx
? ctx
: &ctx_local
);
1774 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
1775 CloseHandle( async
.done
);
1778 LeaveCriticalSection( &channel
->cs
);
1779 TRACE( "returning %08x\n", hr
);
1783 /**************************************************************************
1784 * WsSendReplyMessage [webservices.@]
1786 HRESULT WINAPI
WsSendReplyMessage( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
*desc
,
1787 WS_WRITE_OPTION option
, const void *body
, ULONG size
, WS_MESSAGE
*request
,
1788 const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
1790 struct channel
*channel
= (struct channel
*)handle
;
1791 WS_ASYNC_CONTEXT ctx_local
;
1796 TRACE( "%p %p %p %08x %p %u %p %p %p\n", handle
, msg
, desc
, option
, body
, size
, request
, ctx
, error
);
1797 if (error
) FIXME( "ignoring error parameter\n" );
1799 if (!channel
|| !msg
|| !desc
|| !request
) return E_INVALIDARG
;
1801 EnterCriticalSection( &channel
->cs
);
1803 if (channel
->magic
!= CHANNEL_MAGIC
)
1805 LeaveCriticalSection( &channel
->cs
);
1806 return E_INVALIDARG
;
1808 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
1810 LeaveCriticalSection( &channel
->cs
);
1811 return WS_E_INVALID_OPERATION
;
1814 WsInitializeMessage( msg
, WS_REPLY_MESSAGE
, NULL
, NULL
);
1815 if ((hr
= message_get_id( request
, &id
)) != S_OK
) goto done
;
1816 if ((hr
= message_set_request_id( msg
, &id
)) != S_OK
) goto done
;
1818 if (!ctx
) async_init( &async
, &ctx_local
);
1819 hr
= queue_send_message( channel
, msg
, desc
, option
, body
, size
, ctx
? ctx
: &ctx_local
);
1822 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
1823 CloseHandle( async
.done
);
1827 LeaveCriticalSection( &channel
->cs
);
1828 TRACE( "returning %08x\n", hr
);
1832 static HRESULT
resize_read_buffer( struct channel
*channel
, ULONG size
)
1834 if (!channel
->read_buf
)
1836 if (!(channel
->read_buf
= heap_alloc( size
))) return E_OUTOFMEMORY
;
1837 channel
->read_buflen
= size
;
1840 if (channel
->read_buflen
< size
)
1843 ULONG new_size
= max( size
, channel
->read_buflen
* 2 );
1844 if (!(tmp
= heap_realloc( channel
->read_buf
, new_size
))) return E_OUTOFMEMORY
;
1845 channel
->read_buf
= tmp
;
1846 channel
->read_buflen
= new_size
;
1851 static CALLBACK HRESULT
read_callback( void *state
, void *buf
, ULONG buflen
, ULONG
*retlen
,
1852 const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
1854 SOCKET socket
= *(SOCKET
*)state
;
1857 if ((ret
= recv( socket
, buf
, buflen
, 0 )) >= 0) *retlen
= ret
;
1860 TRACE( "recv failed %u\n", WSAGetLastError() );
1866 static HRESULT
init_reader( struct channel
*channel
)
1868 WS_XML_READER_BUFFER_INPUT buf
= {{WS_XML_READER_INPUT_TYPE_BUFFER
}};
1869 WS_XML_READER_STREAM_INPUT stream
= {{WS_XML_READER_INPUT_TYPE_STREAM
}};
1870 WS_XML_READER_TEXT_ENCODING text
= {{WS_XML_READER_ENCODING_TYPE_TEXT
}};
1871 WS_XML_READER_BINARY_ENCODING bin
= {{WS_XML_READER_ENCODING_TYPE_BINARY
}};
1872 const WS_XML_READER_ENCODING
*encoding
;
1873 const WS_XML_READER_INPUT
*input
;
1876 if (!channel
->reader
&& (hr
= WsCreateReader( NULL
, 0, &channel
->reader
, NULL
)) != S_OK
) return hr
;
1878 switch (channel
->encoding
)
1880 case WS_ENCODING_XML_UTF8
:
1881 text
.charSet
= WS_CHARSET_UTF8
;
1882 encoding
= &text
.encoding
;
1884 if (channel
->binding
== WS_UDP_CHANNEL_BINDING
||
1885 (channel
->binding
== WS_TCP_CHANNEL_BINDING
&& !(channel
->type
& WS_CHANNEL_TYPE_SESSION
)))
1887 stream
.readCallback
= read_callback
;
1888 stream
.readCallbackState
= (channel
->binding
== WS_UDP_CHANNEL_BINDING
) ?
1889 &channel
->u
.udp
.socket
: &channel
->u
.tcp
.socket
;
1890 input
= &stream
.input
;
1894 buf
.encodedData
= channel
->read_buf
;
1895 buf
.encodedDataSize
= channel
->read_size
;
1900 case WS_ENCODING_XML_BINARY_SESSION_1
:
1901 bin
.staticDictionary
= (WS_XML_DICTIONARY
*)&dict_builtin_static
.dict
;
1902 bin
.dynamicDictionary
= &channel
->dict_recv
.dict
;
1905 case WS_ENCODING_XML_BINARY_1
:
1906 encoding
= &bin
.encoding
;
1908 buf
.encodedData
= channel
->read_buf
;
1909 buf
.encodedDataSize
= channel
->read_size
;
1914 FIXME( "unhandled encoding %u\n", channel
->encoding
);
1915 return WS_E_NOT_SUPPORTED
;
1918 return WsSetInput( channel
->reader
, encoding
, input
, NULL
, 0, NULL
);
1921 static const WS_HTTP_MESSAGE_MAPPING
*get_http_message_mapping( struct channel
*channel
)
1923 const struct prop
*prop
= &channel
->prop
[WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING
];
1924 return (const WS_HTTP_MESSAGE_MAPPING
*)prop
->value
;
1927 static HRESULT
map_http_response_headers( struct channel
*channel
, WS_MESSAGE
*msg
)
1929 const WS_HTTP_MESSAGE_MAPPING
*mapping
= get_http_message_mapping( channel
);
1930 return message_map_http_response_headers( msg
, channel
->u
.http
.request
, mapping
);
1933 #define INITIAL_READ_BUFFER_SIZE 4096
1934 static HRESULT
receive_message_bytes_http( struct channel
*channel
, WS_MESSAGE
*msg
)
1936 DWORD len
, bytes_read
, offset
= 0, size
= INITIAL_READ_BUFFER_SIZE
;
1937 ULONG max_len
= get_max_buffer_size( channel
);
1940 if ((hr
= map_http_response_headers( channel
, msg
)) != S_OK
) return hr
;
1942 if ((hr
= resize_read_buffer( channel
, size
)) != S_OK
) return hr
;
1943 channel
->read_size
= 0;
1946 if (!WinHttpQueryDataAvailable( channel
->u
.http
.request
, &len
))
1948 return HRESULT_FROM_WIN32( GetLastError() );
1951 if (channel
->read_size
+ len
> max_len
) return WS_E_QUOTA_EXCEEDED
;
1952 if ((hr
= resize_read_buffer( channel
, channel
->read_size
+ len
)) != S_OK
) return hr
;
1954 if (!WinHttpReadData( channel
->u
.http
.request
, channel
->read_buf
+ offset
, len
, &bytes_read
))
1956 return HRESULT_FROM_WIN32( GetLastError() );
1958 if (!bytes_read
) break;
1959 channel
->read_size
+= bytes_read
;
1960 offset
+= bytes_read
;
1966 static HRESULT
receive_message_sized( struct channel
*channel
, unsigned int size
)
1968 unsigned int offset
= 0, to_read
= size
;
1972 if ((hr
= resize_read_buffer( channel
, size
)) != S_OK
) return hr
;
1974 channel
->read_size
= 0;
1975 while (channel
->read_size
< size
)
1977 if ((bytes_read
= recv( channel
->u
.tcp
.socket
, channel
->read_buf
+ offset
, to_read
, 0 )) < 0)
1979 return HRESULT_FROM_WIN32( WSAGetLastError() );
1981 if (!bytes_read
) break;
1982 channel
->read_size
+= bytes_read
;
1983 to_read
-= bytes_read
;
1984 offset
+= bytes_read
;
1986 if (channel
->read_size
!= size
) return WS_E_INVALID_FORMAT
;
1990 static HRESULT
receive_size( struct channel
*channel
, unsigned int *size
)
1995 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
1996 *size
= byte
& 0x7f;
1997 if (!(byte
& 0x80)) return S_OK
;
1999 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2000 *size
+= (byte
& 0x7f) << 7;
2001 if (!(byte
& 0x80)) return S_OK
;
2003 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2004 *size
+= (byte
& 0x7f) << 14;
2005 if (!(byte
& 0x80)) return S_OK
;
2007 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2008 *size
+= (byte
& 0x7f) << 21;
2009 if (!(byte
& 0x80)) return S_OK
;
2011 if ((hr
= receive_bytes( channel
, &byte
, 1 )) != S_OK
) return hr
;
2012 if (byte
& ~0x0f) return WS_E_INVALID_FORMAT
;
2013 *size
+= byte
<< 28;
2017 static WS_ENCODING
map_known_encoding( enum known_encoding encoding
)
2021 case KNOWN_ENCODING_SOAP11_UTF8
:
2022 case KNOWN_ENCODING_SOAP12_UTF8
: return WS_ENCODING_XML_UTF8
;
2023 case KNOWN_ENCODING_SOAP11_UTF16
:
2024 case KNOWN_ENCODING_SOAP12_UTF16
: return WS_ENCODING_XML_UTF16BE
;
2025 case KNOWN_ENCODING_SOAP11_UTF16LE
:
2026 case KNOWN_ENCODING_SOAP12_UTF16LE
: return WS_ENCODING_XML_UTF16LE
;
2027 case KNOWN_ENCODING_SOAP12_BINARY
: return WS_ENCODING_XML_BINARY_1
;
2028 case KNOWN_ENCODING_SOAP12_BINARY_SESSION
: return WS_ENCODING_XML_BINARY_SESSION_1
;
2030 WARN( "unhandled encoding %u, assuming UTF8\n", encoding
);
2031 return WS_ENCODING_XML_UTF8
;
2035 static HRESULT
receive_preamble( struct channel
*channel
)
2042 if ((hr
= receive_bytes( channel
, &type
, 1 )) != S_OK
) return hr
;
2043 if (type
== FRAME_RECORD_TYPE_PREAMBLE_END
) break;
2046 case FRAME_RECORD_TYPE_VERSION
:
2048 unsigned char major
, minor
;
2049 if ((hr
= receive_bytes( channel
, &major
, 1 )) != S_OK
) return hr
;
2050 if ((hr
= receive_bytes( channel
, &minor
, 1 )) != S_OK
) return hr
;
2051 TRACE( "major %u minor %u\n", major
, major
);
2054 case FRAME_RECORD_TYPE_MODE
:
2057 if ((hr
= receive_bytes( channel
, &mode
, 1 )) != S_OK
) return hr
;
2058 TRACE( "mode %u\n", mode
);
2061 case FRAME_RECORD_TYPE_VIA
:
2066 if ((hr
= receive_size( channel
, &size
)) != S_OK
) return hr
;
2067 if (!(url
= heap_alloc( size
))) return E_OUTOFMEMORY
;
2068 if ((hr
= receive_bytes( channel
, url
, size
)) != S_OK
)
2073 TRACE( "transport URL %s\n", debugstr_an((char *)url
, size
) );
2074 heap_free( url
); /* FIXME: verify */
2077 case FRAME_RECORD_TYPE_KNOWN_ENCODING
:
2079 unsigned char encoding
;
2080 if ((hr
= receive_bytes( channel
, &encoding
, 1 )) != S_OK
) return hr
;
2081 TRACE( "encoding %u\n", encoding
);
2082 channel
->encoding
= map_known_encoding( encoding
);
2086 WARN( "unhandled record type %u\n", type
);
2087 return WS_E_INVALID_FORMAT
;
2094 static HRESULT
receive_sized_envelope( struct channel
*channel
)
2100 if ((hr
= receive_bytes( channel
, &type
, 1 )) != S_OK
) return hr
;
2101 if (type
== FRAME_RECORD_TYPE_END
) return WS_S_END
;
2102 if (type
!= FRAME_RECORD_TYPE_SIZED_ENVELOPE
) return WS_E_INVALID_FORMAT
;
2103 if ((hr
= receive_size( channel
, &size
)) != S_OK
) return hr
;
2104 if ((hr
= receive_message_sized( channel
, size
)) != S_OK
) return hr
;
2108 static HRESULT
read_size( const BYTE
**ptr
, ULONG len
, ULONG
*size
)
2110 const BYTE
*buf
= *ptr
;
2112 if (len
< 1) return WS_E_INVALID_FORMAT
;
2113 *size
= buf
[0] & 0x7f;
2114 if (!(buf
[0] & 0x80))
2119 if (len
< 2) return WS_E_INVALID_FORMAT
;
2120 *size
+= (buf
[1] & 0x7f) << 7;
2121 if (!(buf
[1] & 0x80))
2126 if (len
< 3) return WS_E_INVALID_FORMAT
;
2127 *size
+= (buf
[2] & 0x7f) << 14;
2128 if (!(buf
[2] & 0x80))
2133 if (len
< 4) return WS_E_INVALID_FORMAT
;
2134 *size
+= (buf
[3] & 0x7f) << 21;
2135 if (!(buf
[3] & 0x80))
2140 if (len
< 5 || (buf
[4] & ~0x07)) return WS_E_INVALID_FORMAT
;
2141 *size
+= buf
[4] << 28;
2146 static HRESULT
build_dict( const BYTE
*buf
, ULONG buflen
, struct dictionary
*dict
, ULONG
*used
)
2148 ULONG size
, strings_size
, strings_offset
;
2149 const BYTE
*ptr
= buf
;
2154 if ((hr
= read_size( &ptr
, buflen
, &strings_size
)) != S_OK
) return hr
;
2155 strings_offset
= ptr
- buf
;
2156 if (buflen
< strings_offset
+ strings_size
) return WS_E_INVALID_FORMAT
;
2157 *used
= strings_offset
+ strings_size
;
2158 if (!strings_size
) return S_OK
;
2160 UuidCreate( &dict
->dict
.guid
);
2161 dict
->dict
.isConst
= FALSE
;
2163 buflen
-= strings_offset
;
2164 ptr
= buf
+ strings_offset
;
2165 while (ptr
< buf
+ strings_size
)
2167 if ((hr
= read_size( &ptr
, buflen
, &size
)) != S_OK
)
2175 return WS_E_INVALID_FORMAT
;
2178 if (!(bytes
= heap_alloc( size
)))
2183 memcpy( bytes
, ptr
, size
);
2184 if ((index
= find_string( dict
, bytes
, size
, NULL
)) == -1) /* duplicate */
2190 if ((hr
= insert_string( dict
, bytes
, size
, index
, NULL
)) != S_OK
)
2205 static HRESULT
send_preamble_ack( struct channel
*channel
)
2208 if ((hr
= send_byte( channel
->u
.tcp
.socket
, FRAME_RECORD_TYPE_PREAMBLE_ACK
)) != S_OK
) return hr
;
2209 channel
->session_state
= SESSION_STATE_SETUP_COMPLETE
;
2213 static HRESULT
receive_message_bytes_session( struct channel
*channel
)
2217 if ((hr
= receive_sized_envelope( channel
)) != S_OK
) return hr
;
2218 if (channel
->encoding
== WS_ENCODING_XML_BINARY_SESSION_1
)
2221 if ((hr
= build_dict( (const BYTE
*)channel
->read_buf
, channel
->read_size
, &channel
->dict_recv
,
2222 &size
)) != S_OK
) return hr
;
2223 channel
->read_size
-= size
;
2224 memmove( channel
->read_buf
, channel
->read_buf
+ size
, channel
->read_size
);
2230 static HRESULT
receive_message_bytes( struct channel
*channel
, WS_MESSAGE
*msg
)
2232 switch (channel
->binding
)
2234 case WS_HTTP_CHANNEL_BINDING
:
2235 return receive_message_bytes_http( channel
, msg
);
2237 case WS_TCP_CHANNEL_BINDING
:
2238 if (channel
->type
& WS_CHANNEL_TYPE_SESSION
)
2241 switch (channel
->session_state
)
2243 case SESSION_STATE_UNINITIALIZED
:
2244 if ((hr
= receive_preamble( channel
)) != S_OK
) return hr
;
2245 if ((hr
= send_preamble_ack( channel
)) != S_OK
) return hr
;
2248 case SESSION_STATE_SETUP_COMPLETE
:
2249 return receive_message_bytes_session( channel
);
2252 ERR( "unhandled session state %u\n", channel
->session_state
);
2256 return S_OK
; /* nothing to do, data is read through stream callback */
2258 case WS_UDP_CHANNEL_BINDING
:
2262 ERR( "unhandled binding %u\n", channel
->binding
);
2267 HRESULT
channel_receive_message( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
)
2269 struct channel
*channel
= (struct channel
*)handle
;
2272 EnterCriticalSection( &channel
->cs
);
2274 if (channel
->magic
!= CHANNEL_MAGIC
)
2276 LeaveCriticalSection( &channel
->cs
);
2277 return E_INVALIDARG
;
2279 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2281 LeaveCriticalSection( &channel
->cs
);
2282 return WS_E_INVALID_OPERATION
;
2285 if ((hr
= receive_message_bytes( channel
, msg
)) == S_OK
) hr
= init_reader( channel
);
2287 LeaveCriticalSection( &channel
->cs
);
2291 HRESULT
channel_get_reader( WS_CHANNEL
*handle
, WS_XML_READER
**reader
)
2293 struct channel
*channel
= (struct channel
*)handle
;
2295 EnterCriticalSection( &channel
->cs
);
2297 if (channel
->magic
!= CHANNEL_MAGIC
)
2299 LeaveCriticalSection( &channel
->cs
);
2300 return E_INVALIDARG
;
2303 *reader
= channel
->reader
;
2305 LeaveCriticalSection( &channel
->cs
);
2309 static HRESULT
read_message( WS_MESSAGE
*handle
, WS_XML_READER
*reader
, const WS_ELEMENT_DESCRIPTION
*desc
,
2310 WS_READ_OPTION option
, WS_HEAP
*heap
, void *body
, ULONG size
)
2313 if ((hr
= WsReadEnvelopeStart( handle
, reader
, NULL
, NULL
, NULL
)) != S_OK
) return hr
;
2314 if ((hr
= WsReadBody( handle
, desc
, option
, heap
, body
, size
, NULL
)) != S_OK
) return hr
;
2315 return WsReadEnvelopeEnd( handle
, NULL
);
2318 static HRESULT
receive_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
**desc
,
2319 ULONG count
, WS_RECEIVE_OPTION option
, WS_READ_OPTION read_option
, WS_HEAP
*heap
,
2320 void *value
, ULONG size
, ULONG
*index
)
2325 if ((hr
= receive_message_bytes( channel
, msg
)) != S_OK
) return hr
;
2326 if ((hr
= init_reader( channel
)) != S_OK
) return hr
;
2328 for (i
= 0; i
< count
; i
++)
2330 const WS_ELEMENT_DESCRIPTION
*body
= desc
[i
]->bodyElementDescription
;
2331 if ((hr
= read_message( msg
, channel
->reader
, body
, read_option
, heap
, value
, size
)) == S_OK
)
2333 if (index
) *index
= i
;
2336 if ((hr
= WsResetMessage( msg
, NULL
)) != S_OK
) return hr
;
2337 if ((hr
= init_reader( channel
)) != S_OK
) return hr
;
2339 return (i
== count
) ? WS_E_INVALID_FORMAT
: S_OK
;
2342 struct receive_message
2345 struct channel
*channel
;
2347 const WS_MESSAGE_DESCRIPTION
**desc
;
2349 WS_RECEIVE_OPTION option
;
2350 WS_READ_OPTION read_option
;
2355 WS_ASYNC_CONTEXT ctx
;
2358 static void receive_message_proc( struct task
*task
)
2360 struct receive_message
*r
= (struct receive_message
*)task
;
2363 hr
= receive_message( r
->channel
, r
->msg
, r
->desc
, r
->count
, r
->option
, r
->read_option
, r
->heap
, r
->value
,
2364 r
->size
, r
->index
);
2366 TRACE( "calling %p(%08x)\n", r
->ctx
.callback
, hr
);
2367 r
->ctx
.callback( hr
, WS_LONG_CALLBACK
, r
->ctx
.callbackState
);
2368 TRACE( "%p returned\n", r
->ctx
.callback
);
2371 static HRESULT
queue_receive_message( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
**desc
,
2372 ULONG count
, WS_RECEIVE_OPTION option
, WS_READ_OPTION read_option
,
2373 WS_HEAP
*heap
, void *value
, ULONG size
, ULONG
*index
,
2374 const WS_ASYNC_CONTEXT
*ctx
)
2376 struct receive_message
*r
;
2378 if (!(r
= heap_alloc( sizeof(*r
) ))) return E_OUTOFMEMORY
;
2379 r
->task
.proc
= receive_message_proc
;
2380 r
->channel
= channel
;
2385 r
->read_option
= read_option
;
2391 return queue_task( &channel
->recv_q
, &r
->task
);
2394 /**************************************************************************
2395 * WsReceiveMessage [webservices.@]
2397 HRESULT WINAPI
WsReceiveMessage( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_MESSAGE_DESCRIPTION
**desc
,
2398 ULONG count
, WS_RECEIVE_OPTION option
, WS_READ_OPTION read_option
, WS_HEAP
*heap
,
2399 void *value
, ULONG size
, ULONG
*index
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2401 struct channel
*channel
= (struct channel
*)handle
;
2402 WS_ASYNC_CONTEXT ctx_local
;
2406 TRACE( "%p %p %p %u %08x %08x %p %p %u %p %p %p\n", handle
, msg
, desc
, count
, option
, read_option
, heap
,
2407 value
, size
, index
, ctx
, error
);
2408 if (error
) FIXME( "ignoring error parameter\n" );
2410 if (!channel
|| !msg
|| !desc
|| !count
) return E_INVALIDARG
;
2412 EnterCriticalSection( &channel
->cs
);
2414 if (channel
->magic
!= CHANNEL_MAGIC
)
2416 LeaveCriticalSection( &channel
->cs
);
2417 return E_INVALIDARG
;
2420 if (!ctx
) async_init( &async
, &ctx_local
);
2421 hr
= queue_receive_message( channel
, msg
, desc
, count
, option
, read_option
, heap
, value
, size
, index
,
2422 ctx
? ctx
: &ctx_local
);
2425 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2426 CloseHandle( async
.done
);
2429 LeaveCriticalSection( &channel
->cs
);
2430 TRACE( "returning %08x\n", hr
);
2434 static HRESULT
request_reply( struct channel
*channel
, WS_MESSAGE
*request
,
2435 const WS_MESSAGE_DESCRIPTION
*request_desc
, WS_WRITE_OPTION write_option
,
2436 const void *request_body
, ULONG request_size
, WS_MESSAGE
*reply
,
2437 const WS_MESSAGE_DESCRIPTION
*reply_desc
, WS_READ_OPTION read_option
,
2438 WS_HEAP
*heap
, void *value
, ULONG size
)
2442 if ((hr
= send_message( channel
, request
, request_desc
, write_option
, request_body
, request_size
)) != S_OK
)
2445 return receive_message( channel
, reply
, &reply_desc
, 1, WS_RECEIVE_OPTIONAL_MESSAGE
, read_option
, heap
,
2446 value
, size
, NULL
);
2449 struct request_reply
2452 struct channel
*channel
;
2453 WS_MESSAGE
*request
;
2454 const WS_MESSAGE_DESCRIPTION
*request_desc
;
2455 WS_WRITE_OPTION write_option
;
2456 const void *request_body
;
2459 const WS_MESSAGE_DESCRIPTION
*reply_desc
;
2460 WS_READ_OPTION read_option
;
2464 WS_ASYNC_CONTEXT ctx
;
2467 static void request_reply_proc( struct task
*task
)
2469 struct request_reply
*r
= (struct request_reply
*)task
;
2472 hr
= request_reply( r
->channel
, r
->request
, r
->request_desc
, r
->write_option
, r
->request_body
, r
->request_size
,
2473 r
->reply
, r
->reply_desc
, r
->read_option
, r
->heap
, r
->value
, r
->size
);
2475 TRACE( "calling %p(%08x)\n", r
->ctx
.callback
, hr
);
2476 r
->ctx
.callback( hr
, WS_LONG_CALLBACK
, r
->ctx
.callbackState
);
2477 TRACE( "%p returned\n", r
->ctx
.callback
);
2480 static HRESULT
queue_request_reply( struct channel
*channel
, WS_MESSAGE
*request
,
2481 const WS_MESSAGE_DESCRIPTION
*request_desc
, WS_WRITE_OPTION write_option
,
2482 const void *request_body
, ULONG request_size
, WS_MESSAGE
*reply
,
2483 const WS_MESSAGE_DESCRIPTION
*reply_desc
, WS_READ_OPTION read_option
,
2484 WS_HEAP
*heap
, void *value
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
)
2486 struct request_reply
*r
;
2488 if (!(r
= heap_alloc( sizeof(*r
) ))) return E_OUTOFMEMORY
;
2489 r
->task
.proc
= request_reply_proc
;
2490 r
->channel
= channel
;
2491 r
->request
= request
;
2492 r
->request_desc
= request_desc
;
2493 r
->write_option
= write_option
;
2494 r
->request_body
= request_body
;
2495 r
->request_size
= request_size
;
2497 r
->reply_desc
= reply_desc
;
2498 r
->read_option
= read_option
;
2503 return queue_task( &channel
->recv_q
, &r
->task
);
2506 /**************************************************************************
2507 * WsRequestReply [webservices.@]
2509 HRESULT WINAPI
WsRequestReply( WS_CHANNEL
*handle
, WS_MESSAGE
*request
, const WS_MESSAGE_DESCRIPTION
*request_desc
,
2510 WS_WRITE_OPTION write_option
, const void *request_body
, ULONG request_size
,
2511 WS_MESSAGE
*reply
, const WS_MESSAGE_DESCRIPTION
*reply_desc
, WS_READ_OPTION read_option
,
2512 WS_HEAP
*heap
, void *value
, ULONG size
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2514 struct channel
*channel
= (struct channel
*)handle
;
2515 WS_ASYNC_CONTEXT ctx_local
;
2519 TRACE( "%p %p %p %08x %p %u %p %p %08x %p %p %u %p %p\n", handle
, request
, request_desc
, write_option
,
2520 request_body
, request_size
, reply
, reply_desc
, read_option
, heap
, value
, size
, ctx
, error
);
2521 if (error
) FIXME( "ignoring error parameter\n" );
2523 if (!channel
|| !request
|| !reply
) return E_INVALIDARG
;
2525 EnterCriticalSection( &channel
->cs
);
2527 if (channel
->magic
!= CHANNEL_MAGIC
)
2529 LeaveCriticalSection( &channel
->cs
);
2530 return E_INVALIDARG
;
2532 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2534 LeaveCriticalSection( &channel
->cs
);
2535 return WS_E_INVALID_OPERATION
;
2538 WsInitializeMessage( request
, WS_REQUEST_MESSAGE
, NULL
, NULL
);
2540 if (!ctx
) async_init( &async
, &ctx_local
);
2541 hr
= queue_request_reply( channel
, request
, request_desc
, write_option
, request_body
, request_size
, reply
,
2542 reply_desc
, read_option
, heap
, value
, size
, ctx
? ctx
: &ctx_local
);
2545 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2546 CloseHandle( async
.done
);
2549 LeaveCriticalSection( &channel
->cs
);
2550 TRACE( "returning %08x\n", hr
);
2554 static HRESULT
read_message_start( struct channel
*channel
, WS_MESSAGE
*msg
)
2557 if ((hr
= receive_message_bytes( channel
, msg
)) == S_OK
&& (hr
= init_reader( channel
)) == S_OK
)
2558 hr
= WsReadEnvelopeStart( msg
, channel
->reader
, NULL
, NULL
, NULL
);
2562 struct read_message_start
2565 struct channel
*channel
;
2567 WS_ASYNC_CONTEXT ctx
;
2570 static void read_message_start_proc( struct task
*task
)
2572 struct read_message_start
*r
= (struct read_message_start
*)task
;
2575 hr
= read_message_start( r
->channel
, r
->msg
);
2577 TRACE( "calling %p(%08x)\n", r
->ctx
.callback
, hr
);
2578 r
->ctx
.callback( hr
, WS_LONG_CALLBACK
, r
->ctx
.callbackState
);
2579 TRACE( "%p returned\n", r
->ctx
.callback
);
2582 static HRESULT
queue_read_message_start( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
)
2584 struct read_message_start
*r
;
2586 if (!(r
= heap_alloc( sizeof(*r
) ))) return E_OUTOFMEMORY
;
2587 r
->task
.proc
= read_message_start_proc
;
2588 r
->channel
= channel
;
2591 return queue_task( &channel
->recv_q
, &r
->task
);
2594 /**************************************************************************
2595 * WsReadMessageStart [webservices.@]
2597 HRESULT WINAPI
WsReadMessageStart( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2599 struct channel
*channel
= (struct channel
*)handle
;
2600 WS_ASYNC_CONTEXT ctx_local
;
2604 TRACE( "%p %p %p %p\n", handle
, msg
, ctx
, error
);
2605 if (error
) FIXME( "ignoring error parameter\n" );
2607 if (!channel
|| !msg
) return E_INVALIDARG
;
2609 EnterCriticalSection( &channel
->cs
);
2611 if (channel
->magic
!= CHANNEL_MAGIC
)
2613 LeaveCriticalSection( &channel
->cs
);
2614 return E_INVALIDARG
;
2616 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2618 LeaveCriticalSection( &channel
->cs
);
2619 return WS_E_INVALID_OPERATION
;
2622 if (!ctx
) async_init( &async
, &ctx_local
);
2623 hr
= queue_read_message_start( channel
, msg
, ctx
? ctx
: &ctx_local
);
2626 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2627 CloseHandle( async
.done
);
2630 LeaveCriticalSection( &channel
->cs
);
2631 TRACE( "returning %08x\n", hr
);
2635 static HRESULT
read_message_end( WS_MESSAGE
*msg
)
2637 return WsReadEnvelopeEnd( msg
, NULL
);
2640 struct read_message_end
2644 WS_ASYNC_CONTEXT ctx
;
2647 static void read_message_end_proc( struct task
*task
)
2649 struct read_message_end
*r
= (struct read_message_end
*)task
;
2652 hr
= read_message_end( r
->msg
);
2654 TRACE( "calling %p(%08x)\n", r
->ctx
.callback
, hr
);
2655 r
->ctx
.callback( hr
, WS_LONG_CALLBACK
, r
->ctx
.callbackState
);
2656 TRACE( "%p returned\n", r
->ctx
.callback
);
2659 static HRESULT
queue_read_message_end( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
)
2661 struct read_message_end
*r
;
2663 if (!(r
= heap_alloc( sizeof(*r
) ))) return E_OUTOFMEMORY
;
2664 r
->task
.proc
= read_message_end_proc
;
2667 return queue_task( &channel
->recv_q
, &r
->task
);
2670 /**************************************************************************
2671 * WsReadMessageEnd [webservices.@]
2673 HRESULT WINAPI
WsReadMessageEnd( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2675 struct channel
*channel
= (struct channel
*)handle
;
2676 WS_ASYNC_CONTEXT ctx_local
;
2680 TRACE( "%p %p %p %p\n", handle
, msg
, ctx
, error
);
2681 if (error
) FIXME( "ignoring error parameter\n" );
2683 if (!channel
|| !msg
) return E_INVALIDARG
;
2685 EnterCriticalSection( &channel
->cs
);
2687 if (channel
->magic
!= CHANNEL_MAGIC
)
2689 LeaveCriticalSection( &channel
->cs
);
2690 return E_INVALIDARG
;
2693 if (!ctx
) async_init( &async
, &ctx_local
);
2694 hr
= queue_read_message_end( channel
, msg
, ctx
? ctx
: &ctx_local
);
2697 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2698 CloseHandle( async
.done
);
2701 LeaveCriticalSection( &channel
->cs
);
2702 TRACE( "returning %08x\n", hr
);
2706 static HRESULT
write_message_start( struct channel
*channel
, WS_MESSAGE
*msg
)
2709 if ((hr
= init_writer( channel
)) != S_OK
) return hr
;
2710 if ((hr
= WsAddressMessage( msg
, &channel
->addr
, NULL
)) != S_OK
) return hr
;
2711 return WsWriteEnvelopeStart( msg
, channel
->writer
, NULL
, NULL
, NULL
);
2714 struct write_message_start
2717 struct channel
*channel
;
2719 WS_ASYNC_CONTEXT ctx
;
2722 static void write_message_start_proc( struct task
*task
)
2724 struct write_message_start
*w
= (struct write_message_start
*)task
;
2727 hr
= write_message_start( w
->channel
, w
->msg
);
2729 TRACE( "calling %p(%08x)\n", w
->ctx
.callback
, hr
);
2730 w
->ctx
.callback( hr
, WS_LONG_CALLBACK
, w
->ctx
.callbackState
);
2731 TRACE( "%p returned\n", w
->ctx
.callback
);
2734 static HRESULT
queue_write_message_start( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
)
2736 struct write_message_start
*w
;
2738 if (!(w
= heap_alloc( sizeof(*w
) ))) return E_OUTOFMEMORY
;
2739 w
->task
.proc
= write_message_start_proc
;
2740 w
->channel
= channel
;
2743 return queue_task( &channel
->send_q
, &w
->task
);
2746 /**************************************************************************
2747 * WsWriteMessageStart [webservices.@]
2749 HRESULT WINAPI
WsWriteMessageStart( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2751 struct channel
*channel
= (struct channel
*)handle
;
2752 WS_ASYNC_CONTEXT ctx_local
;
2756 TRACE( "%p %p %p %p\n", handle
, msg
, ctx
, error
);
2757 if (error
) FIXME( "ignoring error parameter\n" );
2759 if (!channel
|| !msg
) return E_INVALIDARG
;
2761 EnterCriticalSection( &channel
->cs
);
2763 if (channel
->magic
!= CHANNEL_MAGIC
)
2765 LeaveCriticalSection( &channel
->cs
);
2766 return E_INVALIDARG
;
2768 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2770 LeaveCriticalSection( &channel
->cs
);
2771 return WS_E_INVALID_OPERATION
;
2774 if (!ctx
) async_init( &async
, &ctx_local
);
2775 hr
= queue_write_message_start( channel
, msg
, ctx
? ctx
: &ctx_local
);
2778 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2779 CloseHandle( async
.done
);
2782 LeaveCriticalSection( &channel
->cs
);
2783 TRACE( "returning %08x\n", hr
);
2787 static HRESULT
write_message_end( struct channel
*channel
, WS_MESSAGE
*msg
)
2790 if ((hr
= WsWriteEnvelopeEnd( msg
, NULL
)) == S_OK
) hr
= send_message_bytes( channel
, msg
);
2794 struct write_message_end
2797 struct channel
*channel
;
2799 WS_ASYNC_CONTEXT ctx
;
2802 static void write_message_end_proc( struct task
*task
)
2804 struct write_message_end
*w
= (struct write_message_end
*)task
;
2807 hr
= write_message_end( w
->channel
, w
->msg
);
2809 TRACE( "calling %p(%08x)\n", w
->ctx
.callback
, hr
);
2810 w
->ctx
.callback( hr
, WS_LONG_CALLBACK
, w
->ctx
.callbackState
);
2811 TRACE( "%p returned\n", w
->ctx
.callback
);
2814 static HRESULT
queue_write_message_end( struct channel
*channel
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
)
2816 struct write_message_start
*w
;
2818 if (!(w
= heap_alloc( sizeof(*w
) ))) return E_OUTOFMEMORY
;
2819 w
->task
.proc
= write_message_end_proc
;
2820 w
->channel
= channel
;
2823 return queue_task( &channel
->send_q
, &w
->task
);
2826 /**************************************************************************
2827 * WsWriteMessageEnd [webservices.@]
2829 HRESULT WINAPI
WsWriteMessageEnd( WS_CHANNEL
*handle
, WS_MESSAGE
*msg
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
2831 struct channel
*channel
= (struct channel
*)handle
;
2832 WS_ASYNC_CONTEXT ctx_local
;
2836 TRACE( "%p %p %p %p\n", handle
, msg
, ctx
, error
);
2837 if (error
) FIXME( "ignoring error parameter\n" );
2839 if (!channel
|| !msg
) return E_INVALIDARG
;
2841 EnterCriticalSection( &channel
->cs
);
2843 if (channel
->magic
!= CHANNEL_MAGIC
)
2845 LeaveCriticalSection( &channel
->cs
);
2846 return E_INVALIDARG
;
2848 if (channel
->state
!= WS_CHANNEL_STATE_OPEN
)
2850 LeaveCriticalSection( &channel
->cs
);
2851 return WS_E_INVALID_OPERATION
;
2854 if (!ctx
) async_init( &async
, &ctx_local
);
2855 hr
= queue_write_message_end( channel
, msg
, ctx
? ctx
: &ctx_local
);
2858 if (hr
== WS_S_ASYNC
) hr
= async_wait( &async
);
2859 CloseHandle( async
.done
);
2862 LeaveCriticalSection( &channel
->cs
);
2863 TRACE( "returning %08x\n", hr
);
2867 static void set_blocking( SOCKET socket
, BOOL blocking
)
2869 ULONG state
= !blocking
;
2870 ioctlsocket( socket
, FIONBIO
, &state
);
2873 static HRESULT
sock_accept( SOCKET socket
, HANDLE wait
, HANDLE cancel
, SOCKET
*ret
)
2875 HANDLE handles
[] = { wait
, cancel
};
2878 if (WSAEventSelect( socket
, handles
[0], FD_ACCEPT
)) return HRESULT_FROM_WIN32( WSAGetLastError() );
2880 switch (WSAWaitForMultipleEvents( 2, handles
, FALSE
, WSA_INFINITE
, FALSE
))
2883 if ((*ret
= accept( socket
, NULL
, NULL
)) != -1)
2885 WSAEventSelect( *ret
, NULL
, 0 );
2886 set_blocking( *ret
, TRUE
);
2889 hr
= HRESULT_FROM_WIN32( WSAGetLastError() );
2893 hr
= WS_E_OPERATION_ABORTED
;
2897 hr
= HRESULT_FROM_WIN32( WSAGetLastError() );
2904 HRESULT
channel_accept_tcp( SOCKET socket
, HANDLE wait
, HANDLE cancel
, WS_CHANNEL
*handle
)
2906 struct channel
*channel
= (struct channel
*)handle
;
2909 EnterCriticalSection( &channel
->cs
);
2911 if (channel
->magic
!= CHANNEL_MAGIC
)
2913 LeaveCriticalSection( &channel
->cs
);
2914 return E_INVALIDARG
;
2917 if ((hr
= sock_accept( socket
, wait
, cancel
, &channel
->u
.tcp
.socket
)) == S_OK
)
2919 BOOL nodelay
= FALSE
;
2920 prop_get( channel
->prop
, channel
->prop_count
, WS_CHANNEL_PROPERTY_NO_DELAY
, &nodelay
, sizeof(nodelay
) );
2921 setsockopt( channel
->u
.tcp
.socket
, IPPROTO_TCP
, TCP_NODELAY
, (const char *)&nodelay
, sizeof(nodelay
) );
2922 channel
->state
= WS_CHANNEL_STATE_OPEN
;
2925 LeaveCriticalSection( &channel
->cs
);
2929 static HRESULT
sock_wait( SOCKET socket
, HANDLE wait
, HANDLE cancel
)
2931 HANDLE handles
[] = { wait
, cancel
};
2934 if (WSAEventSelect( socket
, handles
[0], FD_READ
)) return HRESULT_FROM_WIN32( WSAGetLastError() );
2936 switch (WSAWaitForMultipleEvents( 2, handles
, FALSE
, WSA_INFINITE
, FALSE
))
2943 hr
= WS_E_OPERATION_ABORTED
;
2947 hr
= HRESULT_FROM_WIN32( WSAGetLastError() );
2951 WSAEventSelect( socket
, NULL
, 0 );
2952 set_blocking( socket
, TRUE
);
2956 HRESULT
channel_accept_udp( SOCKET socket
, HANDLE wait
, HANDLE cancel
, WS_CHANNEL
*handle
)
2958 struct channel
*channel
= (struct channel
*)handle
;
2961 EnterCriticalSection( &channel
->cs
);
2963 if (channel
->magic
!= CHANNEL_MAGIC
)
2965 LeaveCriticalSection( &channel
->cs
);
2966 return E_INVALIDARG
;
2969 if ((hr
= sock_wait( socket
, wait
, cancel
)) == S_OK
)
2971 channel
->u
.udp
.socket
= socket
;
2972 channel
->state
= WS_CHANNEL_STATE_OPEN
;
2975 LeaveCriticalSection( &channel
->cs
);