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 void terminate_networking(IWSDiscoveryPublisherImpl
*impl
)
236 BOOL needsCleanup
= impl
->publisherStarted
;
238 impl
->publisherStarted
= FALSE
;
244 BOOL
init_networking(IWSDiscoveryPublisherImpl
*impl
)
247 int ret
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
251 WARN("WSAStartup failed with error: %d\n", ret
);
255 impl
->publisherStarted
= TRUE
;
257 /* TODO: Start listening */