2 * Web Services on Devices
4 * Copyright 2017-2018 Owen Rudge for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wsdapi_internal.h"
26 #include "wine/debug.h"
27 #include "wine/heap.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi
);
33 #define SEND_ADDRESS_IPV4 0xEFFFFFFA /* 239.255.255.250 */
34 #define SEND_PORT 3702
36 static UCHAR send_address_ipv6
[] = {0xFF,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0xC}; /* FF02::C */
38 #define UNICAST_UDP_REPEAT 1
39 #define MULTICAST_UDP_REPEAT 2
40 #define UDP_MIN_DELAY 50
41 #define UDP_MAX_DELAY 250
42 #define UDP_UPPER_DELAY 500
44 static void send_message(SOCKET s
, char *data
, int length
, SOCKADDR_STORAGE
*dest
, int max_initial_delay
, int repeat
)
49 /* Sleep for a random amount of time before sending the message */
50 if (max_initial_delay
> 0)
52 BCryptGenRandom(NULL
, (BYTE
*) &delay
, sizeof(UINT
), BCRYPT_USE_SYSTEM_PREFERRED_RNG
);
53 Sleep(delay
% max_initial_delay
);
56 len
= (dest
->ss_family
== AF_INET6
) ? sizeof(SOCKADDR_IN6
) : sizeof(SOCKADDR_IN
);
58 if (sendto(s
, data
, length
, 0, (SOCKADDR
*) dest
, len
) == SOCKET_ERROR
)
59 WARN("Unable to send data to socket: %d\n", WSAGetLastError());
61 if (repeat
-- <= 0) return;
63 BCryptGenRandom(NULL
, (BYTE
*) &delay
, sizeof(UINT
), BCRYPT_USE_SYSTEM_PREFERRED_RNG
);
64 delay
= delay
% (UDP_MAX_DELAY
- UDP_MIN_DELAY
+ 1) + UDP_MIN_DELAY
;
70 if (sendto(s
, data
, length
, 0, (SOCKADDR
*) dest
, len
) == SOCKET_ERROR
)
71 WARN("Unable to send data to socket: %d\n", WSAGetLastError());
73 if (repeat
-- <= 0) break;
74 delay
= min(delay
* 2, UDP_UPPER_DELAY
);
78 typedef struct sending_thread_params
83 SOCKADDR_STORAGE dest
;
84 int max_initial_delay
;
85 } sending_thread_params
;
87 static DWORD WINAPI
sending_thread(LPVOID lpParam
)
89 sending_thread_params
*params
= (sending_thread_params
*) lpParam
;
91 send_message(params
->sock
, params
->data
, params
->length
, ¶ms
->dest
, params
->max_initial_delay
,
92 MULTICAST_UDP_REPEAT
);
93 closesocket(params
->sock
);
95 heap_free(params
->data
);
101 static BOOL
send_udp_multicast_of_type(char *data
, int length
, int max_initial_delay
, ULONG family
)
103 IP_ADAPTER_ADDRESSES
*adapter_addresses
= NULL
, *adapter_addr
;
104 static const struct in6_addr i_addr_zero
;
105 sending_thread_params
*send_params
;
106 ULONG bufferSize
= 0;
109 HANDLE thread_handle
;
114 /* Get size of buffer for adapters */
115 retval
= GetAdaptersAddresses(family
, 0, NULL
, NULL
, &bufferSize
);
117 if (retval
!= ERROR_BUFFER_OVERFLOW
)
119 WARN("GetAdaptorsAddresses failed with error %08x\n", retval
);
123 adapter_addresses
= (IP_ADAPTER_ADDRESSES
*) heap_alloc(bufferSize
);
125 if (adapter_addresses
== NULL
)
127 WARN("Out of memory allocating space for adapter information\n");
131 /* Get list of adapters */
132 retval
= GetAdaptersAddresses(family
, 0, NULL
, adapter_addresses
, &bufferSize
);
134 if (retval
!= ERROR_SUCCESS
)
136 WARN("GetAdaptorsAddresses failed with error %08x\n", retval
);
140 for (adapter_addr
= adapter_addresses
; adapter_addr
!= NULL
; adapter_addr
= adapter_addr
->Next
)
142 if (adapter_addr
->FirstUnicastAddress
== NULL
)
144 TRACE("No address found for adaptor '%s' (%p)\n", debugstr_a(adapter_addr
->AdapterName
), adapter_addr
);
148 sockaddr
= adapter_addr
->FirstUnicastAddress
->Address
.lpSockaddr
;
150 /* Create a socket and bind to the adapter address */
151 s
= socket(family
, SOCK_DGRAM
, IPPROTO_UDP
);
153 if (s
== INVALID_SOCKET
)
155 WARN("Unable to create socket: %d\n", WSAGetLastError());
159 if (bind(s
, sockaddr
, adapter_addr
->FirstUnicastAddress
->Address
.iSockaddrLength
) == SOCKET_ERROR
)
161 WARN("Unable to bind to socket (adaptor '%s' (%p)): %d\n", debugstr_a(adapter_addr
->AdapterName
),
162 adapter_addr
, WSAGetLastError());
167 /* Set the multicast interface and TTL value */
168 setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &i_addr_zero
,
169 (family
== AF_INET6
) ? sizeof(struct in6_addr
) : sizeof(struct in_addr
));
170 setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
172 /* Set up the thread parameters */
173 send_params
= heap_alloc(sizeof(*send_params
));
175 send_params
->data
= heap_alloc(length
);
176 memcpy(send_params
->data
, data
, length
);
177 send_params
->length
= length
;
178 send_params
->sock
= s
;
179 send_params
->max_initial_delay
= max_initial_delay
;
181 memset(&send_params
->dest
, 0, sizeof(SOCKADDR_STORAGE
));
182 send_params
->dest
.ss_family
= family
;
184 if (family
== AF_INET
)
186 SOCKADDR_IN
*sockaddr4
= (SOCKADDR_IN
*)&send_params
->dest
;
188 sockaddr4
->sin_port
= htons(SEND_PORT
);
189 sockaddr4
->sin_addr
.S_un
.S_addr
= htonl(SEND_ADDRESS_IPV4
);
193 SOCKADDR_IN6
*sockaddr6
= (SOCKADDR_IN6
*)&send_params
->dest
;
195 sockaddr6
->sin6_port
= htons(SEND_PORT
);
196 memcpy(&sockaddr6
->sin6_addr
, &send_address_ipv6
, sizeof(send_address_ipv6
));
199 thread_handle
= CreateThread(NULL
, 0, sending_thread
, send_params
, 0, NULL
);
201 if (thread_handle
== NULL
)
203 WARN("CreateThread failed (error %d)\n", GetLastError());
206 heap_free(send_params
->data
);
207 heap_free(send_params
);
212 CloseHandle(thread_handle
);
218 heap_free(adapter_addresses
);
223 BOOL
send_udp_multicast(IWSDiscoveryPublisherImpl
*impl
, char *data
, int length
, int max_initial_delay
)
225 if ((impl
->addressFamily
& WSDAPI_ADDRESSFAMILY_IPV4
) &&
226 (!send_udp_multicast_of_type(data
, length
,max_initial_delay
, AF_INET
))) return FALSE
;
228 if ((impl
->addressFamily
& WSDAPI_ADDRESSFAMILY_IPV6
) &&
229 (!send_udp_multicast_of_type(data
, length
, max_initial_delay
, AF_INET6
))) return FALSE
;
234 static int join_multicast_group(SOCKET s
, SOCKADDR_STORAGE
*group
, SOCKADDR_STORAGE
*iface
)
236 int level
, optname
, optlen
;
237 struct ipv6_mreq mreqv6
;
238 struct ip_mreq mreqv4
;
241 if (iface
->ss_family
== AF_INET6
)
243 level
= IPPROTO_IPV6
;
244 optname
= IPV6_ADD_MEMBERSHIP
;
245 optval
= (char *)&mreqv6
;
246 optlen
= sizeof(mreqv6
);
248 mreqv6
.ipv6mr_multiaddr
= ((SOCKADDR_IN6
*)group
)->sin6_addr
;
249 mreqv6
.ipv6mr_interface
= ((SOCKADDR_IN6
*)iface
)->sin6_scope_id
;
254 optname
= IP_ADD_MEMBERSHIP
;
255 optval
= (char *)&mreqv4
;
256 optlen
= sizeof(mreqv4
);
258 mreqv4
.imr_multiaddr
.s_addr
= ((SOCKADDR_IN
*)group
)->sin_addr
.s_addr
;
259 mreqv4
.imr_interface
.s_addr
= ((SOCKADDR_IN
*)iface
)->sin_addr
.s_addr
;
262 return setsockopt(s
, level
, optname
, optval
, optlen
);
265 static int set_send_interface(SOCKET s
, SOCKADDR_STORAGE
*iface
)
267 int level
, optname
, optlen
;
270 if (iface
->ss_family
== AF_INET6
)
272 level
= IPPROTO_IPV6
;
273 optname
= IPV6_MULTICAST_IF
;
274 optval
= (char *) &((SOCKADDR_IN6
*)iface
)->sin6_scope_id
;
275 optlen
= sizeof(((SOCKADDR_IN6
*)iface
)->sin6_scope_id
);
280 optname
= IP_MULTICAST_IF
;
281 optval
= (char *) &((SOCKADDR_IN
*)iface
)->sin_addr
.s_addr
;
282 optlen
= sizeof(((SOCKADDR_IN
*)iface
)->sin_addr
.s_addr
);
285 return setsockopt(s
, level
, optname
, optval
, optlen
);
288 typedef struct listener_thread_params
290 IWSDiscoveryPublisherImpl
*impl
;
291 SOCKET listening_socket
;
293 } listener_thread_params
;
295 static HRESULT
process_received_message(listener_thread_params
*params
, char *message
, int message_len
,
296 SOCKADDR_STORAGE
*source_addr
)
298 IWSDUdpMessageParameters
*msg_params
= NULL
;
299 IWSDUdpAddress
*remote_addr
= NULL
;
300 struct notificationSink
*sink
;
301 WSD_SOAP_MESSAGE
*msg
= NULL
;
305 ret
= read_message(params
->impl
, message
, message_len
, &msg
, &msg_type
);
306 if (FAILED(ret
)) return ret
;
311 TRACE("Received probe message\n");
313 ret
= WSDCreateUdpMessageParameters(&msg_params
);
317 ERR("Unable to create IWSDUdpMessageParameters, not processing message.\n");
321 ret
= WSDCreateUdpAddress(&remote_addr
);
325 ERR("Unable to create IWSDUdpAddress, not processing message.\n");
329 IWSDUdpAddress_SetSockaddr(remote_addr
, source_addr
);
330 IWSDUdpMessageParameters_SetRemoteAddress(msg_params
, (IWSDAddress
*)remote_addr
);
332 EnterCriticalSection(¶ms
->impl
->notification_sink_critical_section
);
334 LIST_FOR_EACH_ENTRY(sink
, ¶ms
->impl
->notificationSinks
, struct notificationSink
, entry
)
336 IWSDiscoveryPublisherNotify_ProbeHandler(sink
->notificationSink
, msg
, (IWSDMessageParameters
*)msg_params
);
339 LeaveCriticalSection(¶ms
->impl
->notification_sink_critical_section
);
345 WSDFreeLinkedMemory(msg
);
347 if (remote_addr
!= NULL
) IWSDUdpAddress_Release(remote_addr
);
348 if (msg_params
!= NULL
) IWSDUdpMessageParameters_Release(msg_params
);
353 #define RECEIVE_BUFFER_SIZE 65536
355 static DWORD WINAPI
listening_thread(LPVOID params
)
357 listener_thread_params
*parameter
= (listener_thread_params
*)params
;
358 int bytes_received
, address_len
, err
;
359 SOCKADDR_STORAGE source_addr
;
362 buffer
= heap_alloc(RECEIVE_BUFFER_SIZE
);
363 address_len
= parameter
->ipv6
? sizeof(SOCKADDR_IN6
) : sizeof(SOCKADDR_IN
);
365 while (parameter
->impl
->publisherStarted
)
367 bytes_received
= recvfrom(parameter
->listening_socket
, buffer
, RECEIVE_BUFFER_SIZE
, 0,
368 (LPSOCKADDR
) &source_addr
, &address_len
);
370 if (bytes_received
== SOCKET_ERROR
)
372 err
= WSAGetLastError();
374 if (err
!= WSAETIMEDOUT
)
376 WARN("Received error when trying to read from socket: %d. Stopping listener.\n", err
);
382 process_received_message(parameter
, buffer
, bytes_received
, &source_addr
);
386 /* The publisher has been stopped */
387 closesocket(parameter
->listening_socket
);
390 heap_free(parameter
);
395 static int start_listening(IWSDiscoveryPublisherImpl
*impl
, SOCKADDR_STORAGE
*bind_address
)
397 SOCKADDR_STORAGE multicast_addr
, bind_addr
, interface_addr
;
398 listener_thread_params
*parameter
= NULL
;
399 const DWORD receive_timeout
= 5000;
400 const UINT reuse_addr
= 1;
401 HANDLE thread_handle
;
405 TRACE("(%p, %p) family %d\n", impl
, bind_address
, bind_address
->ss_family
);
407 /* Populate the multicast address */
408 ZeroMemory(&multicast_addr
, sizeof(SOCKADDR_STORAGE
));
410 if (bind_address
->ss_family
== AF_INET
)
412 SOCKADDR_IN
*sockaddr4
= (SOCKADDR_IN
*)&multicast_addr
;
414 sockaddr4
->sin_port
= htons(SEND_PORT
);
415 sockaddr4
->sin_addr
.S_un
.S_addr
= htonl(SEND_ADDRESS_IPV4
);
416 address_length
= sizeof(SOCKADDR_IN
);
420 SOCKADDR_IN6
*sockaddr6
= (SOCKADDR_IN6
*)&multicast_addr
;
422 sockaddr6
->sin6_port
= htons(SEND_PORT
);
423 memcpy(&sockaddr6
->sin6_addr
, &send_address_ipv6
, sizeof(send_address_ipv6
));
424 address_length
= sizeof(SOCKADDR_IN6
);
427 /* Update the port for the binding address */
428 memcpy(&bind_addr
, bind_address
, address_length
);
429 ((SOCKADDR_IN
*)&bind_addr
)->sin_port
= htons(SEND_PORT
);
431 /* Update the port for the interface address */
432 memcpy(&interface_addr
, bind_address
, address_length
);
433 ((SOCKADDR_IN
*)&interface_addr
)->sin_port
= htons(0);
435 /* Create the socket */
436 s
= socket(bind_address
->ss_family
, SOCK_DGRAM
, IPPROTO_UDP
);
438 if (s
== INVALID_SOCKET
)
440 WARN("socket() failed (error %d)\n", WSAGetLastError());
444 /* Ensure the socket can be reused */
445 if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, (const char *)&reuse_addr
, sizeof(reuse_addr
)) == SOCKET_ERROR
)
447 WARN("setsockopt(SO_REUSEADDR) failed (error %d)\n", WSAGetLastError());
451 /* Bind the socket to the local interface so we can receive data */
452 if (bind(s
, (struct sockaddr
*)&bind_addr
, address_length
) == SOCKET_ERROR
)
454 WARN("bind() failed (error %d)\n", WSAGetLastError());
458 /* Join the multicast group */
459 if (join_multicast_group(s
, &multicast_addr
, &interface_addr
) == SOCKET_ERROR
)
461 WARN("Unable to join multicast group (error %d)\n", WSAGetLastError());
465 /* Set the outgoing interface */
466 if (set_send_interface(s
, &interface_addr
) == SOCKET_ERROR
)
468 WARN("Unable to set outgoing interface (error %d)\n", WSAGetLastError());
472 /* Set a 5-second receive timeout */
473 if (setsockopt(s
, SOL_SOCKET
, SO_RCVTIMEO
, (const char *)&receive_timeout
, sizeof(receive_timeout
)) == SOCKET_ERROR
)
475 WARN("setsockopt(SO_RCVTIME0) failed (error %d)\n", WSAGetLastError());
479 /* Allocate memory for thread parameters */
480 parameter
= heap_alloc(sizeof(listener_thread_params
));
482 parameter
->impl
= impl
;
483 parameter
->listening_socket
= s
;
484 parameter
->ipv6
= (bind_address
->ss_family
== AF_INET6
);
486 thread_handle
= CreateThread(NULL
, 0, listening_thread
, parameter
, 0, NULL
);
488 if (thread_handle
== NULL
)
490 WARN("CreateThread failed (error %d)\n", GetLastError());
494 impl
->thread_handles
[impl
->num_thread_handles
] = thread_handle
;
495 impl
->num_thread_handles
++;
501 heap_free(parameter
);
506 static BOOL
start_listening_on_all_addresses(IWSDiscoveryPublisherImpl
*impl
, ULONG family
)
508 IP_ADAPTER_ADDRESSES
*adapter_addresses
= NULL
, *adapter_address
;
509 int valid_listeners
= 0;
510 ULONG bufferSize
= 0;
513 ret
= GetAdaptersAddresses(family
, 0, NULL
, NULL
, &bufferSize
); /* family should be AF_INET or AF_INET6 */
515 if (ret
!= ERROR_BUFFER_OVERFLOW
)
517 WARN("GetAdaptorsAddresses failed with error %08x\n", ret
);
521 /* Get size of buffer for adapters */
522 adapter_addresses
= (IP_ADAPTER_ADDRESSES
*)heap_alloc(bufferSize
);
524 if (adapter_addresses
== NULL
)
526 WARN("Out of memory allocating space for adapter information\n");
530 /* Get list of adapters */
531 ret
= GetAdaptersAddresses(family
, 0, NULL
, adapter_addresses
, &bufferSize
);
533 if (ret
!= ERROR_SUCCESS
)
535 WARN("GetAdaptorsAddresses failed with error %08x\n", ret
);
539 for (adapter_address
= adapter_addresses
; adapter_address
!= NULL
; adapter_address
= adapter_address
->Next
)
541 if (impl
->num_thread_handles
>= MAX_WSD_THREADS
)
543 WARN("Exceeded maximum number of supported listener threads; too many network interfaces.\n");
547 if (adapter_address
->FirstUnicastAddress
== NULL
)
549 TRACE("No address found for adaptor '%s' (%p)\n", adapter_address
->AdapterName
, adapter_address
);
553 valid_listeners
+= start_listening(impl
, (SOCKADDR_STORAGE
*)adapter_address
->FirstUnicastAddress
->Address
.lpSockaddr
);
557 heap_free(adapter_addresses
);
558 return (ret
== ERROR_SUCCESS
) && (valid_listeners
> 0);
561 HRESULT
send_udp_unicast(char *data
, int length
, IWSDUdpAddress
*remote_addr
, int max_initial_delay
)
563 SOCKADDR_STORAGE address
;
567 ZeroMemory(&address
, sizeof(SOCKADDR_STORAGE
));
569 ret
= IWSDUdpAddress_GetSockaddr(remote_addr
, &address
);
573 WARN("No sockaddr specified in send_udp_unicast\n");
577 /* Create a socket and bind to the adapter address */
578 s
= socket(address
.ss_family
, SOCK_DGRAM
, IPPROTO_UDP
);
580 if (s
== INVALID_SOCKET
)
582 int error
= WSAGetLastError();
583 WARN("Unable to create socket: %d\n", error
);
584 return HRESULT_FROM_WIN32(error
);
587 send_message(s
, data
, length
, &address
, max_initial_delay
, UNICAST_UDP_REPEAT
);
593 void terminate_networking(IWSDiscoveryPublisherImpl
*impl
)
595 BOOL needsCleanup
= impl
->publisherStarted
;
598 impl
->publisherStarted
= FALSE
;
599 WaitForMultipleObjects(impl
->num_thread_handles
, impl
->thread_handles
, TRUE
, INFINITE
);
601 for (i
= 0; i
< impl
->num_thread_handles
; i
++)
603 CloseHandle(impl
->thread_handles
[i
]);
610 BOOL
init_networking(IWSDiscoveryPublisherImpl
*impl
)
613 int ret
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
617 WARN("WSAStartup failed with error: %d\n", ret
);
621 impl
->publisherStarted
= TRUE
;
623 if ((impl
->addressFamily
& WSDAPI_ADDRESSFAMILY_IPV4
) && (!start_listening_on_all_addresses(impl
, AF_INET
)))
626 if ((impl
->addressFamily
& WSDAPI_ADDRESSFAMILY_IPV6
) && (!start_listening_on_all_addresses(impl
, AF_INET6
)))
632 terminate_networking(impl
);