windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / webservices / listener.c
blobda4e135703fbb01ec8bb8def692db73900646982
1 /*
2 * Copyright 2017 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>
20 #include <locale.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "webservices.h"
26 #include "wine/debug.h"
27 #include "wine/list.h"
28 #include "webservices_private.h"
29 #include "sock.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
33 HINSTANCE webservices_instance;
35 static BOOL winsock_loaded;
37 static BOOL WINAPI winsock_startup( INIT_ONCE *once, void *param, void **ctx )
39 int ret;
40 WSADATA data;
41 if (!(ret = WSAStartup( MAKEWORD(1,1), &data ))) winsock_loaded = TRUE;
42 else ERR( "WSAStartup failed: %d\n", ret );
43 return TRUE;
46 void winsock_init(void)
48 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
49 InitOnceExecuteOnce( &once, winsock_startup, NULL, NULL );
52 _locale_t c_locale;
54 /******************************************************************
55 * DllMain (webservices.@)
57 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved )
59 switch (reason)
61 case DLL_PROCESS_ATTACH:
62 webservices_instance = hinst;
63 DisableThreadLibraryCalls( hinst );
64 c_locale = _create_locale( LC_ALL, "C" );
65 break;
67 case DLL_PROCESS_DETACH:
68 if (reserved) break;
69 if (winsock_loaded) WSACleanup();
70 _free_locale( c_locale );
71 break;
73 return TRUE;
76 static const struct prop_desc listener_props[] =
78 { sizeof(ULONG), FALSE }, /* WS_LISTENER_PROPERTY_LISTEN_BACKLOG */
79 { sizeof(WS_IP_VERSION), FALSE }, /* WS_LISTENER_PROPERTY_IP_VERSION */
80 { sizeof(WS_LISTENER_STATE), TRUE }, /* WS_LISTENER_PROPERTY_STATE */
81 { sizeof(WS_CALLBACK_MODEL), FALSE }, /* WS_LISTENER_PROPERTY_ASYNC_CALLBACK_MODEL */
82 { sizeof(WS_CHANNEL_TYPE), TRUE }, /* WS_LISTENER_PROPERTY_CHANNEL_TYPE */
83 { sizeof(WS_CHANNEL_BINDING), TRUE }, /* WS_LISTENER_PROPERTY_CHANNEL_BINDING */
84 { sizeof(ULONG), FALSE }, /* WS_LISTENER_PROPERTY_CONNECT_TIMEOUT */
85 { sizeof(BOOL), FALSE }, /* WS_LISTENER_PROPERTY_IS_MULTICAST */
86 { 0, FALSE }, /* WS_LISTENER_PROPERTY_MULTICAST_INTERFACES */
87 { sizeof(BOOL), FALSE }, /* WS_LISTENER_PROPERTY_MULTICAST_LOOPBACK */
88 { sizeof(ULONG), FALSE }, /* WS_LISTENER_PROPERTY_CLOSE_TIMEOUT */
89 { sizeof(ULONG), FALSE }, /* WS_LISTENER_PROPERTY_TO_HEADER_MATCHING_OPTIONS */
90 { sizeof(ULONG), FALSE }, /* WS_LISTENER_PROPERTY_TRANSPORT_URL_MATCHING_OPTIONS */
91 { sizeof(WS_CUSTOM_LISTENER_CALLBACKS), FALSE }, /* WS_LISTENER_PROPERTY_CUSTOM_LISTENER_CALLBACKS */
92 { 0, FALSE }, /* WS_LISTENER_PROPERTY_CUSTOM_LISTENER_PARAMETERS */
93 { sizeof(void *), TRUE }, /* WS_LISTENER_PROPERTY_CUSTOM_LISTENER_INSTANCE */
94 { sizeof(WS_DISALLOWED_USER_AGENT_SUBSTRINGS), FALSE } /* WS_LISTENER_PROPERTY_DISALLOWED_USER_AGENT */
97 struct listener
99 ULONG magic;
100 CRITICAL_SECTION cs;
101 WS_CHANNEL_TYPE type;
102 WS_CHANNEL_BINDING binding;
103 WS_LISTENER_STATE state;
104 HANDLE wait;
105 HANDLE cancel;
106 WS_CHANNEL *channel;
107 union
109 struct
111 SOCKET socket;
112 } tcp;
113 struct
115 SOCKET socket;
116 } udp;
117 } u;
118 ULONG prop_count;
119 struct prop prop[ARRAY_SIZE( listener_props )];
122 #define LISTENER_MAGIC (('L' << 24) | ('I' << 16) | ('S' << 8) | 'T')
124 static struct listener *alloc_listener(void)
126 static const ULONG count = ARRAY_SIZE( listener_props );
127 struct listener *ret;
128 ULONG size = sizeof(*ret) + prop_size( listener_props, count );
130 if (!(ret = calloc( 1, size ))) return NULL;
132 ret->magic = LISTENER_MAGIC;
133 if (!(ret->wait = CreateEventW( NULL, FALSE, FALSE, NULL )))
135 free( ret );
136 return NULL;
138 if (!(ret->cancel = CreateEventW( NULL, FALSE, FALSE, NULL )))
140 CloseHandle( ret->wait );
141 free( ret );
142 return NULL;
144 InitializeCriticalSectionEx( &ret->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
145 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": listener.cs");
147 prop_init( listener_props, count, ret->prop, &ret[1] );
148 ret->prop_count = count;
149 return ret;
152 static void reset_listener( struct listener *listener )
154 listener->state = WS_LISTENER_STATE_CREATED;
155 SetEvent( listener->cancel );
156 listener->channel = NULL;
158 switch (listener->binding)
160 case WS_TCP_CHANNEL_BINDING:
161 closesocket( listener->u.tcp.socket );
162 listener->u.tcp.socket = -1;
163 break;
165 case WS_UDP_CHANNEL_BINDING:
166 closesocket( listener->u.udp.socket );
167 listener->u.udp.socket = -1;
168 break;
170 default: break;
174 static void free_listener( struct listener *listener )
176 reset_listener( listener );
178 CloseHandle( listener->wait );
179 CloseHandle( listener->cancel );
181 listener->cs.DebugInfo->Spare[0] = 0;
182 DeleteCriticalSection( &listener->cs );
183 free( listener );
186 static HRESULT create_listener( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding,
187 const WS_LISTENER_PROPERTY *properties, ULONG count, struct listener **ret )
189 struct listener *listener;
190 HRESULT hr;
191 ULONG i;
193 if (!(listener = alloc_listener())) return E_OUTOFMEMORY;
195 for (i = 0; i < count; i++)
197 hr = prop_set( listener->prop, listener->prop_count, properties[i].id, properties[i].value,
198 properties[i].valueSize );
199 if (hr != S_OK)
201 free_listener( listener );
202 return hr;
206 listener->type = type;
207 listener->binding = binding;
209 switch (listener->binding)
211 case WS_TCP_CHANNEL_BINDING:
212 listener->u.tcp.socket = -1;
213 break;
215 case WS_UDP_CHANNEL_BINDING:
216 listener->u.udp.socket = -1;
217 break;
219 default: break;
222 *ret = listener;
223 return S_OK;
226 /**************************************************************************
227 * WsCreateListener [webservices.@]
229 HRESULT WINAPI WsCreateListener( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding,
230 const WS_LISTENER_PROPERTY *properties, ULONG count,
231 const WS_SECURITY_DESCRIPTION *desc, WS_LISTENER **handle,
232 WS_ERROR *error )
234 struct listener *listener;
235 HRESULT hr;
237 TRACE( "%u %u %p %lu %p %p %p\n", type, binding, properties, count, desc, handle, error );
238 if (error) FIXME( "ignoring error parameter\n" );
239 if (desc) FIXME( "ignoring security description\n" );
241 if (!handle) return E_INVALIDARG;
243 if (type != WS_CHANNEL_TYPE_DUPLEX_SESSION && type != WS_CHANNEL_TYPE_DUPLEX)
245 FIXME( "channel type %u not implemented\n", type );
246 return E_NOTIMPL;
248 if (binding != WS_TCP_CHANNEL_BINDING && binding != WS_UDP_CHANNEL_BINDING)
250 FIXME( "channel binding %u not implemented\n", binding );
251 return E_NOTIMPL;
254 if ((hr = create_listener( type, binding, properties, count, &listener )) != S_OK) return hr;
256 TRACE( "created %p\n", listener );
257 *handle = (WS_LISTENER *)listener;
258 return S_OK;
261 /**************************************************************************
262 * WsFreeListener [webservices.@]
264 void WINAPI WsFreeListener( WS_LISTENER *handle )
266 struct listener *listener = (struct listener *)handle;
268 TRACE( "%p\n", handle );
270 if (!listener) return;
272 EnterCriticalSection( &listener->cs );
274 if (listener->magic != LISTENER_MAGIC)
276 LeaveCriticalSection( &listener->cs );
277 return;
280 listener->magic = 0;
282 LeaveCriticalSection( &listener->cs );
283 free_listener( listener );
286 HRESULT resolve_hostname( const WCHAR *host, USHORT port, struct sockaddr *addr, int *addr_len, int flags )
288 WCHAR service[6];
289 ADDRINFOW hints, *res, *info;
290 HRESULT hr = WS_E_ADDRESS_NOT_AVAILABLE;
292 memset( &hints, 0, sizeof(hints) );
293 hints.ai_flags = flags;
294 hints.ai_family = AF_INET;
296 *addr_len = 0;
297 swprintf( service, ARRAY_SIZE(service), L"%u", port );
298 if (GetAddrInfoW( host, service, &hints, &res )) return HRESULT_FROM_WIN32( WSAGetLastError() );
300 info = res;
301 while (info && info->ai_family != AF_INET) info = info->ai_next;
302 if (info)
304 memcpy( addr, info->ai_addr, info->ai_addrlen );
305 *addr_len = info->ai_addrlen;
306 hr = S_OK;
309 FreeAddrInfoW( res );
310 return hr;
313 HRESULT parse_url( const WS_STRING *str, WS_URL_SCHEME_TYPE *scheme, WCHAR **host, USHORT *port )
315 WS_HEAP *heap;
316 WS_NETTCP_URL *url;
317 HRESULT hr;
319 if ((hr = WsCreateHeap( 1 << 8, 0, NULL, 0, &heap, NULL )) != S_OK) return hr;
320 if ((hr = WsDecodeUrl( str, 0, heap, (WS_URL **)&url, NULL )) != S_OK)
322 WsFreeHeap( heap );
323 return hr;
326 if (url->host.length == 1 && (url->host.chars[0] == '+' || url->host.chars[0] == '*')) *host = NULL;
327 else
329 if (!(*host = malloc( (url->host.length + 1) * sizeof(WCHAR) )))
331 WsFreeHeap( heap );
332 return E_OUTOFMEMORY;
334 memcpy( *host, url->host.chars, url->host.length * sizeof(WCHAR) );
335 (*host)[url->host.length] = 0;
337 *scheme = url->url.scheme;
338 *port = url->port;
340 WsFreeHeap( heap );
341 return hr;
344 static HRESULT open_listener_tcp( struct listener *listener, const WS_STRING *url )
346 struct sockaddr_storage storage;
347 struct sockaddr *addr = (struct sockaddr *)&storage;
348 int addr_len, on = 1;
349 WS_URL_SCHEME_TYPE scheme;
350 WCHAR *host;
351 USHORT port;
352 HRESULT hr;
354 if ((hr = parse_url( url, &scheme, &host, &port )) != S_OK) return hr;
355 if (scheme != WS_URL_NETTCP_SCHEME_TYPE)
357 free( host );
358 return WS_E_INVALID_ENDPOINT_URL;
361 winsock_init();
363 hr = resolve_hostname( host, port, addr, &addr_len, AI_PASSIVE );
364 free( host );
365 if (hr != S_OK) return hr;
367 if ((listener->u.tcp.socket = socket( addr->sa_family, SOCK_STREAM, 0 )) == -1)
368 return HRESULT_FROM_WIN32( WSAGetLastError() );
370 if (setsockopt( listener->u.tcp.socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on) ) < 0)
372 closesocket( listener->u.tcp.socket );
373 listener->u.tcp.socket = -1;
374 return HRESULT_FROM_WIN32( WSAGetLastError() );
377 if (bind( listener->u.tcp.socket, addr, addr_len ) < 0)
379 closesocket( listener->u.tcp.socket );
380 listener->u.tcp.socket = -1;
381 return HRESULT_FROM_WIN32( WSAGetLastError() );
384 if (listen( listener->u.tcp.socket, 0 ) < 0)
386 closesocket( listener->u.tcp.socket );
387 listener->u.tcp.socket = -1;
388 return HRESULT_FROM_WIN32( WSAGetLastError() );
391 listener->state = WS_LISTENER_STATE_OPEN;
392 return S_OK;
395 static HRESULT open_listener_udp( struct listener *listener, const WS_STRING *url )
397 struct sockaddr_storage storage;
398 struct sockaddr *addr = (struct sockaddr *)&storage;
399 int addr_len;
400 WS_URL_SCHEME_TYPE scheme;
401 WCHAR *host;
402 USHORT port;
403 HRESULT hr;
405 if ((hr = parse_url( url, &scheme, &host, &port )) != S_OK) return hr;
406 if (scheme != WS_URL_SOAPUDP_SCHEME_TYPE)
408 free( host );
409 return WS_E_INVALID_ENDPOINT_URL;
412 winsock_init();
414 hr = resolve_hostname( host, port, addr, &addr_len, AI_PASSIVE );
415 free( host );
416 if (hr != S_OK) return hr;
418 if ((listener->u.udp.socket = socket( addr->sa_family, SOCK_DGRAM, 0 )) == -1)
419 return HRESULT_FROM_WIN32( WSAGetLastError() );
421 if (bind( listener->u.udp.socket, addr, addr_len ) < 0)
423 closesocket( listener->u.udp.socket );
424 listener->u.udp.socket = -1;
425 return HRESULT_FROM_WIN32( WSAGetLastError() );
428 listener->state = WS_LISTENER_STATE_OPEN;
429 return S_OK;
432 static HRESULT open_listener( struct listener *listener, const WS_STRING *url )
434 switch (listener->binding)
436 case WS_TCP_CHANNEL_BINDING:
437 return open_listener_tcp( listener, url );
439 case WS_UDP_CHANNEL_BINDING:
440 return open_listener_udp( listener, url );
442 default:
443 ERR( "unhandled binding %u\n", listener->binding );
444 return E_NOTIMPL;
448 /**************************************************************************
449 * WsOpenListener [webservices.@]
451 HRESULT WINAPI WsOpenListener( WS_LISTENER *handle, const WS_STRING *url, const WS_ASYNC_CONTEXT *ctx,
452 WS_ERROR *error )
454 struct listener *listener = (struct listener *)handle;
455 HRESULT hr;
457 TRACE( "%p %s %p %p\n", handle, url ? debugstr_wn(url->chars, url->length) : "null", ctx, error );
458 if (error) FIXME( "ignoring error parameter\n" );
459 if (ctx) FIXME( "ignoring ctx parameter\n" );
461 if (!listener || !url) return E_INVALIDARG;
463 EnterCriticalSection( &listener->cs );
465 if (listener->magic != LISTENER_MAGIC)
467 LeaveCriticalSection( &listener->cs );
468 return E_INVALIDARG;
471 if (listener->state != WS_LISTENER_STATE_CREATED) hr = WS_E_INVALID_OPERATION;
472 else hr = open_listener( listener, url );
474 LeaveCriticalSection( &listener->cs );
475 TRACE( "returning %#lx\n", hr );
476 return hr;
479 static void close_listener( struct listener *listener )
481 reset_listener( listener );
482 listener->state = WS_LISTENER_STATE_CLOSED;
485 /**************************************************************************
486 * WsCloseListener [webservices.@]
488 HRESULT WINAPI WsCloseListener( WS_LISTENER *handle, const WS_ASYNC_CONTEXT *ctx, WS_ERROR *error )
490 struct listener *listener = (struct listener *)handle;
491 HRESULT hr = S_OK;
493 TRACE( "%p %p %p\n", handle, ctx, error );
494 if (error) FIXME( "ignoring error parameter\n" );
495 if (ctx) FIXME( "ignoring ctx parameter\n" );
497 if (!listener) return E_INVALIDARG;
499 EnterCriticalSection( &listener->cs );
501 if (listener->magic != LISTENER_MAGIC)
503 LeaveCriticalSection( &listener->cs );
504 return E_INVALIDARG;
507 close_listener( listener );
509 LeaveCriticalSection( &listener->cs );
510 TRACE( "returning %#lx\n", hr );
511 return hr;
514 /**************************************************************************
515 * WsResetListener [webservices.@]
517 HRESULT WINAPI WsResetListener( WS_LISTENER *handle, WS_ERROR *error )
519 struct listener *listener = (struct listener *)handle;
520 HRESULT hr = S_OK;
522 TRACE( "%p %p\n", handle, error );
523 if (error) FIXME( "ignoring error parameter\n" );
525 if (!listener) return E_INVALIDARG;
527 EnterCriticalSection( &listener->cs );
529 if (listener->magic != LISTENER_MAGIC)
531 LeaveCriticalSection( &listener->cs );
532 return E_INVALIDARG;
535 if (listener->state != WS_LISTENER_STATE_CREATED && listener->state != WS_LISTENER_STATE_CLOSED)
536 hr = WS_E_INVALID_OPERATION;
537 else
538 reset_listener( listener );
540 LeaveCriticalSection( &listener->cs );
541 TRACE( "returning %#lx\n", hr );
542 return hr;
545 /**************************************************************************
546 * WsGetListenerProperty [webservices.@]
548 HRESULT WINAPI WsGetListenerProperty( WS_LISTENER *handle, WS_LISTENER_PROPERTY_ID id, void *buf,
549 ULONG size, WS_ERROR *error )
551 struct listener *listener = (struct listener *)handle;
552 HRESULT hr = S_OK;
554 TRACE( "%p %u %p %lu %p\n", handle, id, buf, size, error );
555 if (error) FIXME( "ignoring error parameter\n" );
557 if (!listener) return E_INVALIDARG;
559 EnterCriticalSection( &listener->cs );
561 if (listener->magic != LISTENER_MAGIC)
563 LeaveCriticalSection( &listener->cs );
564 return E_INVALIDARG;
567 switch (id)
569 case WS_LISTENER_PROPERTY_STATE:
570 if (!buf || size != sizeof(listener->state)) hr = E_INVALIDARG;
571 else *(WS_LISTENER_STATE *)buf = listener->state;
572 break;
574 case WS_LISTENER_PROPERTY_CHANNEL_TYPE:
575 if (!buf || size != sizeof(listener->type)) hr = E_INVALIDARG;
576 else *(WS_CHANNEL_TYPE *)buf = listener->type;
577 break;
579 case WS_LISTENER_PROPERTY_CHANNEL_BINDING:
580 if (!buf || size != sizeof(listener->binding)) hr = E_INVALIDARG;
581 else *(WS_CHANNEL_BINDING *)buf = listener->binding;
582 break;
584 default:
585 hr = prop_get( listener->prop, listener->prop_count, id, buf, size );
588 LeaveCriticalSection( &listener->cs );
589 TRACE( "returning %#lx\n", hr );
590 return hr;
593 /**************************************************************************
594 * WsSetListenerProperty [webservices.@]
596 HRESULT WINAPI WsSetListenerProperty( WS_LISTENER *handle, WS_LISTENER_PROPERTY_ID id, const void *value,
597 ULONG size, WS_ERROR *error )
599 struct listener *listener = (struct listener *)handle;
600 HRESULT hr;
602 TRACE( "%p %u %p %lu %p\n", handle, id, value, size, error );
603 if (error) FIXME( "ignoring error parameter\n" );
605 if (!listener) return E_INVALIDARG;
607 EnterCriticalSection( &listener->cs );
609 if (listener->magic != LISTENER_MAGIC)
611 LeaveCriticalSection( &listener->cs );
612 return E_INVALIDARG;
615 hr = prop_set( listener->prop, listener->prop_count, id, value, size );
617 LeaveCriticalSection( &listener->cs );
618 TRACE( "returning %#lx\n", hr );
619 return hr;
622 /**************************************************************************
623 * WsAcceptChannel [webservices.@]
625 HRESULT WINAPI WsAcceptChannel( WS_LISTENER *handle, WS_CHANNEL *channel_handle, const WS_ASYNC_CONTEXT *ctx,
626 WS_ERROR *error )
628 struct listener *listener = (struct listener *)handle;
629 HRESULT hr = E_NOTIMPL;
630 HANDLE wait, cancel;
632 TRACE( "%p %p %p %p\n", handle, channel_handle, ctx, error );
633 if (error) FIXME( "ignoring error parameter\n" );
634 if (ctx) FIXME( "ignoring ctx parameter\n" );
636 if (!listener || !channel_handle) return E_INVALIDARG;
638 EnterCriticalSection( &listener->cs );
640 if (listener->magic != LISTENER_MAGIC)
642 LeaveCriticalSection( &listener->cs );
643 return E_INVALIDARG;
646 if (listener->state != WS_LISTENER_STATE_OPEN || (listener->channel && listener->channel != channel_handle))
648 hr = WS_E_INVALID_OPERATION;
650 else
652 wait = listener->wait;
653 cancel = listener->cancel;
654 listener->channel = channel_handle;
656 switch (listener->binding)
658 case WS_TCP_CHANNEL_BINDING:
660 SOCKET socket = listener->u.tcp.socket;
662 LeaveCriticalSection( &listener->cs );
663 hr = channel_accept_tcp( socket, wait, cancel, channel_handle );
664 TRACE( "returning %#lx\n", hr );
665 return hr;
667 case WS_UDP_CHANNEL_BINDING:
669 SOCKET socket = listener->u.udp.socket;
671 LeaveCriticalSection( &listener->cs );
672 hr = channel_accept_udp( socket, wait, cancel, channel_handle );
673 TRACE( "returning %#lx\n", hr );
674 return hr;
676 default:
677 FIXME( "listener binding %u not supported\n", listener->binding );
678 break;
682 LeaveCriticalSection( &listener->cs );
683 TRACE( "returning %#lx\n", hr );
684 return hr;