win32u: Respect per-monitor thread dpi awareness when getting window from point.
[wine.git] / dlls / wsdapi / network.c
blob97573c579193886563d81ee9fd62acbfa4c64724
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "wsdapi_internal.h"
26 #include "wine/debug.h"
27 #include "iphlpapi.h"
28 #include "bcrypt.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)
45 UINT delay;
46 int len;
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;
65 for (;;)
67 Sleep(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
79 char *data;
80 int length;
81 SOCKET sock;
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, &params->dest, params->max_initial_delay,
91 MULTICAST_UDP_REPEAT);
92 closesocket(params->sock);
94 free(params->data);
95 free(params);
97 return 0;
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;
110 ret = tmp;
111 err = GetAdaptersAddresses( family, 0, NULL, ret, &size );
113 if (err == ERROR_SUCCESS) return ret;
114 free( ret );
115 return NULL;
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;
123 LPSOCKADDR sockaddr;
124 HANDLE thread_handle;
125 const char ttl = 8;
126 SOCKET s;
128 adapter_addresses = get_adapters(family);
129 if (!adapter_addresses)
130 return FALSE;
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);
137 continue;
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());
148 continue;
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());
155 closesocket(s);
156 continue;
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);
183 else
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());
196 closesocket(s);
198 free(send_params->data);
199 free(send_params);
201 continue;
204 CloseHandle(thread_handle);
207 free(adapter_addresses);
208 return TRUE;
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;
219 return TRUE;
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;
227 char *optval;
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;
239 else
241 level = IPPROTO_IP;
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;
256 char *optval = NULL;
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);
265 else
267 level = IPPROTO_IP;
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;
280 BOOL ipv6;
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;
290 int msg_type;
291 HRESULT ret;
293 ret = read_message(params->impl, message, message_len, &msg, &msg_type);
294 if (FAILED(ret)) return ret;
296 switch (msg_type)
298 case MSGTYPE_PROBE:
299 TRACE("Received probe message\n");
301 ret = WSDCreateUdpMessageParameters(&msg_params);
303 if (FAILED(ret))
305 ERR("Unable to create IWSDUdpMessageParameters, not processing message.\n");
306 goto cleanup;
309 ret = WSDCreateUdpAddress(&remote_addr);
311 if (FAILED(ret))
313 ERR("Unable to create IWSDUdpAddress, not processing message.\n");
314 goto cleanup;
317 IWSDUdpAddress_SetSockaddr(remote_addr, source_addr);
318 IWSDUdpMessageParameters_SetRemoteAddress(msg_params, (IWSDAddress *)remote_addr);
320 EnterCriticalSection(&params->impl->notification_sink_critical_section);
322 LIST_FOR_EACH_ENTRY(sink, &params->impl->notificationSinks, struct notificationSink, entry)
324 IWSDiscoveryPublisherNotify_ProbeHandler(sink->notificationSink, msg, (IWSDMessageParameters *)msg_params);
327 LeaveCriticalSection(&params->impl->notification_sink_critical_section);
329 break;
332 cleanup:
333 WSDFreeLinkedMemory(msg);
335 if (remote_addr != NULL) IWSDUdpAddress_Release(remote_addr);
336 if (msg_params != NULL) IWSDUdpMessageParameters_Release(msg_params);
338 return ret;
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;
348 char *buffer;
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);
365 return 0;
368 else
370 process_received_message(parameter, buffer, bytes_received, &source_addr);
374 /* The publisher has been stopped */
375 closesocket(parameter->listening_socket);
377 free(buffer);
378 free(parameter);
380 return 0;
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;
390 int address_length;
391 SOCKET s = 0;
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);
406 else
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());
429 goto cleanup;
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());
436 goto cleanup;
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());
443 goto cleanup;
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());
450 goto cleanup;
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());
457 goto cleanup;
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());
464 goto cleanup;
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());
479 goto cleanup;
482 impl->thread_handles[impl->num_thread_handles] = thread_handle;
483 impl->num_thread_handles++;
485 return 1;
487 cleanup:
488 closesocket(s);
489 free(parameter);
491 return 0;
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)
501 return FALSE;
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");
508 goto cleanup;
511 if (adapter_address->FirstUnicastAddress == NULL)
513 TRACE("No address found for adaptor '%s' (%p)\n", adapter_address->AdapterName, adapter_address);
514 continue;
517 valid_listeners += start_listening(impl, (SOCKADDR_STORAGE *)adapter_address->FirstUnicastAddress->Address.lpSockaddr);
520 cleanup:
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;
528 HRESULT ret;
529 SOCKET s;
531 ZeroMemory(&address, sizeof(SOCKADDR_STORAGE));
533 ret = IWSDUdpAddress_GetSockaddr(remote_addr, &address);
535 if (FAILED(ret))
537 WARN("No sockaddr specified in send_udp_unicast\n");
538 return ret;
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);
552 closesocket(s);
554 return S_OK;
557 void terminate_networking(IWSDiscoveryPublisherImpl *impl)
559 BOOL needsCleanup = impl->publisherStarted;
560 int i;
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]);
570 if (needsCleanup)
571 WSACleanup();
574 BOOL init_networking(IWSDiscoveryPublisherImpl *impl)
576 WSADATA wsaData;
577 int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
579 if (ret != 0)
581 WARN("WSAStartup failed with error: %d\n", ret);
582 return FALSE;
585 impl->publisherStarted = TRUE;
587 if ((impl->addressFamily & WSDAPI_ADDRESSFAMILY_IPV4) && (!start_listening_on_all_addresses(impl, AF_INET)))
588 goto cleanup;
590 if ((impl->addressFamily & WSDAPI_ADDRESSFAMILY_IPV6) && (!start_listening_on_all_addresses(impl, AF_INET6)))
591 goto cleanup;
593 return TRUE;
595 cleanup:
596 terminate_networking(impl);
597 return FALSE;