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"
30 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi
);
32 #define SEND_ADDRESS_IPV4 0xEFFFFFFA /* 239.255.255.250 */
33 #define SEND_PORT 3702
35 static UCHAR send_address_ipv6
[] = {0xFF,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0xC}; /* FF02::C */
37 #define UNICAST_UDP_REPEAT 1
38 #define MULTICAST_UDP_REPEAT 2
39 #define UDP_MIN_DELAY 50
40 #define UDP_MAX_DELAY 250
41 #define UDP_UPPER_DELAY 500
43 static void send_message(SOCKET s
, char *data
, int length
, SOCKADDR_STORAGE
*dest
, int max_initial_delay
, int repeat
)
48 /* Sleep for a random amount of time before sending the message */
49 if (max_initial_delay
> 0)
51 BCryptGenRandom(NULL
, (BYTE
*) &delay
, sizeof(UINT
), BCRYPT_USE_SYSTEM_PREFERRED_RNG
);
52 Sleep(delay
% max_initial_delay
);
55 len
= (dest
->ss_family
== AF_INET6
) ? sizeof(SOCKADDR_IN6
) : sizeof(SOCKADDR_IN
);
57 if (sendto(s
, data
, length
, 0, (SOCKADDR
*) dest
, len
) == SOCKET_ERROR
)
58 WARN("Unable to send data to socket: %d\n", WSAGetLastError());
60 if (repeat
-- <= 0) return;
62 BCryptGenRandom(NULL
, (BYTE
*) &delay
, sizeof(UINT
), BCRYPT_USE_SYSTEM_PREFERRED_RNG
);
63 delay
= delay
% (UDP_MAX_DELAY
- UDP_MIN_DELAY
+ 1) + UDP_MIN_DELAY
;
69 if (sendto(s
, data
, length
, 0, (SOCKADDR
*) dest
, len
) == SOCKET_ERROR
)
70 WARN("Unable to send data to socket: %d\n", WSAGetLastError());
72 if (repeat
-- <= 0) break;
73 delay
= min(delay
* 2, UDP_UPPER_DELAY
);
77 typedef struct sending_thread_params
82 SOCKADDR_STORAGE dest
;
83 int max_initial_delay
;
84 } sending_thread_params
;
86 static DWORD WINAPI
sending_thread(LPVOID lpParam
)
88 sending_thread_params
*params
= (sending_thread_params
*) lpParam
;
90 send_message(params
->sock
, params
->data
, params
->length
, ¶ms
->dest
, params
->max_initial_delay
,
91 MULTICAST_UDP_REPEAT
);
92 closesocket(params
->sock
);
100 static IP_ADAPTER_ADDRESSES
*get_adapters(ULONG family
)
102 ULONG err
, size
= 4096;
103 IP_ADAPTER_ADDRESSES
*tmp
, *ret
;
105 if (!(ret
= malloc( size
))) return NULL
;
106 err
= GetAdaptersAddresses( family
, 0, NULL
, ret
, &size
);
107 while (err
== ERROR_BUFFER_OVERFLOW
)
109 if (!(tmp
= realloc( ret
, size
))) break;
111 err
= GetAdaptersAddresses( family
, 0, NULL
, ret
, &size
);
113 if (err
== ERROR_SUCCESS
) return ret
;
118 static BOOL
send_udp_multicast_of_type(char *data
, int length
, int max_initial_delay
, ULONG family
)
120 IP_ADAPTER_ADDRESSES
*adapter_addresses
, *adapter_addr
;
121 static const struct in6_addr i_addr_zero
;
122 sending_thread_params
*send_params
;
124 HANDLE thread_handle
;
128 adapter_addresses
= get_adapters(family
);
129 if (!adapter_addresses
)
132 for (adapter_addr
= adapter_addresses
; adapter_addr
!= NULL
; adapter_addr
= adapter_addr
->Next
)
134 if (adapter_addr
->FirstUnicastAddress
== NULL
)
136 TRACE("No address found for adaptor '%s' (%p)\n", debugstr_a(adapter_addr
->AdapterName
), adapter_addr
);
140 sockaddr
= adapter_addr
->FirstUnicastAddress
->Address
.lpSockaddr
;
142 /* Create a socket and bind to the adapter address */
143 s
= socket(family
, SOCK_DGRAM
, IPPROTO_UDP
);
145 if (s
== INVALID_SOCKET
)
147 WARN("Unable to create socket: %d\n", WSAGetLastError());
151 if (bind(s
, sockaddr
, adapter_addr
->FirstUnicastAddress
->Address
.iSockaddrLength
) == SOCKET_ERROR
)
153 WARN("Unable to bind to socket (adaptor '%s' (%p)): %d\n", debugstr_a(adapter_addr
->AdapterName
),
154 adapter_addr
, WSAGetLastError());
159 /* Set the multicast interface and TTL value */
160 setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &i_addr_zero
,
161 (family
== AF_INET6
) ? sizeof(struct in6_addr
) : sizeof(struct in_addr
));
162 setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
164 /* Set up the thread parameters */
165 send_params
= malloc(sizeof(*send_params
));
167 send_params
->data
= malloc(length
);
168 memcpy(send_params
->data
, data
, length
);
169 send_params
->length
= length
;
170 send_params
->sock
= s
;
171 send_params
->max_initial_delay
= max_initial_delay
;
173 memset(&send_params
->dest
, 0, sizeof(SOCKADDR_STORAGE
));
174 send_params
->dest
.ss_family
= family
;
176 if (family
== AF_INET
)
178 SOCKADDR_IN
*sockaddr4
= (SOCKADDR_IN
*)&send_params
->dest
;
180 sockaddr4
->sin_port
= htons(SEND_PORT
);
181 sockaddr4
->sin_addr
.S_un
.S_addr
= htonl(SEND_ADDRESS_IPV4
);
185 SOCKADDR_IN6
*sockaddr6
= (SOCKADDR_IN6
*)&send_params
->dest
;
187 sockaddr6
->sin6_port
= htons(SEND_PORT
);
188 memcpy(&sockaddr6
->sin6_addr
, &send_address_ipv6
, sizeof(send_address_ipv6
));
191 thread_handle
= CreateThread(NULL
, 0, sending_thread
, send_params
, 0, NULL
);
193 if (thread_handle
== NULL
)
195 WARN("CreateThread failed (error %ld)\n", GetLastError());
198 free(send_params
->data
);
204 CloseHandle(thread_handle
);
207 free(adapter_addresses
);
211 BOOL
send_udp_multicast(IWSDiscoveryPublisherImpl
*impl
, char *data
, int length
, int max_initial_delay
)
213 if ((impl
->addressFamily
& WSDAPI_ADDRESSFAMILY_IPV4
) &&
214 (!send_udp_multicast_of_type(data
, length
,max_initial_delay
, AF_INET
))) return FALSE
;
216 if ((impl
->addressFamily
& WSDAPI_ADDRESSFAMILY_IPV6
) &&
217 (!send_udp_multicast_of_type(data
, length
, max_initial_delay
, AF_INET6
))) return FALSE
;
222 static int join_multicast_group(SOCKET s
, SOCKADDR_STORAGE
*group
, SOCKADDR_STORAGE
*iface
)
224 int level
, optname
, optlen
;
225 struct ipv6_mreq mreqv6
;
226 struct ip_mreq mreqv4
;
229 if (iface
->ss_family
== AF_INET6
)
231 level
= IPPROTO_IPV6
;
232 optname
= IPV6_ADD_MEMBERSHIP
;
233 optval
= (char *)&mreqv6
;
234 optlen
= sizeof(mreqv6
);
236 mreqv6
.ipv6mr_multiaddr
= ((SOCKADDR_IN6
*)group
)->sin6_addr
;
237 mreqv6
.ipv6mr_interface
= ((SOCKADDR_IN6
*)iface
)->sin6_scope_id
;
242 optname
= IP_ADD_MEMBERSHIP
;
243 optval
= (char *)&mreqv4
;
244 optlen
= sizeof(mreqv4
);
246 mreqv4
.imr_multiaddr
.s_addr
= ((SOCKADDR_IN
*)group
)->sin_addr
.s_addr
;
247 mreqv4
.imr_interface
.s_addr
= ((SOCKADDR_IN
*)iface
)->sin_addr
.s_addr
;
250 return setsockopt(s
, level
, optname
, optval
, optlen
);
253 static int set_send_interface(SOCKET s
, SOCKADDR_STORAGE
*iface
)
255 int level
, optname
, optlen
;
258 if (iface
->ss_family
== AF_INET6
)
260 level
= IPPROTO_IPV6
;
261 optname
= IPV6_MULTICAST_IF
;
262 optval
= (char *) &((SOCKADDR_IN6
*)iface
)->sin6_scope_id
;
263 optlen
= sizeof(((SOCKADDR_IN6
*)iface
)->sin6_scope_id
);
268 optname
= IP_MULTICAST_IF
;
269 optval
= (char *) &((SOCKADDR_IN
*)iface
)->sin_addr
.s_addr
;
270 optlen
= sizeof(((SOCKADDR_IN
*)iface
)->sin_addr
.s_addr
);
273 return setsockopt(s
, level
, optname
, optval
, optlen
);
276 typedef struct listener_thread_params
278 IWSDiscoveryPublisherImpl
*impl
;
279 SOCKET listening_socket
;
281 } listener_thread_params
;
283 static HRESULT
process_received_message(listener_thread_params
*params
, char *message
, int message_len
,
284 SOCKADDR_STORAGE
*source_addr
)
286 IWSDUdpMessageParameters
*msg_params
= NULL
;
287 IWSDUdpAddress
*remote_addr
= NULL
;
288 struct notificationSink
*sink
;
289 WSD_SOAP_MESSAGE
*msg
= NULL
;
293 ret
= read_message(params
->impl
, message
, message_len
, &msg
, &msg_type
);
294 if (FAILED(ret
)) return ret
;
299 TRACE("Received probe message\n");
301 ret
= WSDCreateUdpMessageParameters(&msg_params
);
305 ERR("Unable to create IWSDUdpMessageParameters, not processing message.\n");
309 ret
= WSDCreateUdpAddress(&remote_addr
);
313 ERR("Unable to create IWSDUdpAddress, not processing message.\n");
317 IWSDUdpAddress_SetSockaddr(remote_addr
, source_addr
);
318 IWSDUdpMessageParameters_SetRemoteAddress(msg_params
, (IWSDAddress
*)remote_addr
);
320 EnterCriticalSection(¶ms
->impl
->notification_sink_critical_section
);
322 LIST_FOR_EACH_ENTRY(sink
, ¶ms
->impl
->notificationSinks
, struct notificationSink
, entry
)
324 IWSDiscoveryPublisherNotify_ProbeHandler(sink
->notificationSink
, msg
, (IWSDMessageParameters
*)msg_params
);
327 LeaveCriticalSection(¶ms
->impl
->notification_sink_critical_section
);
333 WSDFreeLinkedMemory(msg
);
335 if (remote_addr
!= NULL
) IWSDUdpAddress_Release(remote_addr
);
336 if (msg_params
!= NULL
) IWSDUdpMessageParameters_Release(msg_params
);
341 #define RECEIVE_BUFFER_SIZE 65536
343 static DWORD WINAPI
listening_thread(LPVOID params
)
345 listener_thread_params
*parameter
= (listener_thread_params
*)params
;
346 int bytes_received
, address_len
, err
;
347 SOCKADDR_STORAGE source_addr
;
350 buffer
= malloc(RECEIVE_BUFFER_SIZE
);
351 address_len
= parameter
->ipv6
? sizeof(SOCKADDR_IN6
) : sizeof(SOCKADDR_IN
);
353 while (parameter
->impl
->publisherStarted
)
355 bytes_received
= recvfrom(parameter
->listening_socket
, buffer
, RECEIVE_BUFFER_SIZE
, 0,
356 (LPSOCKADDR
) &source_addr
, &address_len
);
358 if (bytes_received
== SOCKET_ERROR
)
360 err
= WSAGetLastError();
362 if (err
!= WSAETIMEDOUT
)
364 WARN("Received error when trying to read from socket: %d. Stopping listener.\n", err
);
370 process_received_message(parameter
, buffer
, bytes_received
, &source_addr
);
374 /* The publisher has been stopped */
375 closesocket(parameter
->listening_socket
);
383 static int start_listening(IWSDiscoveryPublisherImpl
*impl
, SOCKADDR_STORAGE
*bind_address
)
385 SOCKADDR_STORAGE multicast_addr
, bind_addr
, interface_addr
;
386 listener_thread_params
*parameter
= NULL
;
387 const DWORD receive_timeout
= 5000;
388 const UINT reuse_addr
= 1;
389 HANDLE thread_handle
;
393 TRACE("(%p, %p) family %d\n", impl
, bind_address
, bind_address
->ss_family
);
395 /* Populate the multicast address */
396 ZeroMemory(&multicast_addr
, sizeof(SOCKADDR_STORAGE
));
398 if (bind_address
->ss_family
== AF_INET
)
400 SOCKADDR_IN
*sockaddr4
= (SOCKADDR_IN
*)&multicast_addr
;
402 sockaddr4
->sin_port
= htons(SEND_PORT
);
403 sockaddr4
->sin_addr
.S_un
.S_addr
= htonl(SEND_ADDRESS_IPV4
);
404 address_length
= sizeof(SOCKADDR_IN
);
408 SOCKADDR_IN6
*sockaddr6
= (SOCKADDR_IN6
*)&multicast_addr
;
410 sockaddr6
->sin6_port
= htons(SEND_PORT
);
411 memcpy(&sockaddr6
->sin6_addr
, &send_address_ipv6
, sizeof(send_address_ipv6
));
412 address_length
= sizeof(SOCKADDR_IN6
);
415 /* Update the port for the binding address */
416 memcpy(&bind_addr
, bind_address
, address_length
);
417 ((SOCKADDR_IN
*)&bind_addr
)->sin_port
= htons(SEND_PORT
);
419 /* Update the port for the interface address */
420 memcpy(&interface_addr
, bind_address
, address_length
);
421 ((SOCKADDR_IN
*)&interface_addr
)->sin_port
= htons(0);
423 /* Create the socket */
424 s
= socket(bind_address
->ss_family
, SOCK_DGRAM
, IPPROTO_UDP
);
426 if (s
== INVALID_SOCKET
)
428 WARN("socket() failed (error %d)\n", WSAGetLastError());
432 /* Ensure the socket can be reused */
433 if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, (const char *)&reuse_addr
, sizeof(reuse_addr
)) == SOCKET_ERROR
)
435 WARN("setsockopt(SO_REUSEADDR) failed (error %d)\n", WSAGetLastError());
439 /* Bind the socket to the local interface so we can receive data */
440 if (bind(s
, (struct sockaddr
*)&bind_addr
, address_length
) == SOCKET_ERROR
)
442 WARN("bind() failed (error %d)\n", WSAGetLastError());
446 /* Join the multicast group */
447 if (join_multicast_group(s
, &multicast_addr
, &interface_addr
) == SOCKET_ERROR
)
449 WARN("Unable to join multicast group (error %d)\n", WSAGetLastError());
453 /* Set the outgoing interface */
454 if (set_send_interface(s
, &interface_addr
) == SOCKET_ERROR
)
456 WARN("Unable to set outgoing interface (error %d)\n", WSAGetLastError());
460 /* Set a 5-second receive timeout */
461 if (setsockopt(s
, SOL_SOCKET
, SO_RCVTIMEO
, (const char *)&receive_timeout
, sizeof(receive_timeout
)) == SOCKET_ERROR
)
463 WARN("setsockopt(SO_RCVTIME0) failed (error %d)\n", WSAGetLastError());
467 /* Allocate memory for thread parameters */
468 parameter
= malloc(sizeof(*parameter
));
470 parameter
->impl
= impl
;
471 parameter
->listening_socket
= s
;
472 parameter
->ipv6
= (bind_address
->ss_family
== AF_INET6
);
474 thread_handle
= CreateThread(NULL
, 0, listening_thread
, parameter
, 0, NULL
);
476 if (thread_handle
== NULL
)
478 WARN("CreateThread failed (error %ld)\n", GetLastError());
482 impl
->thread_handles
[impl
->num_thread_handles
] = thread_handle
;
483 impl
->num_thread_handles
++;
494 static BOOL
start_listening_on_all_addresses(IWSDiscoveryPublisherImpl
*impl
, ULONG family
)
496 IP_ADAPTER_ADDRESSES
*adapter_addresses
, *adapter_address
;
497 int valid_listeners
= 0;
499 adapter_addresses
= get_adapters(family
); /* family should be AF_INET or AF_INET6 */
500 if (!adapter_addresses
)
503 for (adapter_address
= adapter_addresses
; adapter_address
!= NULL
; adapter_address
= adapter_address
->Next
)
505 if (impl
->num_thread_handles
>= MAX_WSD_THREADS
)
507 WARN("Exceeded maximum number of supported listener threads; too many network interfaces.\n");
511 if (adapter_address
->FirstUnicastAddress
== NULL
)
513 TRACE("No address found for adaptor '%s' (%p)\n", adapter_address
->AdapterName
, adapter_address
);
517 valid_listeners
+= start_listening(impl
, (SOCKADDR_STORAGE
*)adapter_address
->FirstUnicastAddress
->Address
.lpSockaddr
);
521 free(adapter_addresses
);
522 return valid_listeners
> 0;
525 HRESULT
send_udp_unicast(char *data
, int length
, IWSDUdpAddress
*remote_addr
, int max_initial_delay
)
527 SOCKADDR_STORAGE address
;
531 ZeroMemory(&address
, sizeof(SOCKADDR_STORAGE
));
533 ret
= IWSDUdpAddress_GetSockaddr(remote_addr
, &address
);
537 WARN("No sockaddr specified in send_udp_unicast\n");
541 /* Create a socket and bind to the adapter address */
542 s
= socket(address
.ss_family
, SOCK_DGRAM
, IPPROTO_UDP
);
544 if (s
== INVALID_SOCKET
)
546 int error
= WSAGetLastError();
547 WARN("Unable to create socket: %d\n", error
);
548 return HRESULT_FROM_WIN32(error
);
551 send_message(s
, data
, length
, &address
, max_initial_delay
, UNICAST_UDP_REPEAT
);
557 void terminate_networking(IWSDiscoveryPublisherImpl
*impl
)
559 BOOL needsCleanup
= impl
->publisherStarted
;
562 impl
->publisherStarted
= FALSE
;
563 WaitForMultipleObjects(impl
->num_thread_handles
, impl
->thread_handles
, TRUE
, INFINITE
);
565 for (i
= 0; i
< impl
->num_thread_handles
; i
++)
567 CloseHandle(impl
->thread_handles
[i
]);
574 BOOL
init_networking(IWSDiscoveryPublisherImpl
*impl
)
577 int ret
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
581 WARN("WSAStartup failed with error: %d\n", ret
);
585 impl
->publisherStarted
= TRUE
;
587 if ((impl
->addressFamily
& WSDAPI_ADDRESSFAMILY_IPV4
) && (!start_listening_on_all_addresses(impl
, AF_INET
)))
590 if ((impl
->addressFamily
& WSDAPI_ADDRESSFAMILY_IPV6
) && (!start_listening_on_all_addresses(impl
, AF_INET6
)))
596 terminate_networking(impl
);