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
24 #include "webservices.h"
26 #include "wine/debug.h"
27 #include "wine/list.h"
28 #include "webservices_private.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
)
41 if (!(ret
= WSAStartup( MAKEWORD(1,1), &data
))) winsock_loaded
= TRUE
;
42 else ERR( "WSAStartup failed: %d\n", ret
);
46 void winsock_init(void)
48 static INIT_ONCE once
= INIT_ONCE_STATIC_INIT
;
49 InitOnceExecuteOnce( &once
, winsock_startup
, NULL
, NULL
);
54 /******************************************************************
55 * DllMain (webservices.@)
57 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, void *reserved
)
61 case DLL_PROCESS_ATTACH
:
62 webservices_instance
= hinst
;
63 DisableThreadLibraryCalls( hinst
);
64 c_locale
= _create_locale( LC_ALL
, "C" );
67 case DLL_PROCESS_DETACH
:
69 if (winsock_loaded
) WSACleanup();
70 _free_locale( c_locale
);
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 */
101 WS_CHANNEL_TYPE type
;
102 WS_CHANNEL_BINDING binding
;
103 WS_LISTENER_STATE state
;
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
)))
138 if (!(ret
->cancel
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
)))
140 CloseHandle( ret
->wait
);
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
;
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;
165 case WS_UDP_CHANNEL_BINDING
:
166 closesocket( listener
->u
.udp
.socket
);
167 listener
->u
.udp
.socket
= -1;
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
);
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
;
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
);
201 free_listener( listener
);
206 listener
->type
= type
;
207 listener
->binding
= binding
;
209 switch (listener
->binding
)
211 case WS_TCP_CHANNEL_BINDING
:
212 listener
->u
.tcp
.socket
= -1;
215 case WS_UDP_CHANNEL_BINDING
:
216 listener
->u
.udp
.socket
= -1;
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
,
234 struct listener
*listener
;
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
);
248 if (binding
!= WS_TCP_CHANNEL_BINDING
&& binding
!= WS_UDP_CHANNEL_BINDING
)
250 FIXME( "channel binding %u not implemented\n", binding
);
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
;
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
);
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
)
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
;
297 swprintf( service
, ARRAY_SIZE(service
), L
"%u", port
);
298 if (GetAddrInfoW( host
, service
, &hints
, &res
)) return HRESULT_FROM_WIN32( WSAGetLastError() );
301 while (info
&& info
->ai_family
!= AF_INET
) info
= info
->ai_next
;
304 memcpy( addr
, info
->ai_addr
, info
->ai_addrlen
);
305 *addr_len
= info
->ai_addrlen
;
309 FreeAddrInfoW( res
);
313 HRESULT
parse_url( const WS_STRING
*str
, WS_URL_SCHEME_TYPE
*scheme
, WCHAR
**host
, USHORT
*port
)
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
)
326 if (url
->host
.length
== 1 && (url
->host
.chars
[0] == '+' || url
->host
.chars
[0] == '*')) *host
= NULL
;
329 if (!(*host
= malloc( (url
->host
.length
+ 1) * sizeof(WCHAR
) )))
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
;
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
;
354 if ((hr
= parse_url( url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
355 if (scheme
!= WS_URL_NETTCP_SCHEME_TYPE
)
358 return WS_E_INVALID_ENDPOINT_URL
;
363 hr
= resolve_hostname( host
, port
, addr
, &addr_len
, AI_PASSIVE
);
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
;
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
;
400 WS_URL_SCHEME_TYPE scheme
;
405 if ((hr
= parse_url( url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
406 if (scheme
!= WS_URL_SOAPUDP_SCHEME_TYPE
)
409 return WS_E_INVALID_ENDPOINT_URL
;
414 hr
= resolve_hostname( host
, port
, addr
, &addr_len
, AI_PASSIVE
);
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
;
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
);
443 ERR( "unhandled binding %u\n", listener
->binding
);
448 /**************************************************************************
449 * WsOpenListener [webservices.@]
451 HRESULT WINAPI
WsOpenListener( WS_LISTENER
*handle
, const WS_STRING
*url
, const WS_ASYNC_CONTEXT
*ctx
,
454 struct listener
*listener
= (struct listener
*)handle
;
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
);
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
);
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
;
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
);
507 close_listener( listener
);
509 LeaveCriticalSection( &listener
->cs
);
510 TRACE( "returning %#lx\n", hr
);
514 /**************************************************************************
515 * WsResetListener [webservices.@]
517 HRESULT WINAPI
WsResetListener( WS_LISTENER
*handle
, WS_ERROR
*error
)
519 struct listener
*listener
= (struct listener
*)handle
;
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
);
535 if (listener
->state
!= WS_LISTENER_STATE_CREATED
&& listener
->state
!= WS_LISTENER_STATE_CLOSED
)
536 hr
= WS_E_INVALID_OPERATION
;
538 reset_listener( listener
);
540 LeaveCriticalSection( &listener
->cs
);
541 TRACE( "returning %#lx\n", 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
;
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
);
569 case WS_LISTENER_PROPERTY_STATE
:
570 if (!buf
|| size
!= sizeof(listener
->state
)) hr
= E_INVALIDARG
;
571 else *(WS_LISTENER_STATE
*)buf
= listener
->state
;
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
;
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
;
585 hr
= prop_get( listener
->prop
, listener
->prop_count
, id
, buf
, size
);
588 LeaveCriticalSection( &listener
->cs
);
589 TRACE( "returning %#lx\n", 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
;
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
);
615 hr
= prop_set( listener
->prop
, listener
->prop_count
, id
, value
, size
);
617 LeaveCriticalSection( &listener
->cs
);
618 TRACE( "returning %#lx\n", hr
);
622 /**************************************************************************
623 * WsAcceptChannel [webservices.@]
625 HRESULT WINAPI
WsAcceptChannel( WS_LISTENER
*handle
, WS_CHANNEL
*channel_handle
, const WS_ASYNC_CONTEXT
*ctx
,
628 struct listener
*listener
= (struct listener
*)handle
;
629 HRESULT hr
= E_NOTIMPL
;
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
);
646 if (listener
->state
!= WS_LISTENER_STATE_OPEN
|| (listener
->channel
&& listener
->channel
!= channel_handle
))
648 hr
= WS_E_INVALID_OPERATION
;
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
);
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
);
677 FIXME( "listener binding %u not supported\n", listener
->binding
);
682 LeaveCriticalSection( &listener
->cs
);
683 TRACE( "returning %#lx\n", hr
);