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
23 #include "webservices.h"
25 #include "wine/debug.h"
26 #include "wine/list.h"
27 #include "wine/unicode.h"
28 #include "webservices_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(webservices
);
33 static BOOL winsock_loaded
;
35 static BOOL WINAPI
winsock_startup( INIT_ONCE
*once
, void *param
, void **ctx
)
39 if (!(ret
= WSAStartup( MAKEWORD(1,1), &data
))) winsock_loaded
= TRUE
;
40 else ERR( "WSAStartup failed: %d\n", ret
);
44 void winsock_init(void)
46 static INIT_ONCE once
= INIT_ONCE_STATIC_INIT
;
47 InitOnceExecuteOnce( &once
, winsock_startup
, NULL
, NULL
);
50 static const struct prop_desc listener_props
[] =
52 { sizeof(ULONG
), FALSE
}, /* WS_LISTENER_PROPERTY_LISTEN_BACKLOG */
53 { sizeof(WS_IP_VERSION
), FALSE
}, /* WS_LISTENER_PROPERTY_IP_VERSION */
54 { sizeof(WS_LISTENER_STATE
), TRUE
}, /* WS_LISTENER_PROPERTY_STATE */
55 { sizeof(WS_CALLBACK_MODEL
), FALSE
}, /* WS_LISTENER_PROPERTY_ASYNC_CALLBACK_MODEL */
56 { sizeof(WS_CHANNEL_TYPE
), TRUE
}, /* WS_LISTENER_PROPERTY_CHANNEL_TYPE */
57 { sizeof(WS_CHANNEL_BINDING
), TRUE
}, /* WS_LISTENER_PROPERTY_CHANNEL_BINDING */
58 { sizeof(ULONG
), FALSE
}, /* WS_LISTENER_PROPERTY_CONNECT_TIMEOUT */
59 { sizeof(BOOL
), FALSE
}, /* WS_LISTENER_PROPERTY_IS_MULTICAST */
60 { 0, FALSE
}, /* WS_LISTENER_PROPERTY_MULTICAST_INTERFACES */
61 { sizeof(BOOL
), FALSE
}, /* WS_LISTENER_PROPERTY_MULTICAST_LOOPBACK */
62 { sizeof(ULONG
), FALSE
}, /* WS_LISTENER_PROPERTY_CLOSE_TIMEOUT */
63 { sizeof(ULONG
), FALSE
}, /* WS_LISTENER_PROPERTY_TO_HEADER_MATCHING_OPTIONS */
64 { sizeof(ULONG
), FALSE
}, /* WS_LISTENER_PROPERTY_TRANSPORT_URL_MATCHING_OPTIONS */
65 { sizeof(WS_CUSTOM_LISTENER_CALLBACKS
), FALSE
}, /* WS_LISTENER_PROPERTY_CUSTOM_LISTENER_CALLBACKS */
66 { 0, FALSE
}, /* WS_LISTENER_PROPERTY_CUSTOM_LISTENER_PARAMETERS */
67 { sizeof(void *), TRUE
}, /* WS_LISTENER_PROPERTY_CUSTOM_LISTENER_INSTANCE */
68 { sizeof(WS_DISALLOWED_USER_AGENT_SUBSTRINGS
), FALSE
} /* WS_LISTENER_PROPERTY_DISALLOWED_USER_AGENT */
76 WS_CHANNEL_BINDING binding
;
77 WS_LISTENER_STATE state
;
86 struct prop prop
[sizeof(listener_props
)/sizeof(listener_props
[0])];
89 #define LISTENER_MAGIC (('L' << 24) | ('I' << 16) | ('S' << 8) | 'T')
91 static struct listener
*alloc_listener(void)
93 static const ULONG count
= sizeof(listener_props
)/sizeof(listener_props
[0]);
95 ULONG size
= sizeof(*ret
) + prop_size( listener_props
, count
);
97 if (!(ret
= heap_alloc_zero( size
))) return NULL
;
99 ret
->magic
= LISTENER_MAGIC
;
100 InitializeCriticalSection( &ret
->cs
);
101 ret
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": listener.cs");
103 prop_init( listener_props
, count
, ret
->prop
, &ret
[1] );
104 ret
->prop_count
= count
;
108 static void reset_listener( struct listener
*listener
)
110 listener
->state
= WS_LISTENER_STATE_CREATED
;
112 switch (listener
->binding
)
114 case WS_TCP_CHANNEL_BINDING
:
115 closesocket( listener
->u
.tcp
.socket
);
116 listener
->u
.tcp
.socket
= -1;
123 static void free_listener( struct listener
*listener
)
125 reset_listener( listener
);
126 listener
->cs
.DebugInfo
->Spare
[0] = 0;
127 DeleteCriticalSection( &listener
->cs
);
128 heap_free( listener
);
131 static HRESULT
create_listener( WS_CHANNEL_TYPE type
, WS_CHANNEL_BINDING binding
,
132 const WS_LISTENER_PROPERTY
*properties
, ULONG count
, struct listener
**ret
)
134 struct listener
*listener
;
138 if (!(listener
= alloc_listener())) return E_OUTOFMEMORY
;
140 for (i
= 0; i
< count
; i
++)
142 hr
= prop_set( listener
->prop
, listener
->prop_count
, properties
[i
].id
, properties
[i
].value
,
143 properties
[i
].valueSize
);
146 free_listener( listener
);
151 listener
->type
= type
;
152 listener
->binding
= binding
;
154 switch (listener
->binding
)
156 case WS_TCP_CHANNEL_BINDING
:
157 listener
->u
.tcp
.socket
= -1;
167 /**************************************************************************
168 * WsCreateListener [webservices.@]
170 HRESULT WINAPI
WsCreateListener( WS_CHANNEL_TYPE type
, WS_CHANNEL_BINDING binding
,
171 const WS_LISTENER_PROPERTY
*properties
, ULONG count
,
172 const WS_SECURITY_DESCRIPTION
*desc
, WS_LISTENER
**handle
,
175 struct listener
*listener
;
178 TRACE( "%u %u %p %u %p %p %p\n", type
, binding
, properties
, count
, desc
, handle
, error
);
179 if (error
) FIXME( "ignoring error parameter\n" );
180 if (desc
) FIXME( "ignoring security description\n" );
182 if (!handle
) return E_INVALIDARG
;
184 if (type
!= WS_CHANNEL_TYPE_DUPLEX_SESSION
)
186 FIXME( "channel type %u not implemented\n", type
);
189 if (binding
!= WS_TCP_CHANNEL_BINDING
)
191 FIXME( "channel binding %u not implemented\n", binding
);
195 if ((hr
= create_listener( type
, binding
, properties
, count
, &listener
)) != S_OK
) return hr
;
197 *handle
= (WS_LISTENER
*)listener
;
201 /**************************************************************************
202 * WsFreeListener [webservices.@]
204 void WINAPI
WsFreeListener( WS_LISTENER
*handle
)
206 struct listener
*listener
= (struct listener
*)handle
;
208 TRACE( "%p\n", handle
);
210 if (!listener
) return;
212 EnterCriticalSection( &listener
->cs
);
214 if (listener
->magic
!= LISTENER_MAGIC
)
216 LeaveCriticalSection( &listener
->cs
);
222 LeaveCriticalSection( &listener
->cs
);
223 free_listener( listener
);
226 HRESULT
resolve_hostname( const WCHAR
*host
, USHORT port
, struct sockaddr
*addr
, int *addr_len
)
228 static const WCHAR fmtW
[] = {'%','u',0};
230 ADDRINFOW
*res
, *info
;
231 HRESULT hr
= WS_E_ADDRESS_NOT_AVAILABLE
;
234 sprintfW( service
, fmtW
, port
);
235 if (GetAddrInfoW( host
, service
, NULL
, &res
)) return HRESULT_FROM_WIN32( WSAGetLastError() );
238 while (info
&& info
->ai_family
!= AF_INET
&& info
->ai_family
!= AF_INET6
) info
= info
->ai_next
;
241 memcpy( addr
, info
->ai_addr
, info
->ai_addrlen
);
242 *addr_len
= info
->ai_addrlen
;
246 FreeAddrInfoW( res
);
250 HRESULT
parse_url( const WS_STRING
*str
, WS_URL_SCHEME_TYPE
*scheme
, WCHAR
**host
, USHORT
*port
)
256 if ((hr
= WsCreateHeap( 1 << 8, 0, NULL
, 0, &heap
, NULL
)) != S_OK
) return hr
;
257 if ((hr
= WsDecodeUrl( str
, 0, heap
, (WS_URL
**)&url
, NULL
)) != S_OK
)
263 if (url
->host
.length
== 1 && (url
->host
.chars
[0] == '+' || url
->host
.chars
[0] == '*')) *host
= NULL
;
266 if (!(*host
= heap_alloc( (url
->host
.length
+ 1) * sizeof(WCHAR
) )))
269 return E_OUTOFMEMORY
;
271 memcpy( *host
, url
->host
.chars
, url
->host
.length
* sizeof(WCHAR
) );
272 (*host
)[url
->host
.length
] = 0;
274 *scheme
= url
->url
.scheme
;
281 static HRESULT
open_listener_tcp( struct listener
*listener
, const WS_STRING
*url
)
283 struct sockaddr_storage storage
;
284 struct sockaddr
*addr
= (struct sockaddr
*)&storage
;
286 WS_URL_SCHEME_TYPE scheme
;
291 if ((hr
= parse_url( url
, &scheme
, &host
, &port
)) != S_OK
) return hr
;
292 if (scheme
!= WS_URL_NETTCP_SCHEME_TYPE
)
295 return WS_E_INVALID_ENDPOINT_URL
;
300 hr
= resolve_hostname( host
, port
, addr
, &addr_len
);
302 if (hr
!= S_OK
) return hr
;
304 if ((listener
->u
.tcp
.socket
= socket( addr
->sa_family
, SOCK_STREAM
, 0 )) == -1)
305 return HRESULT_FROM_WIN32( WSAGetLastError() );
307 if (bind( listener
->u
.tcp
.socket
, addr
, addr_len
) < 0)
309 closesocket( listener
->u
.tcp
.socket
);
310 listener
->u
.tcp
.socket
= -1;
311 return HRESULT_FROM_WIN32( WSAGetLastError() );
314 if (listen( listener
->u
.tcp
.socket
, 0 ) < 0)
316 closesocket( listener
->u
.tcp
.socket
);
317 listener
->u
.tcp
.socket
= -1;
318 return HRESULT_FROM_WIN32( WSAGetLastError() );
321 listener
->state
= WS_LISTENER_STATE_OPEN
;
325 static HRESULT
open_listener( struct listener
*listener
, const WS_STRING
*url
)
327 switch (listener
->binding
)
329 case WS_TCP_CHANNEL_BINDING
:
330 return open_listener_tcp( listener
, url
);
333 ERR( "unhandled binding %u\n", listener
->binding
);
338 /**************************************************************************
339 * WsOpenListener [webservices.@]
341 HRESULT WINAPI
WsOpenListener( WS_LISTENER
*handle
, WS_STRING
*url
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
343 struct listener
*listener
= (struct listener
*)handle
;
346 TRACE( "%p %s %p %p\n", handle
, url
? debugstr_wn(url
->chars
, url
->length
) : "null", ctx
, error
);
347 if (error
) FIXME( "ignoring error parameter\n" );
348 if (ctx
) FIXME( "ignoring ctx parameter\n" );
350 if (!listener
|| !url
) return E_INVALIDARG
;
352 EnterCriticalSection( &listener
->cs
);
354 if (listener
->magic
!= LISTENER_MAGIC
)
356 LeaveCriticalSection( &listener
->cs
);
360 if (listener
->state
!= WS_LISTENER_STATE_CREATED
)
362 LeaveCriticalSection( &listener
->cs
);
363 return WS_E_INVALID_OPERATION
;
366 hr
= open_listener( listener
, url
);
368 LeaveCriticalSection( &listener
->cs
);
372 static void close_listener( struct listener
*listener
)
374 reset_listener( listener
);
375 listener
->state
= WS_LISTENER_STATE_CLOSED
;
378 /**************************************************************************
379 * WsCloseListener [webservices.@]
381 HRESULT WINAPI
WsCloseListener( WS_LISTENER
*handle
, const WS_ASYNC_CONTEXT
*ctx
, WS_ERROR
*error
)
383 struct listener
*listener
= (struct listener
*)handle
;
385 TRACE( "%p %p %p\n", handle
, ctx
, error
);
386 if (error
) FIXME( "ignoring error parameter\n" );
387 if (ctx
) FIXME( "ignoring ctx parameter\n" );
389 if (!listener
) return E_INVALIDARG
;
391 EnterCriticalSection( &listener
->cs
);
393 if (listener
->magic
!= LISTENER_MAGIC
)
395 LeaveCriticalSection( &listener
->cs
);
399 close_listener( listener
);
401 LeaveCriticalSection( &listener
->cs
);
405 /**************************************************************************
406 * WsResetListener [webservices.@]
408 HRESULT WINAPI
WsResetListener( WS_LISTENER
*handle
, WS_ERROR
*error
)
410 struct listener
*listener
= (struct listener
*)handle
;
412 TRACE( "%p %p\n", handle
, error
);
413 if (error
) FIXME( "ignoring error parameter\n" );
415 if (!listener
) return E_INVALIDARG
;
417 EnterCriticalSection( &listener
->cs
);
419 if (listener
->magic
!= LISTENER_MAGIC
)
421 LeaveCriticalSection( &listener
->cs
);
425 if (listener
->state
!= WS_LISTENER_STATE_CREATED
&& listener
->state
!= WS_LISTENER_STATE_CLOSED
)
427 LeaveCriticalSection( &listener
->cs
);
428 return WS_E_INVALID_OPERATION
;
431 reset_listener( listener
);
433 LeaveCriticalSection( &listener
->cs
);
437 /**************************************************************************
438 * WsGetListenerProperty [webservices.@]
440 HRESULT WINAPI
WsGetListenerProperty( WS_LISTENER
*handle
, WS_LISTENER_PROPERTY_ID id
, void *buf
,
441 ULONG size
, WS_ERROR
*error
)
443 struct listener
*listener
= (struct listener
*)handle
;
446 TRACE( "%p %u %p %u %p\n", handle
, id
, buf
, size
, error
);
447 if (error
) FIXME( "ignoring error parameter\n" );
449 if (!listener
) return E_INVALIDARG
;
451 EnterCriticalSection( &listener
->cs
);
453 if (listener
->magic
!= LISTENER_MAGIC
)
455 LeaveCriticalSection( &listener
->cs
);
461 case WS_LISTENER_PROPERTY_STATE
:
462 if (!buf
|| size
!= sizeof(listener
->state
)) hr
= E_INVALIDARG
;
463 else *(WS_LISTENER_STATE
*)buf
= listener
->state
;
466 case WS_LISTENER_PROPERTY_CHANNEL_TYPE
:
467 if (!buf
|| size
!= sizeof(listener
->type
)) hr
= E_INVALIDARG
;
468 else *(WS_CHANNEL_TYPE
*)buf
= listener
->type
;
471 case WS_LISTENER_PROPERTY_CHANNEL_BINDING
:
472 if (!buf
|| size
!= sizeof(listener
->binding
)) hr
= E_INVALIDARG
;
473 else *(WS_CHANNEL_BINDING
*)buf
= listener
->binding
;
477 hr
= prop_get( listener
->prop
, listener
->prop_count
, id
, buf
, size
);
480 LeaveCriticalSection( &listener
->cs
);
484 /**************************************************************************
485 * WsSetListenerProperty [webservices.@]
487 HRESULT WINAPI
WsSetListenerProperty( WS_LISTENER
*handle
, WS_LISTENER_PROPERTY_ID id
, const void *value
,
488 ULONG size
, WS_ERROR
*error
)
490 struct listener
*listener
= (struct listener
*)handle
;
493 TRACE( "%p %u %p %u\n", handle
, id
, value
, size
);
494 if (error
) FIXME( "ignoring error parameter\n" );
496 if (!listener
) return E_INVALIDARG
;
498 EnterCriticalSection( &listener
->cs
);
500 if (listener
->magic
!= LISTENER_MAGIC
)
502 LeaveCriticalSection( &listener
->cs
);
506 hr
= prop_set( listener
->prop
, listener
->prop_count
, id
, value
, size
);
508 LeaveCriticalSection( &listener
->cs
);
512 /**************************************************************************
513 * WsAcceptChannel [webservices.@]
515 HRESULT WINAPI
WsAcceptChannel( WS_LISTENER
*handle
, WS_CHANNEL
*channel_handle
, const WS_ASYNC_CONTEXT
*ctx
,
518 struct listener
*listener
= (struct listener
*)handle
;
521 TRACE( "%p %p %p %p\n", handle
, channel_handle
, ctx
, error
);
522 if (error
) FIXME( "ignoring error parameter\n" );
523 if (ctx
) FIXME( "ignoring ctx parameter\n" );
525 if (!listener
|| !channel_handle
) return E_INVALIDARG
;
527 EnterCriticalSection( &listener
->cs
);
529 if (listener
->magic
!= LISTENER_MAGIC
)
531 LeaveCriticalSection( &listener
->cs
);
535 if (listener
->state
!= WS_LISTENER_STATE_OPEN
)
537 LeaveCriticalSection( &listener
->cs
);
538 return WS_E_INVALID_OPERATION
;
541 switch (listener
->binding
)
543 case WS_TCP_CHANNEL_BINDING
:
544 hr
= channel_accept_tcp( listener
->u
.tcp
.socket
, channel_handle
);
548 FIXME( "listener binding %u not supported\n", listener
->binding
);
553 LeaveCriticalSection( &listener
->cs
);