cmd: DIR command outputs free space for the path.
[wine.git] / dlls / webservices / channel.c
blob5851fd9d4af9cc0ba7f492fad3c97ac5dacfd6cc
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 init_dict( &channel->dict_send, channel->dict_size );
331 init_dict( &channel->dict_recv, channel->dict_size );
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 channel->dict_send.str_bytes_max = channel->dict_size;
489 channel->dict_recv.str_bytes_max = channel->dict_size;
490 break;
492 case WS_UDP_CHANNEL_BINDING:
493 channel->u.udp.socket = -1;
494 channel->encoding = WS_ENCODING_XML_UTF8;
495 break;
497 default: break;
500 for (i = 0; i < count; i++)
502 const WS_CHANNEL_PROPERTY *prop = &properties[i];
504 TRACE( "property id %u value %p size %lu\n", prop->id, prop->value, prop->valueSize );
505 if (prop->valueSize == sizeof(ULONG) && prop->value) TRACE( " value %#lx\n", *(ULONG *)prop->value );
507 switch (prop->id)
509 case WS_CHANNEL_PROPERTY_ENCODING:
510 if (!prop->value || prop->valueSize != sizeof(channel->encoding))
512 free_channel( channel );
513 return E_INVALIDARG;
515 channel->encoding = *(WS_ENCODING *)prop->value;
516 break;
518 case WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING:
520 const WS_HTTP_MESSAGE_MAPPING *src = (WS_HTTP_MESSAGE_MAPPING *)prop->value;
521 WS_HTTP_MESSAGE_MAPPING dst;
523 if (!prop->value || prop->valueSize != sizeof(*src))
525 free_channel( channel );
526 return E_INVALIDARG;
529 if ((hr = dup_message_mapping( src, &dst )) != S_OK) return hr;
531 if ((hr = prop_set( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING, &dst,
532 sizeof(dst) )) != S_OK)
534 free_message_mapping( &dst );
535 free_channel( channel );
536 return hr;
538 break;
541 case WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE:
542 if (channel->binding != WS_TCP_CHANNEL_BINDING || !prop->value || prop->valueSize != sizeof(channel->dict_size))
544 free_channel( channel );
545 return E_INVALIDARG;
548 channel->dict_size = *(ULONG *)prop->value;
549 channel->dict_send.str_bytes_max = channel->dict_size;
550 channel->dict_recv.str_bytes_max = channel->dict_size;
551 break;
553 default:
554 if ((hr = prop_set( channel->prop, channel->prop_count, prop->id, prop->value, prop->valueSize )) != S_OK)
556 free_channel( channel );
557 return hr;
559 break;
563 *ret = channel;
564 return S_OK;
567 /**************************************************************************
568 * WsCreateChannel [webservices.@]
570 HRESULT WINAPI WsCreateChannel( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding,
571 const WS_CHANNEL_PROPERTY *properties, ULONG count,
572 const WS_SECURITY_DESCRIPTION *desc, WS_CHANNEL **handle,
573 WS_ERROR *error )
575 struct channel *channel;
576 HRESULT hr;
578 TRACE( "%u %u %p %lu %p %p %p\n", type, binding, properties, count, desc, handle, error );
579 if (error) FIXME( "ignoring error parameter\n" );
580 if (desc) FIXME( "ignoring security description\n" );
582 if (!handle) return E_INVALIDARG;
584 if (type != WS_CHANNEL_TYPE_REQUEST && type != WS_CHANNEL_TYPE_DUPLEX &&
585 type != WS_CHANNEL_TYPE_DUPLEX_SESSION)
587 FIXME( "channel type %u not implemented\n", type );
588 return E_NOTIMPL;
590 if (binding != WS_HTTP_CHANNEL_BINDING && binding != WS_TCP_CHANNEL_BINDING &&
591 binding != WS_UDP_CHANNEL_BINDING)
593 FIXME( "channel binding %u not implemented\n", binding );
594 return E_NOTIMPL;
597 if ((hr = create_channel( type, binding, properties, count, &channel )) != S_OK) return hr;
599 TRACE( "created %p\n", channel );
600 *handle = (WS_CHANNEL *)channel;
601 return S_OK;
604 /**************************************************************************
605 * WsCreateChannelForListener [webservices.@]
607 HRESULT WINAPI WsCreateChannelForListener( WS_LISTENER *listener_handle, const WS_CHANNEL_PROPERTY *properties,
608 ULONG count, WS_CHANNEL **handle, WS_ERROR *error )
610 struct channel *channel;
611 WS_CHANNEL_TYPE type;
612 WS_CHANNEL_BINDING binding;
613 HRESULT hr;
615 TRACE( "%p %p %lu %p %p\n", listener_handle, properties, count, handle, error );
616 if (error) FIXME( "ignoring error parameter\n" );
618 if (!listener_handle || !handle) return E_INVALIDARG;
620 if ((hr = WsGetListenerProperty( listener_handle, WS_LISTENER_PROPERTY_CHANNEL_TYPE, &type,
621 sizeof(type), NULL )) != S_OK) return hr;
623 if ((hr = WsGetListenerProperty( listener_handle, WS_LISTENER_PROPERTY_CHANNEL_BINDING, &binding,
624 sizeof(binding), NULL )) != S_OK) return hr;
626 if ((hr = create_channel( type, binding, properties, count, &channel )) != S_OK) return hr;
628 TRACE( "created %p\n", channel );
629 *handle = (WS_CHANNEL *)channel;
630 return S_OK;
633 /**************************************************************************
634 * WsFreeChannel [webservices.@]
636 void WINAPI WsFreeChannel( WS_CHANNEL *handle )
638 struct channel *channel = (struct channel *)handle;
640 TRACE( "%p\n", handle );
642 if (!channel) return;
644 EnterCriticalSection( &channel->cs );
646 if (channel->magic != CHANNEL_MAGIC)
648 LeaveCriticalSection( &channel->cs );
649 return;
652 channel->magic = 0;
654 LeaveCriticalSection( &channel->cs );
655 free_channel( channel );
658 /**************************************************************************
659 * WsResetChannel [webservices.@]
661 HRESULT WINAPI WsResetChannel( WS_CHANNEL *handle, WS_ERROR *error )
663 struct channel *channel = (struct channel *)handle;
664 HRESULT hr = S_OK;
666 TRACE( "%p %p\n", handle, error );
667 if (error) FIXME( "ignoring error parameter\n" );
669 if (!channel) return E_INVALIDARG;
671 EnterCriticalSection( &channel->cs );
673 if (channel->magic != CHANNEL_MAGIC)
675 LeaveCriticalSection( &channel->cs );
676 return E_INVALIDARG;
679 if (channel->state != WS_CHANNEL_STATE_CREATED && channel->state != WS_CHANNEL_STATE_CLOSED)
680 hr = WS_E_INVALID_OPERATION;
681 else
683 abort_channel( channel );
684 reset_channel( channel );
687 LeaveCriticalSection( &channel->cs );
688 TRACE( "returning %#lx\n", hr );
689 return hr;
692 /**************************************************************************
693 * WsGetChannelProperty [webservices.@]
695 HRESULT WINAPI WsGetChannelProperty( WS_CHANNEL *handle, WS_CHANNEL_PROPERTY_ID id, void *buf,
696 ULONG size, WS_ERROR *error )
698 struct channel *channel = (struct channel *)handle;
699 HRESULT hr = S_OK;
701 TRACE( "%p %u %p %lu %p\n", handle, id, buf, size, error );
702 if (error) FIXME( "ignoring error parameter\n" );
704 if (!channel) return E_INVALIDARG;
706 EnterCriticalSection( &channel->cs );
708 if (channel->magic != CHANNEL_MAGIC)
710 LeaveCriticalSection( &channel->cs );
711 return E_INVALIDARG;
714 switch (id)
716 case WS_CHANNEL_PROPERTY_CHANNEL_TYPE:
717 if (!buf || size != sizeof(channel->type)) hr = E_INVALIDARG;
718 else *(WS_CHANNEL_TYPE *)buf = channel->type;
719 break;
721 case WS_CHANNEL_PROPERTY_ENCODING:
722 if (!buf || size != sizeof(channel->encoding)) hr = E_INVALIDARG;
723 else *(WS_ENCODING *)buf = channel->encoding;
724 break;
726 case WS_CHANNEL_PROPERTY_STATE:
727 if (!buf || size != sizeof(channel->state)) hr = E_INVALIDARG;
728 else *(WS_CHANNEL_STATE *)buf = channel->state;
729 break;
731 case WS_CHANNEL_PROPERTY_MAX_SESSION_DICTIONARY_SIZE:
732 if (channel->binding != WS_TCP_CHANNEL_BINDING || !buf || size != sizeof(channel->dict_size))
733 hr = E_INVALIDARG;
734 else
735 *(ULONG *)buf = channel->dict_size;
736 break;
738 default:
739 hr = prop_get( channel->prop, channel->prop_count, id, buf, size );
742 LeaveCriticalSection( &channel->cs );
743 TRACE( "returning %#lx\n", hr );
744 return hr;
747 /**************************************************************************
748 * WsSetChannelProperty [webservices.@]
750 HRESULT WINAPI WsSetChannelProperty( WS_CHANNEL *handle, WS_CHANNEL_PROPERTY_ID id, const void *value,
751 ULONG size, WS_ERROR *error )
753 struct channel *channel = (struct channel *)handle;
754 HRESULT hr;
756 TRACE( "%p %u %p %lu %p\n", handle, id, value, size, error );
757 if (error) FIXME( "ignoring error parameter\n" );
759 if (!channel) return E_INVALIDARG;
761 EnterCriticalSection( &channel->cs );
763 if (channel->magic != CHANNEL_MAGIC)
765 LeaveCriticalSection( &channel->cs );
766 return E_INVALIDARG;
769 hr = prop_set( channel->prop, channel->prop_count, id, value, size );
771 LeaveCriticalSection( &channel->cs );
772 TRACE( "returning %#lx\n", hr );
773 return hr;
776 enum frame_record_type
778 FRAME_RECORD_TYPE_VERSION,
779 FRAME_RECORD_TYPE_MODE,
780 FRAME_RECORD_TYPE_VIA,
781 FRAME_RECORD_TYPE_KNOWN_ENCODING,
782 FRAME_RECORD_TYPE_EXTENSIBLE_ENCODING,
783 FRAME_RECORD_TYPE_UNSIZED_ENVELOPE,
784 FRAME_RECORD_TYPE_SIZED_ENVELOPE,
785 FRAME_RECORD_TYPE_END,
786 FRAME_RECORD_TYPE_FAULT,
787 FRAME_RECORD_TYPE_UPGRADE_REQUEST,
788 FRAME_RECORD_TYPE_UPGRADE_RESPONSE,
789 FRAME_RECORD_TYPE_PREAMBLE_ACK,
790 FRAME_RECORD_TYPE_PREAMBLE_END,
793 static HRESULT send_byte( SOCKET socket, BYTE byte )
795 int count = send( socket, (char *)&byte, 1, 0 );
796 if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
797 if (count != 1) return WS_E_OTHER;
798 return S_OK;
801 struct async
803 HRESULT hr;
804 HANDLE done;
807 static void CALLBACK async_callback( HRESULT hr, WS_CALLBACK_MODEL model, void *state )
809 struct async *async = state;
810 async->hr = hr;
811 SetEvent( async->done );
814 static void async_init( struct async *async, WS_ASYNC_CONTEXT *ctx )
816 async->done = CreateEventW( NULL, FALSE, FALSE, NULL );
817 async->hr = E_FAIL;
818 ctx->callback = async_callback;
819 ctx->callbackState = async;
822 static HRESULT async_wait( struct async *async )
824 DWORD err;
825 if ((err = WaitForSingleObject( async->done, INFINITE )) == WAIT_OBJECT_0) return async->hr;
826 return HRESULT_FROM_WIN32( err );
829 static HRESULT shutdown_session( struct channel *channel )
831 HRESULT hr;
833 if ((channel->type != WS_CHANNEL_TYPE_OUTPUT_SESSION &&
834 channel->type != WS_CHANNEL_TYPE_DUPLEX_SESSION) ||
835 channel->session_state >= SESSION_STATE_SHUTDOWN) return WS_E_INVALID_OPERATION;
837 switch (channel->binding)
839 case WS_TCP_CHANNEL_BINDING:
840 if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_END )) != S_OK) return hr;
841 channel->session_state = SESSION_STATE_SHUTDOWN;
842 return S_OK;
844 default:
845 FIXME( "unhandled binding %u\n", channel->binding );
846 return E_NOTIMPL;
850 struct shutdown_session
852 struct task task;
853 struct channel *channel;
854 WS_ASYNC_CONTEXT ctx;
857 static void shutdown_session_proc( struct task *task )
859 struct shutdown_session *s = (struct shutdown_session *)task;
860 HRESULT hr;
862 hr = shutdown_session( s->channel );
864 TRACE( "calling %p(%#lx)\n", s->ctx.callback, hr );
865 s->ctx.callback( hr, WS_LONG_CALLBACK, s->ctx.callbackState );
866 TRACE( "%p returned\n", s->ctx.callback );
869 static HRESULT queue_shutdown_session( struct channel *channel, const WS_ASYNC_CONTEXT *ctx )
871 struct shutdown_session *s;
873 if (!(s = malloc( sizeof(*s) ))) return E_OUTOFMEMORY;
874 s->task.proc = shutdown_session_proc;
875 s->channel = channel;
876 s->ctx = *ctx;
877 return queue_task( &channel->send_q, &s->task );
880 static HRESULT check_state( struct channel *channel, WS_CHANNEL_STATE state_expected )
882 if (channel->state == WS_CHANNEL_STATE_FAULTED) return WS_E_OBJECT_FAULTED;
883 if (channel->state != state_expected) return WS_E_INVALID_OPERATION;
884 return S_OK;
887 HRESULT WINAPI WsShutdownSessionChannel( WS_CHANNEL *handle, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
889 struct channel *channel = (struct channel *)handle;
890 WS_ASYNC_CONTEXT ctx_local;
891 struct async async;
892 HRESULT hr;
894 TRACE( "%p %p %p\n", handle, ctx, error );
895 if (error) FIXME( "ignoring error parameter\n" );
897 if (!channel) return E_INVALIDARG;
899 EnterCriticalSection( &channel->cs );
901 if (channel->magic != CHANNEL_MAGIC)
903 LeaveCriticalSection( &channel->cs );
904 return E_INVALIDARG;
906 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
908 LeaveCriticalSection( &channel->cs );
909 return hr;
912 if (!ctx) async_init( &async, &ctx_local );
913 hr = queue_shutdown_session( channel, ctx ? ctx : &ctx_local );
914 if (!ctx)
916 if (hr == WS_S_ASYNC) hr = async_wait( &async );
917 CloseHandle( async.done );
920 LeaveCriticalSection( &channel->cs );
921 TRACE( "returning %#lx\n", hr );
922 return hr;
925 static void close_channel( struct channel *channel )
927 reset_channel( channel );
928 channel->state = WS_CHANNEL_STATE_CLOSED;
931 struct close_channel
933 struct task task;
934 struct channel *channel;
935 WS_ASYNC_CONTEXT ctx;
938 static void close_channel_proc( struct task *task )
940 struct close_channel *c = (struct close_channel *)task;
942 close_channel( c->channel );
944 TRACE( "calling %p(S_OK)\n", c->ctx.callback );
945 c->ctx.callback( S_OK, WS_LONG_CALLBACK, c->ctx.callbackState );
946 TRACE( "%p returned\n", c->ctx.callback );
949 static HRESULT queue_close_channel( struct channel *channel, const WS_ASYNC_CONTEXT *ctx )
951 struct close_channel *c;
953 if (!(c = malloc( sizeof(*c) ))) return E_OUTOFMEMORY;
954 c->task.proc = close_channel_proc;
955 c->channel = channel;
956 c->ctx = *ctx;
957 return queue_task( &channel->send_q, &c->task );
960 /**************************************************************************
961 * WsCloseChannel [webservices.@]
963 HRESULT WINAPI WsCloseChannel( WS_CHANNEL *handle, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
965 struct channel *channel = (struct channel *)handle;
966 WS_ASYNC_CONTEXT ctx_local;
967 struct async async;
968 HRESULT hr;
970 TRACE( "%p %p %p\n", handle, ctx, error );
971 if (error) FIXME( "ignoring error parameter\n" );
973 if (!channel) return E_INVALIDARG;
975 EnterCriticalSection( &channel->cs );
977 if (channel->magic != CHANNEL_MAGIC)
979 LeaveCriticalSection( &channel->cs );
980 return E_INVALIDARG;
983 if (!ctx) async_init( &async, &ctx_local );
984 hr = queue_close_channel( channel, ctx ? ctx : &ctx_local );
985 if (!ctx)
987 if (hr == WS_S_ASYNC) hr = async_wait( &async );
988 CloseHandle( async.done );
991 LeaveCriticalSection( &channel->cs );
992 TRACE( "returning %#lx\n", hr );
993 return hr;
996 static HRESULT parse_http_url( const WCHAR *url, ULONG len, URL_COMPONENTS *uc )
998 HRESULT hr = E_OUTOFMEMORY;
999 WCHAR *tmp;
1000 DWORD err;
1002 memset( uc, 0, sizeof(*uc) );
1003 uc->dwStructSize = sizeof(*uc);
1004 uc->dwHostNameLength = 128;
1005 uc->lpszHostName = malloc( uc->dwHostNameLength * sizeof(WCHAR) );
1006 uc->dwUrlPathLength = 128;
1007 uc->lpszUrlPath = malloc( uc->dwUrlPathLength * sizeof(WCHAR) );
1008 uc->dwExtraInfoLength = 128;
1009 uc->lpszExtraInfo = malloc( uc->dwExtraInfoLength * sizeof(WCHAR) );
1010 if (!uc->lpszHostName || !uc->lpszUrlPath || !uc->lpszExtraInfo) goto error;
1012 if (!WinHttpCrackUrl( url, len, ICU_DECODE, uc ))
1014 if ((err = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
1016 hr = HRESULT_FROM_WIN32( err );
1017 goto error;
1019 if (!(tmp = realloc( uc->lpszHostName, uc->dwHostNameLength * sizeof(WCHAR) ))) goto error;
1020 uc->lpszHostName = tmp;
1021 if (!(tmp = realloc( uc->lpszUrlPath, uc->dwUrlPathLength * sizeof(WCHAR) ))) goto error;
1022 uc->lpszUrlPath = tmp;
1023 if (!(tmp = realloc( uc->lpszExtraInfo, uc->dwExtraInfoLength * sizeof(WCHAR) ))) goto error;
1024 uc->lpszExtraInfo = tmp;
1025 WinHttpCrackUrl( url, len, ICU_DECODE, uc );
1028 return S_OK;
1030 error:
1031 free( uc->lpszHostName );
1032 free( uc->lpszUrlPath );
1033 free( uc->lpszExtraInfo );
1034 return hr;
1037 static HRESULT open_channel_http( struct channel *channel )
1039 HINTERNET ses = NULL, con = NULL;
1040 URL_COMPONENTS uc;
1041 HRESULT hr;
1043 if (channel->u.http.connect) return S_OK;
1045 if ((hr = parse_http_url( channel->addr.url.chars, channel->addr.url.length, &uc )) != S_OK) return hr;
1046 if (!(channel->u.http.path = malloc( (uc.dwUrlPathLength + uc.dwExtraInfoLength + 1) * sizeof(WCHAR) )))
1048 hr = E_OUTOFMEMORY;
1049 goto done;
1051 else
1053 lstrcpyW( channel->u.http.path, uc.lpszUrlPath );
1054 if (uc.dwExtraInfoLength) lstrcatW( channel->u.http.path, uc.lpszExtraInfo );
1057 channel->u.http.flags = WINHTTP_FLAG_REFRESH;
1058 switch (uc.nScheme)
1060 case INTERNET_SCHEME_HTTP: break;
1061 case INTERNET_SCHEME_HTTPS:
1062 channel->u.http.flags |= WINHTTP_FLAG_SECURE;
1063 break;
1065 default:
1066 hr = WS_E_INVALID_ENDPOINT_URL;
1067 goto done;
1070 if (!(ses = WinHttpOpen( L"MS-WebServices/1.0", 0, NULL, NULL, 0 )))
1072 hr = HRESULT_FROM_WIN32( GetLastError() );
1073 goto done;
1075 if (!(con = WinHttpConnect( ses, uc.lpszHostName, uc.nPort, 0 )))
1077 hr = HRESULT_FROM_WIN32( GetLastError() );
1078 goto done;
1081 channel->u.http.session = ses;
1082 channel->u.http.connect = con;
1084 done:
1085 if (hr != S_OK)
1087 WinHttpCloseHandle( con );
1088 WinHttpCloseHandle( ses );
1090 free( uc.lpszHostName );
1091 free( uc.lpszUrlPath );
1092 free( uc.lpszExtraInfo );
1093 return hr;
1096 static HRESULT open_channel_tcp( struct channel *channel )
1098 struct sockaddr_storage storage;
1099 struct sockaddr *addr = (struct sockaddr *)&storage;
1100 BOOL nodelay = FALSE;
1101 int addr_len;
1102 WS_URL_SCHEME_TYPE scheme;
1103 WCHAR *host;
1104 USHORT port;
1105 HRESULT hr;
1107 if (channel->u.tcp.socket != -1) return S_OK;
1109 if ((hr = parse_url( &channel->addr.url, &scheme, &host, &port )) != S_OK) return hr;
1110 if (scheme != WS_URL_NETTCP_SCHEME_TYPE)
1112 free( host );
1113 return WS_E_INVALID_ENDPOINT_URL;
1116 winsock_init();
1118 hr = resolve_hostname( host, port, addr, &addr_len, 0 );
1119 free( host );
1120 if (hr != S_OK) return hr;
1122 if ((channel->u.tcp.socket = socket( addr->sa_family, SOCK_STREAM, 0 )) == -1)
1123 return HRESULT_FROM_WIN32( WSAGetLastError() );
1125 if (connect( channel->u.tcp.socket, addr, addr_len ) < 0)
1127 closesocket( channel->u.tcp.socket );
1128 channel->u.tcp.socket = -1;
1129 return HRESULT_FROM_WIN32( WSAGetLastError() );
1132 prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_NO_DELAY, &nodelay, sizeof(nodelay) );
1133 setsockopt( channel->u.tcp.socket, IPPROTO_TCP, TCP_NODELAY, (const char *)&nodelay, sizeof(nodelay) );
1134 return S_OK;
1137 static HRESULT open_channel_udp( struct channel *channel )
1139 struct sockaddr_storage storage;
1140 struct sockaddr *addr = (struct sockaddr *)&storage;
1141 int addr_len;
1142 WS_URL_SCHEME_TYPE scheme;
1143 WCHAR *host;
1144 USHORT port;
1145 HRESULT hr;
1147 if (channel->u.udp.socket != -1) return S_OK;
1149 if ((hr = parse_url( &channel->addr.url, &scheme, &host, &port )) != S_OK) return hr;
1150 if (scheme != WS_URL_SOAPUDP_SCHEME_TYPE)
1152 free( host );
1153 return WS_E_INVALID_ENDPOINT_URL;
1156 winsock_init();
1158 hr = resolve_hostname( host, port, addr, &addr_len, 0 );
1159 free( host );
1160 if (hr != S_OK) return hr;
1162 if ((channel->u.udp.socket = socket( addr->sa_family, SOCK_DGRAM, 0 )) == -1)
1163 return HRESULT_FROM_WIN32( WSAGetLastError() );
1165 if (connect( channel->u.udp.socket, addr, addr_len ) < 0)
1167 closesocket( channel->u.udp.socket );
1168 channel->u.udp.socket = -1;
1169 return HRESULT_FROM_WIN32( WSAGetLastError() );
1172 return S_OK;
1175 static HRESULT open_channel( struct channel *channel, const WS_ENDPOINT_ADDRESS *endpoint )
1177 HRESULT hr;
1179 if (endpoint->headers || endpoint->extensions || endpoint->identity)
1181 FIXME( "headers, extensions or identity not supported\n" );
1182 return E_NOTIMPL;
1185 TRACE( "endpoint %s\n", debugstr_wn(endpoint->url.chars, endpoint->url.length) );
1187 if (!(channel->addr.url.chars = malloc( endpoint->url.length * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1188 memcpy( channel->addr.url.chars, endpoint->url.chars, endpoint->url.length * sizeof(WCHAR) );
1189 channel->addr.url.length = endpoint->url.length;
1191 switch (channel->binding)
1193 case WS_HTTP_CHANNEL_BINDING:
1194 hr = open_channel_http( channel );
1195 break;
1197 case WS_TCP_CHANNEL_BINDING:
1198 hr = open_channel_tcp( channel );
1199 break;
1201 case WS_UDP_CHANNEL_BINDING:
1202 hr = open_channel_udp( channel );
1203 break;
1205 default:
1206 ERR( "unhandled binding %u\n", channel->binding );
1207 return E_NOTIMPL;
1210 if (hr == S_OK) channel->state = WS_CHANNEL_STATE_OPEN;
1211 return hr;
1214 struct open_channel
1216 struct task task;
1217 struct channel *channel;
1218 const WS_ENDPOINT_ADDRESS *endpoint;
1219 WS_ASYNC_CONTEXT ctx;
1222 static void open_channel_proc( struct task *task )
1224 struct open_channel *o = (struct open_channel *)task;
1225 HRESULT hr;
1227 hr = open_channel( o->channel, o->endpoint );
1229 TRACE( "calling %p(%#lx)\n", o->ctx.callback, hr );
1230 o->ctx.callback( hr, WS_LONG_CALLBACK, o->ctx.callbackState );
1231 TRACE( "%p returned\n", o->ctx.callback );
1234 static HRESULT queue_open_channel( struct channel *channel, const WS_ENDPOINT_ADDRESS *endpoint,
1235 const WS_ASYNC_CONTEXT *ctx )
1237 struct open_channel *o;
1239 if (!(o = malloc( sizeof(*o) ))) return E_OUTOFMEMORY;
1240 o->task.proc = open_channel_proc;
1241 o->channel = channel;
1242 o->endpoint = endpoint;
1243 o->ctx = *ctx;
1244 return queue_task( &channel->send_q, &o->task );
1247 /**************************************************************************
1248 * WsOpenChannel [webservices.@]
1250 HRESULT WINAPI WsOpenChannel( WS_CHANNEL *handle, const WS_ENDPOINT_ADDRESS *endpoint, const WS_ASYNC_CONTEXT *ctx,
1251 WS_ERROR *error )
1253 struct channel *channel = (struct channel *)handle;
1254 WS_ASYNC_CONTEXT ctx_local;
1255 struct async async;
1256 HRESULT hr;
1258 TRACE( "%p %p %p %p\n", handle, endpoint, ctx, error );
1259 if (error) FIXME( "ignoring error parameter\n" );
1261 if (!channel || !endpoint) return E_INVALIDARG;
1263 EnterCriticalSection( &channel->cs );
1265 if (channel->magic != CHANNEL_MAGIC)
1267 LeaveCriticalSection( &channel->cs );
1268 return E_INVALIDARG;
1270 if ((hr = check_state( channel, WS_CHANNEL_STATE_CREATED )) != S_OK)
1272 LeaveCriticalSection( &channel->cs );
1273 return hr;
1276 if (!ctx) async_init( &async, &ctx_local );
1277 hr = queue_open_channel( channel, endpoint, ctx ? ctx : &ctx_local );
1278 if (!ctx)
1280 if (hr == WS_S_ASYNC) hr = async_wait( &async );
1281 CloseHandle( async.done );
1284 LeaveCriticalSection( &channel->cs );
1285 TRACE( "returning %#lx\n", hr );
1286 return hr;
1289 static HRESULT send_message_http( HINTERNET request, BYTE *data, ULONG len )
1291 if (!WinHttpSendRequest( request, NULL, 0, data, len, len, 0 ))
1292 return HRESULT_FROM_WIN32( GetLastError() );
1294 if (!WinHttpReceiveResponse( request, NULL ))
1295 return HRESULT_FROM_WIN32( GetLastError() );
1296 return S_OK;
1299 static ULONG get_max_buffer_size( struct channel *channel )
1301 ULONG size;
1302 prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE, &size, sizeof(size) );
1303 return size;
1306 static HRESULT write_bytes( struct channel *channel, BYTE *bytes, ULONG len )
1308 if (!channel->send_buf)
1310 channel->send_buflen = get_max_buffer_size( channel );
1311 if (!(channel->send_buf = malloc( channel->send_buflen ))) return E_OUTOFMEMORY;
1313 if (channel->send_size + len >= channel->send_buflen) return WS_E_QUOTA_EXCEEDED;
1315 memcpy( channel->send_buf + channel->send_size, bytes, len );
1316 channel->send_size += len;
1317 return S_OK;
1320 static inline HRESULT write_byte( struct channel *channel, BYTE byte )
1322 return write_bytes( channel, &byte, 1 );
1325 static HRESULT write_size( struct channel *channel, ULONG size )
1327 HRESULT hr;
1328 if (size < 0x80) return write_byte( channel, size );
1329 if ((hr = write_byte( channel, (size & 0x7f) | 0x80 )) != S_OK) return hr;
1330 if ((size >>= 7) < 0x80) return write_byte( channel, size );
1331 if ((hr = write_byte( channel, (size & 0x7f) | 0x80 )) != S_OK) return hr;
1332 if ((size >>= 7) < 0x80) return write_byte( channel, size );
1333 if ((hr = write_byte( channel, (size & 0x7f) | 0x80 )) != S_OK) return hr;
1334 if ((size >>= 7) < 0x80) return write_byte( channel, size );
1335 if ((hr = write_byte( channel, (size & 0x7f) | 0x80 )) != S_OK) return hr;
1336 if ((size >>= 7) < 0x08) return write_byte( channel, size );
1337 return E_INVALIDARG;
1340 static inline ULONG size_length( ULONG size )
1342 if (size < 0x80) return 1;
1343 if (size < 0x4000) return 2;
1344 if (size < 0x200000) return 3;
1345 if (size < 0x10000000) return 4;
1346 return 5;
1349 static ULONG string_table_size( const struct dictionary *dict )
1351 ULONG i, size = 0;
1352 for (i = 0; i < dict->dict.stringCount; i++)
1354 if (dict->sequence[i] == dict->current_sequence)
1355 size += size_length( dict->dict.strings[i].length ) + dict->dict.strings[i].length;
1357 return size;
1360 static HRESULT write_string_table( struct channel *channel, const struct dictionary *dict )
1362 ULONG i;
1363 HRESULT hr;
1364 for (i = 0; i < dict->dict.stringCount; i++)
1366 if (dict->sequence[i] != dict->current_sequence) continue;
1367 if ((hr = write_size( channel, dict->dict.strings[i].length )) != S_OK) return hr;
1368 if ((hr = write_bytes( channel, dict->dict.strings[i].bytes, dict->dict.strings[i].length )) != S_OK) return hr;
1370 return S_OK;
1373 static HRESULT string_to_utf8( const WS_STRING *str, unsigned char **ret, int *len )
1375 *len = WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, NULL, 0, NULL, NULL );
1376 if (!(*ret = malloc( *len ))) return E_OUTOFMEMORY;
1377 WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, (char *)*ret, *len, NULL, NULL );
1378 return S_OK;
1381 enum session_mode
1383 SESSION_MODE_INVALID = 0,
1384 SESSION_MODE_SINGLETON = 1,
1385 SESSION_MODE_DUPLEX = 2,
1386 SESSION_MODE_SIMPLEX = 3,
1389 static enum session_mode map_channel_type( struct channel *channel )
1391 switch (channel->type)
1393 case WS_CHANNEL_TYPE_DUPLEX_SESSION: return SESSION_MODE_DUPLEX;
1394 default:
1395 FIXME( "unhandled channel type %#x\n", channel->type );
1396 return SESSION_MODE_INVALID;
1400 enum known_encoding
1402 KNOWN_ENCODING_SOAP11_UTF8 = 0x00,
1403 KNOWN_ENCODING_SOAP11_UTF16 = 0x01,
1404 KNOWN_ENCODING_SOAP11_UTF16LE = 0x02,
1405 KNOWN_ENCODING_SOAP12_UTF8 = 0x03,
1406 KNOWN_ENCODING_SOAP12_UTF16 = 0x04,
1407 KNOWN_ENCODING_SOAP12_UTF16LE = 0x05,
1408 KNOWN_ENCODING_SOAP12_MTOM = 0x06,
1409 KNOWN_ENCODING_SOAP12_BINARY = 0x07,
1410 KNOWN_ENCODING_SOAP12_BINARY_SESSION = 0x08,
1413 static enum known_encoding map_channel_encoding( struct channel *channel )
1415 WS_ENVELOPE_VERSION version;
1417 prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION, &version, sizeof(version) );
1419 switch (version)
1421 case WS_ENVELOPE_VERSION_SOAP_1_1:
1422 switch (channel->encoding)
1424 case WS_ENCODING_XML_UTF8: return KNOWN_ENCODING_SOAP11_UTF8;
1425 case WS_ENCODING_XML_UTF16LE: return KNOWN_ENCODING_SOAP11_UTF16LE;
1426 default:
1427 FIXME( "unhandled version/encoding %u/%u\n", version, channel->encoding );
1428 return 0;
1430 case WS_ENVELOPE_VERSION_SOAP_1_2:
1431 switch (channel->encoding)
1433 case WS_ENCODING_XML_UTF8: return KNOWN_ENCODING_SOAP12_UTF8;
1434 case WS_ENCODING_XML_UTF16LE: return KNOWN_ENCODING_SOAP12_UTF16LE;
1435 case WS_ENCODING_XML_BINARY_1: return KNOWN_ENCODING_SOAP12_BINARY;
1436 case WS_ENCODING_XML_BINARY_SESSION_1: return KNOWN_ENCODING_SOAP12_BINARY_SESSION;
1437 default:
1438 FIXME( "unhandled version/encoding %u/%u\n", version, channel->encoding );
1439 return 0;
1441 default:
1442 ERR( "unhandled version %u\n", version );
1443 return 0;
1447 #define FRAME_VERSION_MAJOR 1
1448 #define FRAME_VERSION_MINOR 0
1450 static HRESULT write_preamble( struct channel *channel )
1452 unsigned char *url;
1453 HRESULT hr;
1454 int len;
1456 if ((hr = write_byte( channel, FRAME_RECORD_TYPE_VERSION )) != S_OK) return hr;
1457 if ((hr = write_byte( channel, FRAME_VERSION_MAJOR )) != S_OK) return hr;
1458 if ((hr = write_byte( channel, FRAME_VERSION_MINOR )) != S_OK) return hr;
1460 if ((hr = write_byte( channel, FRAME_RECORD_TYPE_MODE )) != S_OK) return hr;
1461 if ((hr = write_byte( channel, map_channel_type(channel) )) != S_OK) return hr;
1463 if ((hr = write_byte( channel, FRAME_RECORD_TYPE_VIA )) != S_OK) return hr;
1464 if ((hr = string_to_utf8( &channel->addr.url, &url, &len )) != S_OK) return hr;
1465 if ((hr = write_size( channel, len )) != S_OK) goto done;
1466 if ((hr = write_bytes( channel, url, len )) != S_OK) goto done;
1468 if ((hr = write_byte( channel, FRAME_RECORD_TYPE_KNOWN_ENCODING )) != S_OK) goto done;
1469 if ((hr = write_byte( channel, map_channel_encoding(channel) )) != S_OK) goto done;
1470 hr = write_byte( channel, FRAME_RECORD_TYPE_PREAMBLE_END );
1472 done:
1473 free( url );
1474 return hr;
1477 static HRESULT send_bytes( SOCKET socket, char *bytes, int len )
1479 int count = send( socket, bytes, len, 0 );
1480 if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
1481 if (count != len) return WS_E_OTHER;
1482 return S_OK;
1485 static HRESULT send_preamble( struct channel *channel )
1487 HRESULT hr;
1488 if ((hr = write_preamble( channel )) != S_OK) return hr;
1489 if ((hr = send_bytes( channel->u.tcp.socket, channel->send_buf, channel->send_size )) != S_OK) return hr;
1490 channel->send_size = 0;
1491 return S_OK;
1494 static HRESULT receive_bytes( struct channel *channel, unsigned char *bytes, int len )
1496 int count = recv( channel->u.tcp.socket, (char *)bytes, len, 0 );
1497 if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
1498 if (count != len) return WS_E_INVALID_FORMAT;
1499 return S_OK;
1502 static HRESULT receive_preamble_ack( struct channel *channel )
1504 unsigned char byte;
1505 HRESULT hr;
1507 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
1508 if (byte != FRAME_RECORD_TYPE_PREAMBLE_ACK) return WS_E_INVALID_FORMAT;
1509 channel->session_state = SESSION_STATE_SETUP_COMPLETE;
1510 return S_OK;
1513 static HRESULT write_sized_envelope( struct channel *channel, BYTE *data, ULONG len )
1515 ULONG table_size = string_table_size( &channel->dict_send );
1516 HRESULT hr;
1518 if ((hr = write_byte( channel, FRAME_RECORD_TYPE_SIZED_ENVELOPE )) != S_OK) return hr;
1519 if ((hr = write_size( channel, size_length(table_size) + table_size + len )) != S_OK) return hr;
1520 if ((hr = write_size( channel, table_size )) != S_OK) return hr;
1521 if ((hr = write_string_table( channel, &channel->dict_send )) != S_OK) return hr;
1522 return write_bytes( channel, data, len );
1525 static HRESULT send_sized_envelope( struct channel *channel, BYTE *data, ULONG len )
1527 HRESULT hr;
1528 if ((hr = write_sized_envelope( channel, data, len )) != S_OK) return hr;
1529 if ((hr = send_bytes( channel->u.tcp.socket, channel->send_buf, channel->send_size )) != S_OK) return hr;
1530 channel->send_size = 0;
1531 return S_OK;
1534 static HRESULT open_http_request( struct channel *channel, HINTERNET *req )
1536 if ((*req = WinHttpOpenRequest( channel->u.http.connect, L"POST", channel->u.http.path,
1537 NULL, NULL, NULL, channel->u.http.flags ))) return S_OK;
1538 return HRESULT_FROM_WIN32( GetLastError() );
1541 static HRESULT send_message_bytes( struct channel *channel, WS_MESSAGE *msg )
1543 WS_XML_WRITER *writer;
1544 WS_BYTES buf;
1545 HRESULT hr;
1547 channel->msg = msg;
1548 WsGetMessageProperty( channel->msg, WS_MESSAGE_PROPERTY_BODY_WRITER, &writer, sizeof(writer), NULL );
1549 WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &buf, sizeof(buf), NULL );
1551 switch (channel->binding)
1553 case WS_HTTP_CHANNEL_BINDING:
1554 if (channel->u.http.request)
1556 WinHttpCloseHandle( channel->u.http.request );
1557 channel->u.http.request = NULL;
1559 if ((hr = open_http_request( channel, &channel->u.http.request )) != S_OK) return hr;
1560 if ((hr = message_insert_http_headers( msg, channel->u.http.request )) != S_OK) return hr;
1561 return send_message_http( channel->u.http.request, buf.bytes, buf.length );
1563 case WS_TCP_CHANNEL_BINDING:
1564 if (channel->type & WS_CHANNEL_TYPE_SESSION)
1566 switch (channel->session_state)
1568 case SESSION_STATE_UNINITIALIZED:
1569 if ((hr = send_preamble( channel )) != S_OK) return hr;
1570 if ((hr = receive_preamble_ack( channel )) != S_OK) return hr;
1571 /* fall through */
1573 case SESSION_STATE_SETUP_COMPLETE:
1574 return send_sized_envelope( channel, buf.bytes, buf.length );
1576 default:
1577 ERR( "unhandled session state %u\n", channel->session_state );
1578 return WS_E_OTHER;
1581 /* fall through */
1583 case WS_UDP_CHANNEL_BINDING:
1584 return WsFlushWriter( writer, 0, NULL, NULL );
1586 default:
1587 ERR( "unhandled binding %u\n", channel->binding );
1588 return E_NOTIMPL;
1592 HRESULT channel_send_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
1594 struct channel *channel = (struct channel *)handle;
1595 HRESULT hr;
1597 EnterCriticalSection( &channel->cs );
1599 if (channel->magic != CHANNEL_MAGIC)
1601 LeaveCriticalSection( &channel->cs );
1602 return E_INVALIDARG;
1604 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
1606 LeaveCriticalSection( &channel->cs );
1607 return hr;
1610 hr = send_message_bytes( channel, msg );
1611 if (hr != S_OK) channel->state = WS_CHANNEL_STATE_FAULTED;
1613 LeaveCriticalSection( &channel->cs );
1614 return hr;
1617 static HRESULT CALLBACK dict_cb( void *state, const WS_XML_STRING *str, BOOL *found, ULONG *id, WS_ERROR *error )
1619 struct dictionary *dict = state;
1620 HRESULT hr = S_OK;
1621 BYTE *bytes;
1622 int index;
1624 if ((index = find_string( dict, str->bytes, str->length, id )) == -1)
1626 *found = TRUE;
1627 return S_OK;
1630 if (str->length + dict->str_bytes + 1 > dict->str_bytes_max)
1632 WARN( "max string bytes exceeded\n" );
1633 *found = FALSE;
1634 return hr;
1637 if (!(bytes = malloc( str->length ))) return E_OUTOFMEMORY;
1638 memcpy( bytes, str->bytes, str->length );
1639 if ((hr = insert_string( dict, bytes, str->length, index, id )) == S_OK)
1641 *found = TRUE;
1642 return S_OK;
1644 free( bytes );
1646 *found = FALSE;
1647 return hr;
1650 static CALLBACK HRESULT write_callback( void *state, const WS_BYTES *buf, ULONG count, const WS_ASYNC_CONTEXT *ctx,
1651 WS_ERROR *error )
1653 SOCKET socket = *(SOCKET *)state;
1654 if (send( socket, (const char *)buf->bytes, buf->length, 0 ) < 0)
1656 TRACE( "send failed %u\n", WSAGetLastError() );
1658 return S_OK;
1661 static HRESULT init_writer( struct channel *channel )
1663 WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
1664 WS_XML_WRITER_STREAM_OUTPUT stream = {{WS_XML_WRITER_OUTPUT_TYPE_STREAM}};
1665 WS_XML_WRITER_TEXT_ENCODING text = {{WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8};
1666 WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
1667 const WS_XML_WRITER_ENCODING *encoding;
1668 const WS_XML_WRITER_OUTPUT *output;
1669 WS_XML_WRITER_PROPERTY prop;
1670 ULONG max_size = (1 << 17);
1671 HRESULT hr;
1673 prop.id = WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE;
1674 prop.value = &max_size;
1675 prop.valueSize = sizeof(max_size);
1676 if (!channel->writer && (hr = WsCreateWriter( &prop, 1, &channel->writer, NULL )) != S_OK) return hr;
1678 switch (channel->encoding)
1680 case WS_ENCODING_XML_UTF8:
1681 encoding = &text.encoding;
1682 if (channel->binding == WS_UDP_CHANNEL_BINDING ||
1683 (channel->binding == WS_TCP_CHANNEL_BINDING && !(channel->type & WS_CHANNEL_TYPE_SESSION)))
1685 stream.writeCallback = write_callback;
1686 stream.writeCallbackState = (channel->binding == WS_UDP_CHANNEL_BINDING) ?
1687 &channel->u.udp.socket : &channel->u.tcp.socket;
1688 output = &stream.output;
1690 else output = &buf.output;
1691 break;
1693 case WS_ENCODING_XML_BINARY_SESSION_1:
1694 bin.staticDictionary = (WS_XML_DICTIONARY *)&dict_builtin_static.dict;
1695 /* fall through */
1697 case WS_ENCODING_XML_BINARY_1:
1698 encoding = &bin.encoding;
1699 output = &buf.output;
1700 break;
1702 default:
1703 FIXME( "unhandled encoding %u\n", channel->encoding );
1704 return WS_E_NOT_SUPPORTED;
1707 return WsSetOutput( channel->writer, encoding, output, NULL, 0, NULL );
1710 static HRESULT write_message( struct channel *channel, WS_MESSAGE *msg, const WS_ELEMENT_DESCRIPTION *desc,
1711 WS_WRITE_OPTION option, const void *body, ULONG size )
1713 HRESULT hr;
1714 if ((hr = writer_set_lookup( channel->writer, TRUE )) != S_OK) return hr;
1715 if ((hr = WsWriteEnvelopeStart( msg, channel->writer, NULL, NULL, NULL )) != S_OK) return hr;
1716 if ((hr = writer_set_lookup( channel->writer, FALSE )) != S_OK) return hr;
1717 channel->dict_send.current_sequence++;
1718 if ((hr = writer_set_dict_callback( channel->writer, dict_cb, &channel->dict_send )) != S_OK) return hr;
1719 if ((hr = WsWriteBody( msg, desc, option, body, size, NULL )) != S_OK) return hr;
1720 return WsWriteEnvelopeEnd( msg, NULL );
1723 static HRESULT send_message( struct channel *channel, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION *desc,
1724 WS_WRITE_OPTION option, const void *body, ULONG size )
1726 HRESULT hr;
1727 if ((hr = WsAddressMessage( msg, &channel->addr, NULL )) != S_OK) goto done;
1728 if ((hr = message_set_action( msg, desc->action )) != S_OK) goto done;
1729 if ((hr = init_writer( channel )) != S_OK) goto done;
1730 if ((hr = write_message( channel, msg, desc->bodyElementDescription, option, body, size )) != S_OK) goto done;
1731 hr = send_message_bytes( channel, msg );
1733 done:
1734 if (hr != S_OK) channel->state = WS_CHANNEL_STATE_FAULTED;
1735 return hr;
1738 struct send_message
1740 struct task task;
1741 struct channel *channel;
1742 WS_MESSAGE *msg;
1743 const WS_MESSAGE_DESCRIPTION *desc;
1744 WS_WRITE_OPTION option;
1745 const void *body;
1746 ULONG size;
1747 WS_ASYNC_CONTEXT ctx;
1750 static void send_message_proc( struct task *task )
1752 struct send_message *s = (struct send_message *)task;
1753 HRESULT hr;
1755 hr = send_message( s->channel, s->msg, s->desc, s->option, s->body, s->size );
1757 TRACE( "calling %p(%#lx)\n", s->ctx.callback, hr );
1758 s->ctx.callback( hr, WS_LONG_CALLBACK, s->ctx.callbackState );
1759 TRACE( "%p returned\n", s->ctx.callback );
1762 static HRESULT queue_send_message( struct channel *channel, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION *desc,
1763 WS_WRITE_OPTION option, const void *body, ULONG size, const WS_ASYNC_CONTEXT *ctx )
1765 struct send_message *s;
1767 if (!(s = malloc( sizeof(*s) ))) return E_OUTOFMEMORY;
1768 s->task.proc = send_message_proc;
1769 s->channel = channel;
1770 s->msg = msg;
1771 s->desc = desc;
1772 s->option = option;
1773 s->body = body;
1774 s->size = size;
1775 s->ctx = *ctx;
1776 return queue_task( &channel->send_q, &s->task );
1779 /**************************************************************************
1780 * WsSendMessage [webservices.@]
1782 HRESULT WINAPI WsSendMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION *desc,
1783 WS_WRITE_OPTION option, const void *body, ULONG size, const WS_ASYNC_CONTEXT *ctx,
1784 WS_ERROR *error )
1786 struct channel *channel = (struct channel *)handle;
1787 WS_ASYNC_CONTEXT ctx_local;
1788 struct async async;
1789 HRESULT hr;
1791 TRACE( "%p %p %p %u %p %lu %p %p\n", handle, msg, desc, option, body, size, ctx, error );
1792 if (error) FIXME( "ignoring error parameter\n" );
1794 if (!channel || !msg || !desc) return E_INVALIDARG;
1796 EnterCriticalSection( &channel->cs );
1798 if (channel->magic != CHANNEL_MAGIC)
1800 LeaveCriticalSection( &channel->cs );
1801 return E_INVALIDARG;
1803 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
1805 LeaveCriticalSection( &channel->cs );
1806 return hr;
1809 WsInitializeMessage( msg, WS_BLANK_MESSAGE, NULL, NULL );
1811 if (!ctx) async_init( &async, &ctx_local );
1812 hr = queue_send_message( channel, msg, desc, option, body, size, ctx ? ctx : &ctx_local );
1813 if (!ctx)
1815 if (hr == WS_S_ASYNC) hr = async_wait( &async );
1816 CloseHandle( async.done );
1819 LeaveCriticalSection( &channel->cs );
1820 TRACE( "returning %#lx\n", hr );
1821 return hr;
1824 /**************************************************************************
1825 * WsSendReplyMessage [webservices.@]
1827 HRESULT WINAPI WsSendReplyMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION *desc,
1828 WS_WRITE_OPTION option, const void *body, ULONG size, WS_MESSAGE *request,
1829 const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
1831 struct channel *channel = (struct channel *)handle;
1832 WS_ASYNC_CONTEXT ctx_local;
1833 struct async async;
1834 GUID id;
1835 HRESULT hr;
1837 TRACE( "%p %p %p %u %p %lu %p %p %p\n", handle, msg, desc, option, body, size, request, ctx, error );
1838 if (error) FIXME( "ignoring error parameter\n" );
1840 if (!channel || !msg || !desc || !request) return E_INVALIDARG;
1842 EnterCriticalSection( &channel->cs );
1844 if (channel->magic != CHANNEL_MAGIC)
1846 LeaveCriticalSection( &channel->cs );
1847 return E_INVALIDARG;
1849 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
1851 LeaveCriticalSection( &channel->cs );
1852 return hr;
1855 WsInitializeMessage( msg, WS_REPLY_MESSAGE, NULL, NULL );
1856 if ((hr = message_get_id( request, &id )) != S_OK) goto done;
1857 if ((hr = message_set_request_id( msg, &id )) != S_OK) goto done;
1859 if (!ctx) async_init( &async, &ctx_local );
1860 hr = queue_send_message( channel, msg, desc, option, body, size, ctx ? ctx : &ctx_local );
1861 if (!ctx)
1863 if (hr == WS_S_ASYNC) hr = async_wait( &async );
1864 CloseHandle( async.done );
1867 done:
1868 LeaveCriticalSection( &channel->cs );
1869 TRACE( "returning %#lx\n", hr );
1870 return hr;
1873 static HRESULT resize_read_buffer( struct channel *channel, ULONG size )
1875 if (!channel->read_buf)
1877 if (!(channel->read_buf = malloc( size ))) return E_OUTOFMEMORY;
1878 channel->read_buflen = size;
1879 return S_OK;
1881 if (channel->read_buflen < size)
1883 char *tmp;
1884 ULONG new_size = max( size, channel->read_buflen * 2 );
1885 if (!(tmp = realloc( channel->read_buf, new_size ))) return E_OUTOFMEMORY;
1886 channel->read_buf = tmp;
1887 channel->read_buflen = new_size;
1889 return S_OK;
1892 static CALLBACK HRESULT read_callback( void *state, void *buf, ULONG buflen, ULONG *retlen,
1893 const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
1895 SOCKET socket = *(SOCKET *)state;
1896 int ret;
1898 if ((ret = recv( socket, buf, buflen, 0 )) >= 0) *retlen = ret;
1899 else
1901 TRACE( "recv failed %u\n", WSAGetLastError() );
1902 *retlen = 0;
1904 return S_OK;
1907 static HRESULT init_reader( struct channel *channel )
1909 WS_XML_READER_BUFFER_INPUT buf = {{WS_XML_READER_INPUT_TYPE_BUFFER}};
1910 WS_XML_READER_STREAM_INPUT stream = {{WS_XML_READER_INPUT_TYPE_STREAM}};
1911 WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}};
1912 WS_XML_READER_BINARY_ENCODING bin = {{WS_XML_READER_ENCODING_TYPE_BINARY}};
1913 const WS_XML_READER_ENCODING *encoding;
1914 const WS_XML_READER_INPUT *input;
1915 HRESULT hr;
1917 if (!channel->reader && (hr = WsCreateReader( NULL, 0, &channel->reader, NULL )) != S_OK) return hr;
1919 switch (channel->encoding)
1921 case WS_ENCODING_XML_UTF8:
1922 text.charSet = WS_CHARSET_UTF8;
1923 encoding = &text.encoding;
1925 if (channel->binding == WS_UDP_CHANNEL_BINDING ||
1926 (channel->binding == WS_TCP_CHANNEL_BINDING && !(channel->type & WS_CHANNEL_TYPE_SESSION)))
1928 stream.readCallback = read_callback;
1929 stream.readCallbackState = (channel->binding == WS_UDP_CHANNEL_BINDING) ?
1930 &channel->u.udp.socket : &channel->u.tcp.socket;
1931 input = &stream.input;
1933 else
1935 buf.encodedData = channel->read_buf;
1936 buf.encodedDataSize = channel->read_size;
1937 input = &buf.input;
1939 break;
1941 case WS_ENCODING_XML_BINARY_SESSION_1:
1942 bin.staticDictionary = (WS_XML_DICTIONARY *)&dict_builtin_static.dict;
1943 bin.dynamicDictionary = &channel->dict_recv.dict;
1944 /* fall through */
1946 case WS_ENCODING_XML_BINARY_1:
1947 encoding = &bin.encoding;
1949 buf.encodedData = channel->read_buf;
1950 buf.encodedDataSize = channel->read_size;
1951 input = &buf.input;
1952 break;
1954 default:
1955 FIXME( "unhandled encoding %u\n", channel->encoding );
1956 return WS_E_NOT_SUPPORTED;
1959 return WsSetInput( channel->reader, encoding, input, NULL, 0, NULL );
1962 static const WS_HTTP_MESSAGE_MAPPING *get_http_message_mapping( struct channel *channel )
1964 const struct prop *prop = &channel->prop[WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING];
1965 return (const WS_HTTP_MESSAGE_MAPPING *)prop->value;
1968 static HRESULT map_http_response_headers( struct channel *channel, WS_MESSAGE *msg )
1970 const WS_HTTP_MESSAGE_MAPPING *mapping = get_http_message_mapping( channel );
1971 return message_map_http_response_headers( msg, channel->u.http.request, mapping );
1974 #define INITIAL_READ_BUFFER_SIZE 4096
1975 static HRESULT receive_message_bytes_http( struct channel *channel, WS_MESSAGE *msg )
1977 DWORD len, bytes_read, offset = 0, size = INITIAL_READ_BUFFER_SIZE;
1978 ULONG max_len = get_max_buffer_size( channel );
1979 HRESULT hr;
1981 if ((hr = map_http_response_headers( channel, msg )) != S_OK) return hr;
1983 if ((hr = resize_read_buffer( channel, size )) != S_OK) return hr;
1984 channel->read_size = 0;
1985 for (;;)
1987 if (!WinHttpQueryDataAvailable( channel->u.http.request, &len ))
1989 return HRESULT_FROM_WIN32( GetLastError() );
1991 if (!len) break;
1992 if (channel->read_size + len > max_len) return WS_E_QUOTA_EXCEEDED;
1993 if ((hr = resize_read_buffer( channel, channel->read_size + len )) != S_OK) return hr;
1995 if (!WinHttpReadData( channel->u.http.request, channel->read_buf + offset, len, &bytes_read ))
1997 return HRESULT_FROM_WIN32( GetLastError() );
1999 if (!bytes_read) break;
2000 channel->read_size += bytes_read;
2001 offset += bytes_read;
2004 return S_OK;
2007 static HRESULT receive_message_sized( struct channel *channel, unsigned int size )
2009 unsigned int offset = 0, to_read = size;
2010 int bytes_read;
2011 HRESULT hr;
2013 if ((hr = resize_read_buffer( channel, size )) != S_OK) return hr;
2015 channel->read_size = 0;
2016 while (channel->read_size < size)
2018 if ((bytes_read = recv( channel->u.tcp.socket, channel->read_buf + offset, to_read, 0 )) < 0)
2020 return HRESULT_FROM_WIN32( WSAGetLastError() );
2022 if (!bytes_read) break;
2023 channel->read_size += bytes_read;
2024 to_read -= bytes_read;
2025 offset += bytes_read;
2027 if (channel->read_size != size) return WS_E_INVALID_FORMAT;
2028 return S_OK;
2031 static HRESULT receive_size( struct channel *channel, unsigned int *size )
2033 unsigned char byte;
2034 HRESULT hr;
2036 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
2037 *size = byte & 0x7f;
2038 if (!(byte & 0x80)) return S_OK;
2040 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
2041 *size += (byte & 0x7f) << 7;
2042 if (!(byte & 0x80)) return S_OK;
2044 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
2045 *size += (byte & 0x7f) << 14;
2046 if (!(byte & 0x80)) return S_OK;
2048 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
2049 *size += (byte & 0x7f) << 21;
2050 if (!(byte & 0x80)) return S_OK;
2052 if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
2053 if (byte & ~0x0f) return WS_E_INVALID_FORMAT;
2054 *size += byte << 28;
2055 return S_OK;
2058 static WS_ENCODING map_known_encoding( enum known_encoding encoding )
2060 switch (encoding)
2062 case KNOWN_ENCODING_SOAP11_UTF8:
2063 case KNOWN_ENCODING_SOAP12_UTF8: return WS_ENCODING_XML_UTF8;
2064 case KNOWN_ENCODING_SOAP11_UTF16:
2065 case KNOWN_ENCODING_SOAP12_UTF16: return WS_ENCODING_XML_UTF16BE;
2066 case KNOWN_ENCODING_SOAP11_UTF16LE:
2067 case KNOWN_ENCODING_SOAP12_UTF16LE: return WS_ENCODING_XML_UTF16LE;
2068 case KNOWN_ENCODING_SOAP12_BINARY: return WS_ENCODING_XML_BINARY_1;
2069 case KNOWN_ENCODING_SOAP12_BINARY_SESSION: return WS_ENCODING_XML_BINARY_SESSION_1;
2070 default:
2071 WARN( "unhandled encoding %u, assuming UTF8\n", encoding );
2072 return WS_ENCODING_XML_UTF8;
2076 static HRESULT receive_preamble( struct channel *channel )
2078 unsigned char type;
2079 HRESULT hr;
2081 for (;;)
2083 if ((hr = receive_bytes( channel, &type, 1 )) != S_OK) return hr;
2084 if (type == FRAME_RECORD_TYPE_PREAMBLE_END) break;
2085 switch (type)
2087 case FRAME_RECORD_TYPE_VERSION:
2089 unsigned char major, minor;
2090 if ((hr = receive_bytes( channel, &major, 1 )) != S_OK) return hr;
2091 if ((hr = receive_bytes( channel, &minor, 1 )) != S_OK) return hr;
2092 TRACE( "major %u minor %u\n", major, major );
2093 break;
2095 case FRAME_RECORD_TYPE_MODE:
2097 unsigned char mode;
2098 if ((hr = receive_bytes( channel, &mode, 1 )) != S_OK) return hr;
2099 TRACE( "mode %u\n", mode );
2100 break;
2102 case FRAME_RECORD_TYPE_VIA:
2104 unsigned int size;
2105 unsigned char *url;
2107 if ((hr = receive_size( channel, &size )) != S_OK) return hr;
2108 if (!(url = malloc( size ))) return E_OUTOFMEMORY;
2109 if ((hr = receive_bytes( channel, url, size )) != S_OK)
2111 free( url );
2112 return hr;
2114 TRACE( "transport URL %s\n", debugstr_an((char *)url, size) );
2115 free( url ); /* FIXME: verify */
2116 break;
2118 case FRAME_RECORD_TYPE_KNOWN_ENCODING:
2120 unsigned char encoding;
2121 if ((hr = receive_bytes( channel, &encoding, 1 )) != S_OK) return hr;
2122 TRACE( "encoding %u\n", encoding );
2123 channel->encoding = map_known_encoding( encoding );
2124 break;
2126 default:
2127 WARN( "unhandled record type %u\n", type );
2128 return WS_E_INVALID_FORMAT;
2132 return S_OK;
2135 static HRESULT receive_sized_envelope( struct channel *channel )
2137 unsigned char type;
2138 unsigned int size;
2139 HRESULT hr;
2141 if ((hr = receive_bytes( channel, &type, 1 )) != S_OK) return hr;
2142 if (type == FRAME_RECORD_TYPE_END) return WS_S_END;
2143 if (type != FRAME_RECORD_TYPE_SIZED_ENVELOPE) return WS_E_INVALID_FORMAT;
2144 if ((hr = receive_size( channel, &size )) != S_OK) return hr;
2145 if ((hr = receive_message_sized( channel, size )) != S_OK) return hr;
2146 return S_OK;
2149 static HRESULT read_size( const BYTE **ptr, ULONG len, ULONG *size )
2151 const BYTE *buf = *ptr;
2153 if (len < 1) return WS_E_INVALID_FORMAT;
2154 *size = buf[0] & 0x7f;
2155 if (!(buf[0] & 0x80))
2157 *ptr += 1;
2158 return S_OK;
2160 if (len < 2) return WS_E_INVALID_FORMAT;
2161 *size += (buf[1] & 0x7f) << 7;
2162 if (!(buf[1] & 0x80))
2164 *ptr += 2;
2165 return S_OK;
2167 if (len < 3) return WS_E_INVALID_FORMAT;
2168 *size += (buf[2] & 0x7f) << 14;
2169 if (!(buf[2] & 0x80))
2171 *ptr += 3;
2172 return S_OK;
2174 if (len < 4) return WS_E_INVALID_FORMAT;
2175 *size += (buf[3] & 0x7f) << 21;
2176 if (!(buf[3] & 0x80))
2178 *ptr += 4;
2179 return S_OK;
2181 if (len < 5 || (buf[4] & ~0x07)) return WS_E_INVALID_FORMAT;
2182 *size += buf[4] << 28;
2183 *ptr += 5;
2184 return S_OK;
2187 static HRESULT build_dict( const BYTE *buf, ULONG buflen, struct dictionary *dict, ULONG *used )
2189 ULONG size, strings_size, strings_offset;
2190 const BYTE *ptr = buf;
2191 BYTE *bytes;
2192 int index;
2193 HRESULT hr;
2195 if ((hr = read_size( &ptr, buflen, &strings_size )) != S_OK) return hr;
2196 strings_offset = ptr - buf;
2197 if (buflen < strings_offset + strings_size) return WS_E_INVALID_FORMAT;
2198 *used = strings_offset + strings_size;
2199 if (!strings_size) return S_OK;
2201 UuidCreate( &dict->dict.guid );
2202 dict->dict.isConst = FALSE;
2204 buflen -= strings_offset;
2205 ptr = buf + strings_offset;
2206 while (ptr < buf + strings_size)
2208 if ((hr = read_size( &ptr, buflen, &size )) != S_OK)
2210 init_dict( dict, 0 );
2211 return hr;
2213 if (size > buflen)
2215 init_dict( dict, 0 );
2216 return WS_E_INVALID_FORMAT;
2218 if (size + dict->str_bytes + 1 > dict->str_bytes_max)
2220 hr = WS_E_QUOTA_EXCEEDED;
2221 goto error;
2223 buflen -= size;
2224 if (!(bytes = malloc( size )))
2226 hr = E_OUTOFMEMORY;
2227 goto error;
2229 memcpy( bytes, ptr, size );
2230 if ((index = find_string( dict, bytes, size, NULL )) == -1) /* duplicate */
2232 free( bytes );
2233 ptr += size;
2234 continue;
2236 if ((hr = insert_string( dict, bytes, size, index, NULL )) != S_OK)
2238 free( bytes );
2239 init_dict( dict, 0 );
2240 return hr;
2242 ptr += size;
2244 return S_OK;
2246 error:
2247 init_dict( dict, 0 );
2248 return hr;
2251 static HRESULT send_preamble_ack( struct channel *channel )
2253 HRESULT hr;
2254 if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_PREAMBLE_ACK )) != S_OK) return hr;
2255 channel->session_state = SESSION_STATE_SETUP_COMPLETE;
2256 return S_OK;
2259 static HRESULT receive_message_bytes_session( struct channel *channel )
2261 HRESULT hr;
2263 if ((hr = receive_sized_envelope( channel )) != S_OK) return hr;
2264 if (channel->encoding == WS_ENCODING_XML_BINARY_SESSION_1)
2266 ULONG size;
2267 if ((hr = build_dict( (const BYTE *)channel->read_buf, channel->read_size, &channel->dict_recv,
2268 &size )) != S_OK) return hr;
2269 channel->read_size -= size;
2270 memmove( channel->read_buf, channel->read_buf + size, channel->read_size );
2273 return S_OK;
2276 static HRESULT receive_message_bytes( struct channel *channel, WS_MESSAGE *msg )
2278 switch (channel->binding)
2280 case WS_HTTP_CHANNEL_BINDING:
2281 return receive_message_bytes_http( channel, msg );
2283 case WS_TCP_CHANNEL_BINDING:
2284 if (channel->type & WS_CHANNEL_TYPE_SESSION)
2286 HRESULT hr;
2287 switch (channel->session_state)
2289 case SESSION_STATE_UNINITIALIZED:
2290 if ((hr = receive_preamble( channel )) != S_OK) return hr;
2291 if ((hr = send_preamble_ack( channel )) != S_OK) return hr;
2292 /* fall through */
2294 case SESSION_STATE_SETUP_COMPLETE:
2295 return receive_message_bytes_session( channel );
2297 default:
2298 ERR( "unhandled session state %u\n", channel->session_state );
2299 return WS_E_OTHER;
2302 return S_OK; /* nothing to do, data is read through stream callback */
2304 case WS_UDP_CHANNEL_BINDING:
2305 return S_OK;
2307 default:
2308 ERR( "unhandled binding %u\n", channel->binding );
2309 return E_NOTIMPL;
2313 HRESULT channel_receive_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
2315 struct channel *channel = (struct channel *)handle;
2316 HRESULT hr;
2318 EnterCriticalSection( &channel->cs );
2320 if (channel->magic != CHANNEL_MAGIC)
2322 LeaveCriticalSection( &channel->cs );
2323 return E_INVALIDARG;
2325 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
2327 LeaveCriticalSection( &channel->cs );
2328 return hr;
2331 if ((hr = receive_message_bytes( channel, msg )) == S_OK) hr = init_reader( channel );
2332 if (hr != S_OK) channel->state = WS_CHANNEL_STATE_FAULTED;
2334 LeaveCriticalSection( &channel->cs );
2335 return hr;
2338 HRESULT channel_get_reader( WS_CHANNEL *handle, WS_XML_READER **reader )
2340 struct channel *channel = (struct channel *)handle;
2342 EnterCriticalSection( &channel->cs );
2344 if (channel->magic != CHANNEL_MAGIC)
2346 LeaveCriticalSection( &channel->cs );
2347 return E_INVALIDARG;
2350 *reader = channel->reader;
2352 LeaveCriticalSection( &channel->cs );
2353 return S_OK;
2356 static HRESULT read_message( WS_MESSAGE *handle, WS_XML_READER *reader, const WS_ELEMENT_DESCRIPTION *desc,
2357 WS_READ_OPTION option, WS_HEAP *heap, void *body, ULONG size, WS_ERROR *error )
2359 HRESULT hr;
2360 if ((hr = WsReadEnvelopeStart( handle, reader, NULL, NULL, NULL )) != S_OK) return hr;
2361 if ((hr = message_read_fault( handle, heap, error )) != S_OK) return hr;
2362 if ((hr = WsReadBody( handle, desc, option, heap, body, size, NULL )) != S_OK) return hr;
2363 return WsReadEnvelopeEnd( handle, NULL );
2366 static HRESULT receive_message( struct channel *channel, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION **desc,
2367 ULONG count, WS_RECEIVE_OPTION option, WS_READ_OPTION read_option, WS_HEAP *heap,
2368 void *value, ULONG size, ULONG *index, WS_ERROR *error )
2370 HRESULT hr;
2371 ULONG i;
2373 if ((hr = receive_message_bytes( channel, msg )) != S_OK) goto done;
2374 if ((hr = init_reader( channel )) != S_OK) goto done;
2376 for (i = 0; i < count; i++)
2378 const WS_ELEMENT_DESCRIPTION *body = desc[i]->bodyElementDescription;
2379 if ((hr = read_message( msg, channel->reader, body, read_option, heap, value, size, error )) == S_OK)
2381 if (index) *index = i;
2382 break;
2384 if ((hr = WsResetMessage( msg, NULL )) != S_OK) goto done;
2385 if ((hr = init_reader( channel )) != S_OK) goto done;
2387 hr = (i == count) ? WS_E_INVALID_FORMAT : S_OK;
2389 done:
2390 if (hr != S_OK) channel->state = WS_CHANNEL_STATE_FAULTED;
2391 return hr;
2394 struct receive_message
2396 struct task task;
2397 struct channel *channel;
2398 WS_MESSAGE *msg;
2399 const WS_MESSAGE_DESCRIPTION **desc;
2400 ULONG count;
2401 WS_RECEIVE_OPTION option;
2402 WS_READ_OPTION read_option;
2403 WS_HEAP *heap;
2404 void *value;
2405 ULONG size;
2406 ULONG *index;
2407 WS_ASYNC_CONTEXT ctx;
2408 WS_ERROR *error;
2411 static void receive_message_proc( struct task *task )
2413 struct receive_message *r = (struct receive_message *)task;
2414 HRESULT hr;
2416 hr = receive_message( r->channel, r->msg, r->desc, r->count, r->option, r->read_option, r->heap, r->value,
2417 r->size, r->index, r->error );
2419 TRACE( "calling %p(%#lx)\n", r->ctx.callback, hr );
2420 r->ctx.callback( hr, WS_LONG_CALLBACK, r->ctx.callbackState );
2421 TRACE( "%p returned\n", r->ctx.callback );
2424 static HRESULT queue_receive_message( struct channel *channel, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION **desc,
2425 ULONG count, WS_RECEIVE_OPTION option, WS_READ_OPTION read_option,
2426 WS_HEAP *heap, void *value, ULONG size, ULONG *index,
2427 const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
2429 struct receive_message *r;
2431 if (!(r = malloc( sizeof(*r) ))) return E_OUTOFMEMORY;
2432 r->task.proc = receive_message_proc;
2433 r->channel = channel;
2434 r->msg = msg;
2435 r->desc = desc;
2436 r->count = count;
2437 r->option = option;
2438 r->read_option = read_option;
2439 r->heap = heap;
2440 r->value = value;
2441 r->size = size;
2442 r->index = index;
2443 r->ctx = *ctx;
2444 r->error = error;
2445 return queue_task( &channel->recv_q, &r->task );
2448 /**************************************************************************
2449 * WsReceiveMessage [webservices.@]
2451 HRESULT WINAPI WsReceiveMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_MESSAGE_DESCRIPTION **desc,
2452 ULONG count, WS_RECEIVE_OPTION option, WS_READ_OPTION read_option, WS_HEAP *heap,
2453 void *value, ULONG size, ULONG *index, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
2455 struct channel *channel = (struct channel *)handle;
2456 WS_ASYNC_CONTEXT ctx_local;
2457 struct async async;
2458 HRESULT hr;
2460 TRACE( "%p %p %p %lu %u %u %p %p %lu %p %p %p\n", handle, msg, desc, count, option, read_option, heap,
2461 value, size, index, ctx, error );
2463 if (!channel || !msg || !desc || !count) return E_INVALIDARG;
2465 EnterCriticalSection( &channel->cs );
2467 if (channel->magic != CHANNEL_MAGIC)
2469 LeaveCriticalSection( &channel->cs );
2470 return E_INVALIDARG;
2472 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
2474 LeaveCriticalSection( &channel->cs );
2475 return hr;
2478 if (!ctx) async_init( &async, &ctx_local );
2479 hr = queue_receive_message( channel, msg, desc, count, option, read_option, heap, value, size, index,
2480 ctx ? ctx : &ctx_local, error );
2481 if (!ctx)
2483 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2484 CloseHandle( async.done );
2487 LeaveCriticalSection( &channel->cs );
2488 TRACE( "returning %#lx\n", hr );
2489 return hr;
2492 static HRESULT request_reply( struct channel *channel, WS_MESSAGE *request,
2493 const WS_MESSAGE_DESCRIPTION *request_desc, WS_WRITE_OPTION write_option,
2494 const void *request_body, ULONG request_size, WS_MESSAGE *reply,
2495 const WS_MESSAGE_DESCRIPTION *reply_desc, WS_READ_OPTION read_option,
2496 WS_HEAP *heap, void *value, ULONG size, WS_ERROR *error )
2498 HRESULT hr;
2500 if ((hr = send_message( channel, request, request_desc, write_option, request_body, request_size )) != S_OK)
2501 return hr;
2503 return receive_message( channel, reply, &reply_desc, 1, WS_RECEIVE_OPTIONAL_MESSAGE, read_option, heap,
2504 value, size, NULL, error );
2507 struct request_reply
2509 struct task task;
2510 struct channel *channel;
2511 WS_MESSAGE *request;
2512 const WS_MESSAGE_DESCRIPTION *request_desc;
2513 WS_WRITE_OPTION write_option;
2514 const void *request_body;
2515 ULONG request_size;
2516 WS_MESSAGE *reply;
2517 const WS_MESSAGE_DESCRIPTION *reply_desc;
2518 WS_READ_OPTION read_option;
2519 WS_HEAP *heap;
2520 void *value;
2521 ULONG size;
2522 WS_ASYNC_CONTEXT ctx;
2523 WS_ERROR *error;
2526 static void request_reply_proc( struct task *task )
2528 struct request_reply *r = (struct request_reply *)task;
2529 HRESULT hr;
2531 hr = request_reply( r->channel, r->request, r->request_desc, r->write_option, r->request_body, r->request_size,
2532 r->reply, r->reply_desc, r->read_option, r->heap, r->value, r->size, r->error );
2534 TRACE( "calling %p(%#lx)\n", r->ctx.callback, hr );
2535 r->ctx.callback( hr, WS_LONG_CALLBACK, r->ctx.callbackState );
2536 TRACE( "%p returned\n", r->ctx.callback );
2539 static HRESULT queue_request_reply( struct channel *channel, WS_MESSAGE *request,
2540 const WS_MESSAGE_DESCRIPTION *request_desc, WS_WRITE_OPTION write_option,
2541 const void *request_body, ULONG request_size, WS_MESSAGE *reply,
2542 const WS_MESSAGE_DESCRIPTION *reply_desc, WS_READ_OPTION read_option,
2543 WS_HEAP *heap, void *value, ULONG size, const WS_ASYNC_CONTEXT *ctx,
2544 WS_ERROR *error )
2546 struct request_reply *r;
2548 if (!(r = malloc( sizeof(*r) ))) return E_OUTOFMEMORY;
2549 r->task.proc = request_reply_proc;
2550 r->channel = channel;
2551 r->request = request;
2552 r->request_desc = request_desc;
2553 r->write_option = write_option;
2554 r->request_body = request_body;
2555 r->request_size = request_size;
2556 r->reply = reply;
2557 r->reply_desc = reply_desc;
2558 r->read_option = read_option;
2559 r->heap = heap;
2560 r->value = value;
2561 r->size = size;
2562 r->ctx = *ctx;
2563 r->error = error;
2564 return queue_task( &channel->recv_q, &r->task );
2567 /**************************************************************************
2568 * WsRequestReply [webservices.@]
2570 HRESULT WINAPI WsRequestReply( WS_CHANNEL *handle, WS_MESSAGE *request, const WS_MESSAGE_DESCRIPTION *request_desc,
2571 WS_WRITE_OPTION write_option, const void *request_body, ULONG request_size,
2572 WS_MESSAGE *reply, const WS_MESSAGE_DESCRIPTION *reply_desc, WS_READ_OPTION read_option,
2573 WS_HEAP *heap, void *value, ULONG size, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
2575 struct channel *channel = (struct channel *)handle;
2576 WS_ASYNC_CONTEXT ctx_local;
2577 struct async async;
2578 HRESULT hr;
2580 TRACE( "%p %p %p %u %p %lu %p %p %u %p %p %lu %p %p\n", handle, request, request_desc, write_option,
2581 request_body, request_size, reply, reply_desc, read_option, heap, value, size, ctx, error );
2583 if (!channel || !request || !reply) return E_INVALIDARG;
2585 EnterCriticalSection( &channel->cs );
2587 if (channel->magic != CHANNEL_MAGIC)
2589 LeaveCriticalSection( &channel->cs );
2590 return E_INVALIDARG;
2592 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
2594 LeaveCriticalSection( &channel->cs );
2595 return hr;
2598 WsInitializeMessage( request, WS_REQUEST_MESSAGE, NULL, NULL );
2600 if (!ctx) async_init( &async, &ctx_local );
2601 hr = queue_request_reply( channel, request, request_desc, write_option, request_body, request_size, reply,
2602 reply_desc, read_option, heap, value, size, ctx ? ctx : &ctx_local, error );
2603 if (!ctx)
2605 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2606 CloseHandle( async.done );
2609 LeaveCriticalSection( &channel->cs );
2610 TRACE( "returning %#lx\n", hr );
2611 return hr;
2614 static HRESULT read_message_start( struct channel *channel, WS_MESSAGE *msg )
2616 HRESULT hr;
2617 if ((hr = receive_message_bytes( channel, msg )) == S_OK && (hr = init_reader( channel )) == S_OK)
2618 hr = WsReadEnvelopeStart( msg, channel->reader, NULL, NULL, NULL );
2619 if (hr != S_OK) channel->state = WS_CHANNEL_STATE_FAULTED;
2620 return hr;
2623 struct read_message_start
2625 struct task task;
2626 struct channel *channel;
2627 WS_MESSAGE *msg;
2628 WS_ASYNC_CONTEXT ctx;
2631 static void read_message_start_proc( struct task *task )
2633 struct read_message_start *r = (struct read_message_start *)task;
2634 HRESULT hr;
2636 hr = read_message_start( r->channel, r->msg );
2638 TRACE( "calling %p(%#lx)\n", r->ctx.callback, hr );
2639 r->ctx.callback( hr, WS_LONG_CALLBACK, r->ctx.callbackState );
2640 TRACE( "%p returned\n", r->ctx.callback );
2643 static HRESULT queue_read_message_start( struct channel *channel, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx )
2645 struct read_message_start *r;
2647 if (!(r = malloc( sizeof(*r) ))) return E_OUTOFMEMORY;
2648 r->task.proc = read_message_start_proc;
2649 r->channel = channel;
2650 r->msg = msg;
2651 r->ctx = *ctx;
2652 return queue_task( &channel->recv_q, &r->task );
2655 /**************************************************************************
2656 * WsReadMessageStart [webservices.@]
2658 HRESULT WINAPI WsReadMessageStart( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
2660 struct channel *channel = (struct channel *)handle;
2661 WS_ASYNC_CONTEXT ctx_local;
2662 struct async async;
2663 HRESULT hr;
2665 TRACE( "%p %p %p %p\n", handle, msg, ctx, error );
2666 if (error) FIXME( "ignoring error parameter\n" );
2668 if (!channel || !msg) return E_INVALIDARG;
2670 EnterCriticalSection( &channel->cs );
2672 if (channel->magic != CHANNEL_MAGIC)
2674 LeaveCriticalSection( &channel->cs );
2675 return E_INVALIDARG;
2677 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
2679 LeaveCriticalSection( &channel->cs );
2680 return hr;
2683 if (!ctx) async_init( &async, &ctx_local );
2684 hr = queue_read_message_start( channel, msg, ctx ? ctx : &ctx_local );
2685 if (!ctx)
2687 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2688 CloseHandle( async.done );
2691 LeaveCriticalSection( &channel->cs );
2692 TRACE( "returning %#lx\n", hr );
2693 return hr;
2696 static HRESULT read_message_end( struct channel *channel, WS_MESSAGE *msg )
2698 HRESULT hr = WsReadEnvelopeEnd( msg, NULL );
2699 if (hr != S_OK) channel->state = WS_CHANNEL_STATE_FAULTED;
2700 return hr;
2703 struct read_message_end
2705 struct task task;
2706 struct channel *channel;
2707 WS_MESSAGE *msg;
2708 WS_ASYNC_CONTEXT ctx;
2711 static void read_message_end_proc( struct task *task )
2713 struct read_message_end *r = (struct read_message_end *)task;
2714 HRESULT hr;
2716 hr = read_message_end( r->channel, r->msg );
2718 TRACE( "calling %p(%#lx)\n", r->ctx.callback, hr );
2719 r->ctx.callback( hr, WS_LONG_CALLBACK, r->ctx.callbackState );
2720 TRACE( "%p returned\n", r->ctx.callback );
2723 static HRESULT queue_read_message_end( struct channel *channel, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx )
2725 struct read_message_end *r;
2727 if (!(r = malloc( sizeof(*r) ))) return E_OUTOFMEMORY;
2728 r->task.proc = read_message_end_proc;
2729 r->channel = channel;
2730 r->msg = msg;
2731 r->ctx = *ctx;
2732 return queue_task( &channel->recv_q, &r->task );
2735 /**************************************************************************
2736 * WsReadMessageEnd [webservices.@]
2738 HRESULT WINAPI WsReadMessageEnd( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
2740 struct channel *channel = (struct channel *)handle;
2741 WS_ASYNC_CONTEXT ctx_local;
2742 struct async async;
2743 HRESULT hr;
2745 TRACE( "%p %p %p %p\n", handle, msg, ctx, error );
2746 if (error) FIXME( "ignoring error parameter\n" );
2748 if (!channel || !msg) return E_INVALIDARG;
2750 EnterCriticalSection( &channel->cs );
2752 if (channel->magic != CHANNEL_MAGIC)
2754 LeaveCriticalSection( &channel->cs );
2755 return E_INVALIDARG;
2758 if (!ctx) async_init( &async, &ctx_local );
2759 hr = queue_read_message_end( channel, msg, ctx ? ctx : &ctx_local );
2760 if (!ctx)
2762 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2763 CloseHandle( async.done );
2766 LeaveCriticalSection( &channel->cs );
2767 TRACE( "returning %#lx\n", hr );
2768 return hr;
2771 static HRESULT write_message_start( struct channel *channel, WS_MESSAGE *msg )
2773 HRESULT hr;
2774 if ((hr = init_writer( channel )) != S_OK) goto done;
2775 if ((hr = WsAddressMessage( msg, &channel->addr, NULL )) != S_OK) goto done;
2776 hr = WsWriteEnvelopeStart( msg, channel->writer, NULL, NULL, NULL );
2778 done:
2779 if (hr != S_OK) channel->state = WS_CHANNEL_STATE_FAULTED;
2780 return hr;
2783 struct write_message_start
2785 struct task task;
2786 struct channel *channel;
2787 WS_MESSAGE *msg;
2788 WS_ASYNC_CONTEXT ctx;
2791 static void write_message_start_proc( struct task *task )
2793 struct write_message_start *w = (struct write_message_start *)task;
2794 HRESULT hr;
2796 hr = write_message_start( w->channel, w->msg );
2798 TRACE( "calling %p(%#lx)\n", w->ctx.callback, hr );
2799 w->ctx.callback( hr, WS_LONG_CALLBACK, w->ctx.callbackState );
2800 TRACE( "%p returned\n", w->ctx.callback );
2803 static HRESULT queue_write_message_start( struct channel *channel, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx )
2805 struct write_message_start *w;
2807 if (!(w = malloc( sizeof(*w) ))) return E_OUTOFMEMORY;
2808 w->task.proc = write_message_start_proc;
2809 w->channel = channel;
2810 w->msg = msg;
2811 w->ctx = *ctx;
2812 return queue_task( &channel->send_q, &w->task );
2815 /**************************************************************************
2816 * WsWriteMessageStart [webservices.@]
2818 HRESULT WINAPI WsWriteMessageStart( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
2820 struct channel *channel = (struct channel *)handle;
2821 WS_ASYNC_CONTEXT ctx_local;
2822 struct async async;
2823 HRESULT hr;
2825 TRACE( "%p %p %p %p\n", handle, msg, ctx, error );
2826 if (error) FIXME( "ignoring error parameter\n" );
2828 if (!channel || !msg) return E_INVALIDARG;
2830 EnterCriticalSection( &channel->cs );
2832 if (channel->magic != CHANNEL_MAGIC)
2834 LeaveCriticalSection( &channel->cs );
2835 return E_INVALIDARG;
2837 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
2839 LeaveCriticalSection( &channel->cs );
2840 return hr;
2843 if (!ctx) async_init( &async, &ctx_local );
2844 hr = queue_write_message_start( channel, msg, ctx ? ctx : &ctx_local );
2845 if (!ctx)
2847 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2848 CloseHandle( async.done );
2851 LeaveCriticalSection( &channel->cs );
2852 TRACE( "returning %#lx\n", hr );
2853 return hr;
2856 static HRESULT write_message_end( struct channel *channel, WS_MESSAGE *msg )
2858 HRESULT hr;
2859 if ((hr = WsWriteEnvelopeEnd( msg, NULL )) == S_OK) hr = send_message_bytes( channel, msg );
2860 if (hr != S_OK) channel->state = WS_CHANNEL_STATE_FAULTED;
2861 return hr;
2864 struct write_message_end
2866 struct task task;
2867 struct channel *channel;
2868 WS_MESSAGE *msg;
2869 WS_ASYNC_CONTEXT ctx;
2872 static void write_message_end_proc( struct task *task )
2874 struct write_message_end *w = (struct write_message_end *)task;
2875 HRESULT hr;
2877 hr = write_message_end( w->channel, w->msg );
2879 TRACE( "calling %p(%#lx)\n", w->ctx.callback, hr );
2880 w->ctx.callback( hr, WS_LONG_CALLBACK, w->ctx.callbackState );
2881 TRACE( "%p returned\n", w->ctx.callback );
2884 static HRESULT queue_write_message_end( struct channel *channel, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx )
2886 struct write_message_start *w;
2888 if (!(w = malloc( sizeof(*w) ))) return E_OUTOFMEMORY;
2889 w->task.proc = write_message_end_proc;
2890 w->channel = channel;
2891 w->msg = msg;
2892 w->ctx = *ctx;
2893 return queue_task( &channel->send_q, &w->task );
2896 /**************************************************************************
2897 * WsWriteMessageEnd [webservices.@]
2899 HRESULT WINAPI WsWriteMessageEnd( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
2901 struct channel *channel = (struct channel *)handle;
2902 WS_ASYNC_CONTEXT ctx_local;
2903 struct async async;
2904 HRESULT hr;
2906 TRACE( "%p %p %p %p\n", handle, msg, ctx, error );
2907 if (error) FIXME( "ignoring error parameter\n" );
2909 if (!channel || !msg) return E_INVALIDARG;
2911 EnterCriticalSection( &channel->cs );
2913 if (channel->magic != CHANNEL_MAGIC)
2915 LeaveCriticalSection( &channel->cs );
2916 return E_INVALIDARG;
2918 if ((hr = check_state( channel, WS_CHANNEL_STATE_OPEN )) != S_OK)
2920 LeaveCriticalSection( &channel->cs );
2921 return hr;
2924 if (!ctx) async_init( &async, &ctx_local );
2925 hr = queue_write_message_end( channel, msg, ctx ? ctx : &ctx_local );
2926 if (!ctx)
2928 if (hr == WS_S_ASYNC) hr = async_wait( &async );
2929 CloseHandle( async.done );
2932 LeaveCriticalSection( &channel->cs );
2933 TRACE( "returning %#lx\n", hr );
2934 return hr;
2937 static void set_blocking( SOCKET socket, BOOL blocking )
2939 ULONG state = !blocking;
2940 ioctlsocket( socket, FIONBIO, &state );
2943 static HRESULT sock_accept( SOCKET socket, HANDLE wait, HANDLE cancel, SOCKET *ret )
2945 HANDLE handles[] = { wait, cancel };
2946 HRESULT hr = S_OK;
2948 if (WSAEventSelect( socket, handles[0], FD_ACCEPT )) return HRESULT_FROM_WIN32( WSAGetLastError() );
2950 switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE ))
2952 case 0:
2953 if ((*ret = accept( socket, NULL, NULL )) != -1)
2955 WSAEventSelect( *ret, NULL, 0 );
2956 set_blocking( *ret, TRUE );
2957 break;
2959 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
2960 break;
2962 case 1:
2963 hr = WS_E_OPERATION_ABORTED;
2964 break;
2966 default:
2967 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
2968 break;
2971 return hr;
2974 HRESULT channel_accept_tcp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle )
2976 struct channel *channel = (struct channel *)handle;
2977 HRESULT hr;
2979 EnterCriticalSection( &channel->cs );
2981 if (channel->magic != CHANNEL_MAGIC)
2983 LeaveCriticalSection( &channel->cs );
2984 return E_INVALIDARG;
2987 if ((hr = sock_accept( socket, wait, cancel, &channel->u.tcp.socket )) == S_OK)
2989 BOOL nodelay = FALSE;
2990 prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_NO_DELAY, &nodelay, sizeof(nodelay) );
2991 setsockopt( channel->u.tcp.socket, IPPROTO_TCP, TCP_NODELAY, (const char *)&nodelay, sizeof(nodelay) );
2992 channel->state = WS_CHANNEL_STATE_OPEN;
2995 LeaveCriticalSection( &channel->cs );
2996 return hr;
2999 static HRESULT sock_wait( SOCKET socket, HANDLE wait, HANDLE cancel )
3001 HANDLE handles[] = { wait, cancel };
3002 HRESULT hr;
3004 if (WSAEventSelect( socket, handles[0], FD_READ )) return HRESULT_FROM_WIN32( WSAGetLastError() );
3006 switch (WSAWaitForMultipleEvents( 2, handles, FALSE, WSA_INFINITE, FALSE ))
3008 case 0:
3009 hr = S_OK;
3010 break;
3012 case 1:
3013 hr = WS_E_OPERATION_ABORTED;
3014 break;
3016 default:
3017 hr = HRESULT_FROM_WIN32( WSAGetLastError() );
3018 break;
3021 WSAEventSelect( socket, NULL, 0 );
3022 set_blocking( socket, TRUE );
3023 return hr;
3026 HRESULT channel_accept_udp( SOCKET socket, HANDLE wait, HANDLE cancel, WS_CHANNEL *handle )
3028 struct channel *channel = (struct channel *)handle;
3029 HRESULT hr;
3031 EnterCriticalSection( &channel->cs );
3033 if (channel->magic != CHANNEL_MAGIC)
3035 LeaveCriticalSection( &channel->cs );
3036 return E_INVALIDARG;
3039 if ((hr = sock_wait( socket, wait, cancel )) == S_OK)
3041 channel->u.udp.socket = socket;
3042 channel->state = WS_CHANNEL_STATE_OPEN;
3045 LeaveCriticalSection( &channel->cs );
3046 return hr;
3049 HRESULT channel_address_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
3051 struct channel *channel = (struct channel *)handle;
3052 return WsAddressMessage( msg, &channel->addr, NULL );