webservices: Properly handle max session dictionary size channel property.
[wine.git] / dlls / webservices / channel.c
blob4941844afe54a7a767878cf603344295b6d70a0a
1 /*
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
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winuser.h"
24 #include "rpc.h"
25 #include "webservices.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
29 #include "webservices_private.h"
30 #include "sock.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 */
88 struct task
90 struct list entry;
91 void (*proc)( struct task * );
94 struct queue
96 CRITICAL_SECTION cs;
97 HANDLE wait;
98 HANDLE cancel;
99 HANDLE ready;
100 struct list tasks;
103 static struct task *dequeue_task( struct queue *queue )
105 struct task *task;
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 );
114 return 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 );
123 for (;;)
125 DWORD err = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
126 switch (err)
128 case WAIT_OBJECT_0:
130 struct task *task;
131 while ((task = dequeue_task( queue )))
133 task->proc( task );
134 free( task );
136 break;
138 case WAIT_OBJECT_0 + 1:
139 TRACE( "cancelled\n" );
140 SetEvent( queue->ready );
141 return;
143 default:
144 ERR( "wait failed %lu\n", err );
145 return;
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() );
160 else
162 WaitForSingleObject( queue->ready, INFINITE );
163 return S_OK;
166 error:
167 CloseHandle( queue->wait );
168 queue->wait = NULL;
169 CloseHandle( queue->cancel );
170 queue->cancel = NULL;
171 CloseHandle( queue->ready );
172 queue->ready = NULL;
173 return hr;
176 static HRESULT queue_task( struct queue *queue, struct task *task )
178 HRESULT hr;
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 );
187 return WS_S_ASYNC;
190 enum session_state
192 SESSION_STATE_UNINITIALIZED,
193 SESSION_STATE_SETUP_COMPLETE,
194 SESSION_STATE_SHUTDOWN,
197 struct channel
199 ULONG magic;
200 CRITICAL_SECTION cs;
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;
207 WS_MESSAGE *msg;
208 WS_ENCODING encoding;
209 enum session_state session_state;
210 struct dictionary dict_send;
211 struct dictionary dict_recv;
212 struct queue send_q;
213 struct queue recv_q;
214 union
216 struct
218 HINTERNET session;
219 HINTERNET connect;
220 HINTERNET request;
221 WCHAR *path;
222 DWORD flags;
223 } http;
224 struct
226 SOCKET socket;
227 } tcp;
228 struct
230 SOCKET socket;
231 } udp;
232 } u;
233 char *read_buf;
234 ULONG read_buflen;
235 ULONG read_size;
236 char *send_buf;
237 ULONG send_buflen;
238 ULONG send_size;
239 ULONG dict_size;
240 ULONG prop_count;
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 );
249 struct channel *ret;
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;
264 return ret;
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 )
276 struct list *ptr;
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 );
285 free( task );
288 CloseHandle( queue->wait );
289 queue->wait = NULL;
290 CloseHandle( queue->cancel );
291 queue->cancel = NULL;
292 CloseHandle( queue->ready );
293 queue->ready = NULL;
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 );
316 return E_INVALIDARG;
319 abort_channel( channel );
321 LeaveCriticalSection( &channel->cs );
322 return S_OK;
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 );
332 channel->msg = NULL;
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;
348 break;
350 case WS_TCP_CHANNEL_BINDING:
351 closesocket( channel->u.tcp.socket );
352 channel->u.tcp.socket = -1;
353 break;
355 case WS_UDP_CHANNEL_BINDING:
356 closesocket( channel->u.udp.socket );
357 channel->u.udp.socket = -1;
358 break;
360 default: break;
364 static void free_header_mappings( WS_HTTP_HEADER_MAPPING **mappings, ULONG count )
366 ULONG i;
367 for (i = 0; i < count; i++) free( mappings[i] );
368 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 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 );
402 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 = 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;
415 return dst;
418 static HRESULT dup_message_mapping( const WS_HTTP_MESSAGE_MAPPING *src, WS_HTTP_MESSAGE_MAPPING *dst )
420 ULONG i, size;
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;
454 return S_OK;
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;
464 HRESULT hr;
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;
482 break;
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;
488 break;
490 case WS_UDP_CHANNEL_BINDING:
491 channel->u.udp.socket = -1;
492 channel->encoding = WS_ENCODING_XML_UTF8;
493 break;
495 default: break;
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 );
505 switch (prop->id)
507 case WS_CHANNEL_PROPERTY_ENCODING:
508 if (!prop->value || prop->valueSize != sizeof(channel->encoding))
510 free_channel( channel );
511 return E_INVALIDARG;
513 channel->encoding = *(WS_ENCODING *)prop->value;
514 break;
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 );
524 return E_INVALIDARG;
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 );
534 return hr;
536 break;
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 );
543 return E_INVALIDARG;
546 channel->dict_size = *(ULONG *)prop->value;
547 break;
549 default:
550 if ((hr = prop_set( channel->prop, channel->prop_count, prop->id, prop->value, prop->valueSize )) != S_OK)
552 free_channel( channel );
553 return hr;
555 break;
559 *ret = channel;
560 return S_OK;
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,
569 WS_ERROR *error )
571 struct channel *channel;
572 HRESULT hr;
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 );
584 return E_NOTIMPL;
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 );
590 return E_NOTIMPL;
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;
597 return S_OK;
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;
609 HRESULT hr;
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;
626 return S_OK;
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 );
645 return;
648 channel->magic = 0;
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;
660 HRESULT hr = S_OK;
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 );
672 return E_INVALIDARG;
675 if (channel->state != WS_CHANNEL_STATE_CREATED && channel->state != WS_CHANNEL_STATE_CLOSED)
676 hr = WS_E_INVALID_OPERATION;
677 else
679 abort_channel( channel );
680 reset_channel( channel );
683 LeaveCriticalSection( &channel->cs );
684 TRACE( "returning %#lx\n", hr );
685 return 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;
695 HRESULT hr = S_OK;
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 );
707 return E_INVALIDARG;
710 switch (id)
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;
715 break;
717 case WS_CHANNEL_PROPERTY_ENCODING:
718 if (!buf || size != sizeof(channel->encoding)) hr = E_INVALIDARG;
719 else *(WS_ENCODING *)buf = channel->encoding;
720 break;
722 case WS_CHANNEL_PROPERTY_STATE:
723 if (!buf || size != sizeof(channel->state)) hr = E_INVALIDARG;
724 else *(WS_CHANNEL_STATE *)buf = channel->state;
725 break;
727 case WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE:
728 if (channel->binding != WS_TCP_CHANNEL_BINDING || !buf || size != sizeof(channel->dict_size))
729 hr = E_INVALIDARG;
730 else
731 *(ULONG *)buf = channel->dict_size;
732 break;
734 default:
735 hr = prop_get( channel->prop, channel->prop_count, id, buf, size );
738 LeaveCriticalSection( &channel->cs );
739 TRACE( "returning %#lx\n", hr );
740 return 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;
750 HRESULT hr;
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 );
762 return E_INVALIDARG;
765 hr = prop_set( channel->prop, channel->prop_count, id, value, size );
767 LeaveCriticalSection( &channel->cs );
768 TRACE( "returning %#lx\n", hr );
769 return 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;
794 return S_OK;
797 struct async
799 HRESULT hr;
800 HANDLE done;
803 static void CALLBACK async_callback( HRESULT hr, WS_CALLBACK_MODEL model, void *state )
805 struct async *async = state;
806 async->hr = hr;
807 SetEvent( async->done );
810 static void async_init( struct async *async, WS_ASYNC_CONTEXT *ctx )
812 async->done = CreateEventW( NULL, FALSE, FALSE, NULL );
813 async->hr = E_FAIL;
814 ctx->callback = async_callback;
815 ctx->callbackState = async;
818 static HRESULT async_wait( struct async *async )
820 DWORD err;
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 )
827 HRESULT hr;
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;
838 return S_OK;
840 default:
841 FIXME( "unhandled binding %u\n", channel->binding );
842 return E_NOTIMPL;
846 struct shutdown_session
848 struct task task;
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;
856 HRESULT hr;
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;
872 s->ctx = *ctx;
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;
880 struct async async;
881 HRESULT hr;
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 );
893 return E_INVALIDARG;
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 );
903 if (!ctx)
905 if (hr == WS_S_ASYNC) hr = async_wait( &async );
906 CloseHandle( async.done );
909 LeaveCriticalSection( &channel->cs );
910 TRACE( "returning %#lx\n", hr );
911 return hr;
914 static void close_channel( struct channel *channel )
916 reset_channel( channel );
917 channel->state = WS_CHANNEL_STATE_CLOSED;
920 struct close_channel
922 struct task task;
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;
945 c->ctx = *ctx;
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;
956 struct async async;
957 HRESULT hr;
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 );
969 return E_INVALIDARG;
972 if (!ctx) async_init( &async, &ctx_local );
973 hr = queue_close_channel( channel, ctx ? ctx : &ctx_local );
974 if (!ctx)
976 if (hr == WS_S_ASYNC) hr = async_wait( &async );
977 CloseHandle( async.done );
980 LeaveCriticalSection( &channel->cs );
981 TRACE( "returning %#lx\n", hr );
982 return hr;
985 static HRESULT parse_http_url( const WCHAR *url, ULONG len, URL_COMPONENTS *uc )
987 HRESULT hr = E_OUTOFMEMORY;
988 WCHAR *tmp;
989 DWORD err;
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 );
1006 goto error;
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 );
1017 return S_OK;
1019 error:
1020 free( uc->lpszHostName );
1021 free( uc->lpszUrlPath );
1022 free( uc->lpszExtraInfo );
1023 return hr;
1026 static HRESULT open_channel_http( struct channel *channel )
1028 HINTERNET ses = NULL, con = NULL;
1029 URL_COMPONENTS uc;
1030 HRESULT hr;
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) )))
1037 hr = E_OUTOFMEMORY;
1038 goto done;
1040 else
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;
1047 switch (uc.nScheme)
1049 case INTERNET_SCHEME_HTTP: break;
1050 case INTERNET_SCHEME_HTTPS:
1051 channel->u.http.flags |= WINHTTP_FLAG_SECURE;
1052 break;
1054 default:
1055 hr = WS_E_INVALID_ENDPOINT_URL;
1056 goto done;
1059 if (!(ses = WinHttpOpen( L"MS-WebServices/1.0", 0, NULL, NULL, 0 )))
1061 hr = HRESULT_FROM_WIN32( GetLastError() );
1062 goto done;
1064 if (!(con = WinHttpConnect( ses, uc.lpszHostName, uc.nPort, 0 )))
1066 hr = HRESULT_FROM_WIN32( GetLastError() );
1067 goto done;
1070 channel->u.http.session = ses;
1071 channel->u.http.connect = con;
1073 done:
1074 if (hr != S_OK)
1076 WinHttpCloseHandle( con );
1077 WinHttpCloseHandle( ses );
1079 free( uc.lpszHostName );
1080 free( uc.lpszUrlPath );
1081 free( uc.lpszExtraInfo );
1082 return hr;
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;
1090 int addr_len;
1091 WS_URL_SCHEME_TYPE scheme;
1092 WCHAR *host;
1093 USHORT port;
1094 HRESULT hr;
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)
1101 free( host );
1102 return WS_E_INVALID_ENDPOINT_URL;
1105 winsock_init();
1107 hr = resolve_hostname( host, port, addr, &addr_len, 0 );
1108 free( host );
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) );
1123 return S_OK;
1126 static HRESULT open_channel_udp( struct channel *channel )
1128 struct sockaddr_storage storage;
1129 struct sockaddr *addr = (struct sockaddr *)&storage;
1130 int addr_len;
1131 WS_URL_SCHEME_TYPE scheme;
1132 WCHAR *host;
1133 USHORT port;
1134 HRESULT hr;
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)
1141 free( host );
1142 return WS_E_INVALID_ENDPOINT_URL;
1145 winsock_init();
1147 hr = resolve_hostname( host, port, addr, &addr_len, 0 );
1148 free( host );
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() );
1161 return S_OK;
1164 static HRESULT open_channel( struct channel *channel, const WS_ENDPOINT_ADDRESS *endpoint )
1166 HRESULT hr;
1168 if (endpoint->headers || endpoint->extensions || endpoint->identity)
1170 FIXME( "headers, extensions or identity not supported\n" );
1171 return E_NOTIMPL;
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 );
1184 break;
1186 case WS_TCP_CHANNEL_BINDING:
1187 hr = open_channel_tcp( channel );
1188 break;
1190 case WS_UDP_CHANNEL_BINDING:
1191 hr = open_channel_udp( channel );
1192 break;
1194 default:
1195 ERR( "unhandled binding %u\n", channel->binding );
1196 return E_NOTIMPL;
1199 if (hr == S_OK) channel->state = WS_CHANNEL_STATE_OPEN;
1200 return hr;
1203 struct open_channel
1205 struct task task;
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;
1214 HRESULT hr;
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;
1232 o->ctx = *ctx;
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,
1240 WS_ERROR *error )
1242 struct channel *channel = (struct channel *)handle;
1243 WS_ASYNC_CONTEXT ctx_local;
1244 struct async async;
1245 HRESULT hr;
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 );
1267 if (!ctx)
1269 if (hr == WS_S_ASYNC) hr = async_wait( &async );
1270 CloseHandle( async.done );
1273 LeaveCriticalSection( &channel->cs );
1274 TRACE( "returning %#lx\n", hr );
1275 return 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() );
1285 return S_OK;
1288 static ULONG get_max_buffer_size( struct channel *channel )
1290 ULONG size;
1291 prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE, &size, sizeof(size) );
1292 return 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;
1306 return S_OK;
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 )
1316 HRESULT hr;
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;
1335 return 5;
1338 static ULONG string_table_size( const struct dictionary *dict )
1340 ULONG i, size = 0;
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;
1346 return size;
1349 static HRESULT write_string_table( struct channel *channel, const struct dictionary *dict )
1351 ULONG i;
1352 HRESULT hr;
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;
1359 return S_OK;
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 );
1367 return S_OK;
1370 enum session_mode
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;
1383 default:
1384 FIXME( "unhandled channel type %#x\n", channel->type );
1385 return SESSION_MODE_INVALID;
1389 enum known_encoding
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) );
1408 switch (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;
1415 default:
1416 FIXME( "unhandled version/encoding %u/%u\n", version, channel->encoding );
1417 return 0;
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;
1426 default:
1427 FIXME( "unhandled version/encoding %u/%u\n", version, channel->encoding );
1428 return 0;
1430 default:
1431 ERR( "unhandled version %u\n", version );
1432 return 0;
1436 #define FRAME_VERSION_MAJOR 1
1437 #define FRAME_VERSION_MINOR 0
1439 static HRESULT write_preamble( struct channel *channel )
1441 unsigned char *url;
1442 HRESULT hr;
1443 int len;
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 );
1461 done:
1462 free( url );
1463 return hr;
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;
1471 return S_OK;
1474 static HRESULT send_preamble( struct channel *channel )
1476 HRESULT hr;
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;
1480 return S_OK;
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;
1488 return S_OK;
1491 static HRESULT receive_preamble_ack( struct channel *channel )
1493 unsigned char byte;
1494 HRESULT hr;
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;
1499 return S_OK;
1502 static HRESULT write_sized_envelope( struct channel *channel, BYTE *data, ULONG len )
1504 ULONG table_size = string_table_size( &channel->dict_send );
1505 HRESULT hr;
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 )
1516 HRESULT hr;
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;
1520 return S_OK;
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;
1533 WS_BYTES buf;
1534 HRESULT hr;
1536 channel->msg = msg;
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;
1560 /* fall through */
1562 case SESSION_STATE_SETUP_COMPLETE:
1563 return send_sized_envelope( channel, buf.bytes, buf.length );
1565 default:
1566 ERR( "unhandled session state %u\n", channel->session_state );
1567 return WS_E_OTHER;
1570 /* fall through */
1572 case WS_UDP_CHANNEL_BINDING:
1573 return WsFlushWriter( writer, 0, NULL, NULL );
1575 default:
1576 ERR( "unhandled binding %u\n", channel->binding );
1577 return E_NOTIMPL;
1581 HRESULT channel_send_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
1583 struct channel *channel = (struct channel *)handle;
1584 HRESULT hr;
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 );
1602 return hr;
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;
1608 HRESULT hr = S_OK;
1609 BYTE *bytes;
1610 int index;
1612 if ((index = find_string( dict, str->bytes, str->length, id )) == -1)
1614 *found = TRUE;
1615 return S_OK;
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)
1622 *found = TRUE;
1623 return S_OK;
1625 free( bytes );
1627 *found = FALSE;
1628 return hr;
1631 static CALLBACK HRESULT write_callback( void *state, const WS_BYTES *buf, ULONG count, const WS_ASYNC_CONTEXT *ctx,
1632 WS_ERROR *error )
1634 SOCKET socket = *(SOCKET *)state;
1635 if (send( socket, (const char *)buf->bytes, buf->length, 0 ) < 0)
1637 TRACE( "send failed %u\n", WSAGetLastError() );
1639 return S_OK;
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);
1652 HRESULT hr;
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;
1672 break;
1674 case WS_ENCODING_XML_BINARY_SESSION_1:
1675 bin.staticDictionary = (WS_XML_DICTIONARY *)&dict_builtin_static.dict;
1676 /* fall through */
1678 case WS_ENCODING_XML_BINARY_1:
1679 encoding = &bin.encoding;
1680 output = &buf.output;
1681 break;
1683 default:
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 )
1694 HRESULT hr;
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 )
1707 HRESULT hr;
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 );
1715 struct send_message
1717 struct task task;
1718 struct channel *channel;
1719 WS_MESSAGE *msg;
1720 const WS_MESSAGE_DESCRIPTION *desc;
1721 WS_WRITE_OPTION option;
1722 const void *body;
1723 ULONG size;
1724 WS_ASYNC_CONTEXT ctx;
1727 static void send_message_proc( struct task *task )
1729 struct send_message *s = (struct send_message *)task;
1730 HRESULT hr;
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;
1747 s->msg = msg;
1748 s->desc = desc;
1749 s->option = option;
1750 s->body = body;
1751 s->size = size;
1752 s->ctx = *ctx;
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,
1761 WS_ERROR *error )
1763 struct channel *channel = (struct channel *)handle;
1764 WS_ASYNC_CONTEXT ctx_local;
1765 struct async async;
1766 HRESULT hr;
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 );
1790 if (!ctx)
1792 if (hr == WS_S_ASYNC) hr = async_wait( &async );
1793 CloseHandle( async.done );
1796 LeaveCriticalSection( &channel->cs );
1797 TRACE( "returning %#lx\n", hr );
1798 return 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;
1810 struct async async;
1811 GUID id;
1812 HRESULT hr;
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 );
1838 if (!ctx)
1840 if (hr == WS_S_ASYNC) hr = async_wait( &async );
1841 CloseHandle( async.done );
1844 done:
1845 LeaveCriticalSection( &channel->cs );
1846 TRACE( "returning %#lx\n", hr );
1847 return 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;
1856 return S_OK;
1858 if (channel->read_buflen < size)
1860 char *tmp;
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;
1866 return S_OK;
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;
1873 int ret;
1875 if ((ret = recv( socket, buf, buflen, 0 )) >= 0) *retlen = ret;
1876 else
1878 TRACE( "recv failed %u\n", WSAGetLastError() );
1879 *retlen = 0;
1881 return S_OK;
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;
1892 HRESULT hr;
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;
1910 else
1912 buf.encodedData = channel->read_buf;
1913 buf.encodedDataSize = channel->read_size;
1914 input = &buf.input;
1916 break;
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;
1921 /* fall through */
1923 case WS_ENCODING_XML_BINARY_1:
1924 encoding = &bin.encoding;
1926 buf.encodedData = channel->read_buf;
1927 buf.encodedDataSize = channel->read_size;
1928 input = &buf.input;
1929 break;
1931 default:
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 );
1956 HRESULT hr;
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;
1962 for (;;)
1964 if (!WinHttpQueryDataAvailable( channel->u.http.request, &len ))
1966 return HRESULT_FROM_WIN32( GetLastError() );
1968 if (!len) break;
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;
1981 return S_OK;
1984 static HRESULT receive_message_sized( struct channel *channel, unsigned int size )
1986 unsigned int offset = 0, to_read = size;
1987 int bytes_read;
1988 HRESULT hr;
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;
2005 return S_OK;
2008 static HRESULT receive_size( struct channel *channel, unsigned int *size )
2010 unsigned char byte;
2011 HRESULT hr;
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;
2032 return S_OK;
2035 static WS_ENCODING map_known_encoding( enum known_encoding encoding )
2037 switch (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;
2047 default:
2048 WARN( "unhandled encoding %u, assuming UTF8\n", encoding );
2049 return WS_ENCODING_XML_UTF8;
2053 static HRESULT receive_preamble( struct channel *channel )
2055 unsigned char type;
2056 HRESULT hr;
2058 for (;;)
2060 if ((hr = receive_bytes( channel, &type, 1 )) != S_OK) return hr;
2061 if (type == FRAME_RECORD_TYPE_PREAMBLE_END) break;
2062 switch (type)
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 );
2070 break;
2072 case FRAME_RECORD_TYPE_MODE:
2074 unsigned char mode;
2075 if ((hr = receive_bytes( channel, &mode, 1 )) != S_OK) return hr;
2076 TRACE( "mode %u\n", mode );
2077 break;
2079 case FRAME_RECORD_TYPE_VIA:
2081 unsigned int size;
2082 unsigned char *url;
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)
2088 free( url );
2089 return hr;
2091 TRACE( "transport URL %s\n", debugstr_an((char *)url, size) );
2092 free( url ); /* FIXME: verify */
2093 break;
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 );
2101 break;
2103 default:
2104 WARN( "unhandled record type %u\n", type );
2105 return WS_E_INVALID_FORMAT;
2109 return S_OK;
2112 static HRESULT receive_sized_envelope( struct channel *channel )
2114 unsigned char type;
2115 unsigned int size;
2116 HRESULT hr;
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;
2123 return S_OK;
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))
2134 *ptr += 1;
2135 return S_OK;
2137 if (len < 2) return WS_E_INVALID_FORMAT;
2138 *size += (buf[1] & 0x7f) << 7;
2139 if (!(buf[1] & 0x80))
2141 *ptr += 2;
2142 return S_OK;
2144 if (len < 3) return WS_E_INVALID_FORMAT;
2145 *size += (buf[2] & 0x7f) << 14;
2146 if (!(buf[2] & 0x80))
2148 *ptr += 3;
2149 return S_OK;
2151 if (len < 4) return WS_E_INVALID_FORMAT;
2152 *size += (buf[3] & 0x7f) << 21;
2153 if (!(buf[3] & 0x80))
2155 *ptr += 4;
2156 return S_OK;
2158 if (len < 5 || (buf[4] & ~0x07)) return WS_E_INVALID_FORMAT;
2159 *size += buf[4] << 28;
2160 *ptr += 5;
2161 return S_OK;
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;
2168 BYTE *bytes;
2169 int index;
2170 HRESULT hr;
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)
2187 clear_dict( dict );
2188 return hr;
2190 if (size > buflen)
2192 clear_dict( dict );
2193 return WS_E_INVALID_FORMAT;
2195 buflen -= size;
2196 if (!(bytes = malloc( size )))
2198 hr = E_OUTOFMEMORY;
2199 goto error;
2201 memcpy( bytes, ptr, size );
2202 if ((index = find_string( dict, bytes, size, NULL )) == -1) /* duplicate */
2204 free( bytes );
2205 ptr += size;
2206 continue;
2208 if ((hr = insert_string( dict, bytes, size, index, NULL )) != S_OK)
2210 free( bytes );
2211 clear_dict( dict );
2212 return hr;
2214 ptr += size;
2216 return S_OK;
2218 error:
2219 clear_dict( dict );
2220 return hr;
2223 static HRESULT send_preamble_ack( struct channel *channel )
2225 HRESULT hr;
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;
2228 return S_OK;
2231 static HRESULT receive_message_bytes_session( struct channel *channel )
2233 HRESULT hr;
2235 if ((hr = receive_sized_envelope( channel )) != S_OK) return hr;
2236 if (channel->encoding == WS_ENCODING_XML_BINARY_SESSION_1)
2238 ULONG size;
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 );
2245 return S_OK;
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)
2258 HRESULT hr;
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;
2264 /* fall through */
2266 case SESSION_STATE_SETUP_COMPLETE:
2267 return receive_message_bytes_session( channel );
2269 default:
2270 ERR( "unhandled session state %u\n", channel->session_state );
2271 return WS_E_OTHER;
2274 return S_OK; /* nothing to do, data is read through stream callback */
2276 case WS_UDP_CHANNEL_BINDING:
2277 return S_OK;
2279 default:
2280 ERR( "unhandled binding %u\n", channel->binding );
2281 return E_NOTIMPL;
2285 HRESULT channel_receive_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
2287 struct channel *channel = (struct channel *)handle;
2288 HRESULT hr;
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 );
2306 return hr;
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 );
2324 return S_OK;
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 )
2330 HRESULT hr;
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 )
2340 HRESULT hr;
2341 ULONG i;
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;
2352 break;
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
2362 struct task task;
2363 struct channel *channel;
2364 WS_MESSAGE *msg;
2365 const WS_MESSAGE_DESCRIPTION **desc;
2366 ULONG count;
2367 WS_RECEIVE_OPTION option;
2368 WS_READ_OPTION read_option;
2369 WS_HEAP *heap;
2370 void *value;
2371 ULONG size;
2372 ULONG *index;
2373 WS_ASYNC_CONTEXT ctx;
2376 static void receive_message_proc( struct task *task )
2378 struct receive_message *r = (struct receive_message *)task;
2379 HRESULT hr;
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;
2399 r->msg = msg;
2400 r->desc = desc;
2401 r->count = count;
2402 r->option = option;
2403 r->read_option = read_option;
2404 r->heap = heap;
2405 r->value = value;
2406 r->size = size;
2407 r->index = index;
2408 r->ctx = *ctx;
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;
2421 struct async async;
2422 HRESULT hr;
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 );
2446 if (!ctx)
2448 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2449 CloseHandle( async.done );
2452 LeaveCriticalSection( &channel->cs );
2453 TRACE( "returning %#lx\n", hr );
2454 return 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 )
2463 HRESULT hr;
2465 if ((hr = send_message( channel, request, request_desc, write_option, request_body, request_size )) != S_OK)
2466 return hr;
2468 return receive_message( channel, reply, &reply_desc, 1, WS_RECEIVE_OPTIONAL_MESSAGE, read_option, heap,
2469 value, size, NULL );
2472 struct request_reply
2474 struct task task;
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;
2480 ULONG request_size;
2481 WS_MESSAGE *reply;
2482 const WS_MESSAGE_DESCRIPTION *reply_desc;
2483 WS_READ_OPTION read_option;
2484 WS_HEAP *heap;
2485 void *value;
2486 ULONG size;
2487 WS_ASYNC_CONTEXT ctx;
2490 static void request_reply_proc( struct task *task )
2492 struct request_reply *r = (struct request_reply *)task;
2493 HRESULT hr;
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;
2519 r->reply = reply;
2520 r->reply_desc = reply_desc;
2521 r->read_option = read_option;
2522 r->heap = heap;
2523 r->value = value;
2524 r->size = size;
2525 r->ctx = *ctx;
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;
2539 struct async async;
2540 HRESULT hr;
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 );
2566 if (!ctx)
2568 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2569 CloseHandle( async.done );
2572 LeaveCriticalSection( &channel->cs );
2573 TRACE( "returning %#lx\n", hr );
2574 return hr;
2577 static HRESULT read_message_start( struct channel *channel, WS_MESSAGE *msg )
2579 HRESULT hr;
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 );
2582 return hr;
2585 struct read_message_start
2587 struct task task;
2588 struct channel *channel;
2589 WS_MESSAGE *msg;
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;
2596 HRESULT hr;
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;
2612 r->msg = msg;
2613 r->ctx = *ctx;
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;
2624 struct async async;
2625 HRESULT hr;
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 );
2647 if (!ctx)
2649 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2650 CloseHandle( async.done );
2653 LeaveCriticalSection( &channel->cs );
2654 TRACE( "returning %#lx\n", hr );
2655 return hr;
2658 static HRESULT read_message_end( WS_MESSAGE *msg )
2660 return WsReadEnvelopeEnd( msg, NULL );
2663 struct read_message_end
2665 struct task task;
2666 WS_MESSAGE *msg;
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;
2673 HRESULT hr;
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;
2688 r->msg = msg;
2689 r->ctx = *ctx;
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;
2700 struct async async;
2701 HRESULT hr;
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 );
2718 if (!ctx)
2720 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2721 CloseHandle( async.done );
2724 LeaveCriticalSection( &channel->cs );
2725 TRACE( "returning %#lx\n", hr );
2726 return hr;
2729 static HRESULT write_message_start( struct channel *channel, WS_MESSAGE *msg )
2731 HRESULT hr;
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
2739 struct task task;
2740 struct channel *channel;
2741 WS_MESSAGE *msg;
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;
2748 HRESULT hr;
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;
2764 w->msg = msg;
2765 w->ctx = *ctx;
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;
2776 struct async async;
2777 HRESULT hr;
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 );
2799 if (!ctx)
2801 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2802 CloseHandle( async.done );
2805 LeaveCriticalSection( &channel->cs );
2806 TRACE( "returning %#lx\n", hr );
2807 return hr;
2810 static HRESULT write_message_end( struct channel *channel, WS_MESSAGE *msg )
2812 HRESULT hr;
2813 if ((hr = WsWriteEnvelopeEnd( msg, NULL )) == S_OK) hr = send_message_bytes( channel, msg );
2814 return hr;
2817 struct write_message_end
2819 struct task task;
2820 struct channel *channel;
2821 WS_MESSAGE *msg;
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;
2828 HRESULT hr;
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;
2844 w->msg = msg;
2845 w->ctx = *ctx;
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;
2856 struct async async;
2857 HRESULT hr;
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 );
2879 if (!ctx)
2881 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2882 CloseHandle( async.done );
2885 LeaveCriticalSection( &channel->cs );
2886 TRACE( "returning %#lx\n", hr );
2887 return 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 };
2899 HRESULT hr = S_OK;
2901 if (WSAEventSelect( socket, handles[0], FD_ACCEPT )) return HRESULT_FROM_WIN32( WSAGetLastError() );
2903 switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE ))
2905 case 0:
2906 if ((*ret = accept( socket, NULL, NULL )) != -1)
2908 WSAEventSelect( *ret, NULL, 0 );
2909 set_blocking( *ret, TRUE );
2910 break;
2912 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
2913 break;
2915 case 1:
2916 hr = WS_E_OPERATION_ABORTED;
2917 break;
2919 default:
2920 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
2921 break;
2924 return hr;
2927 HRESULT channel_accept_tcp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle )
2929 struct channel *channel = (struct channel *)handle;
2930 HRESULT hr;
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 );
2949 return hr;
2952 static HRESULT sock_wait( SOCKET socket, HANDLE wait, HANDLE cancel )
2954 HANDLE handles[] = { wait, cancel };
2955 HRESULT hr;
2957 if (WSAEventSelect( socket, handles[0], FD_READ )) return HRESULT_FROM_WIN32( WSAGetLastError() );
2959 switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE ))
2961 case 0:
2962 hr = S_OK;
2963 break;
2965 case 1:
2966 hr = WS_E_OPERATION_ABORTED;
2967 break;
2969 default:
2970 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
2971 break;
2974 WSAEventSelect( socket, NULL, 0 );
2975 set_blocking( socket, TRUE );
2976 return hr;
2979 HRESULT channel_accept_udp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle )
2981 struct channel *channel = (struct channel *)handle;
2982 HRESULT hr;
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 );
2999 return hr;