Skip to content

Commit b336afb

Browse files
committed
mdns: Fix/Update Windows mdns code
This syncs the application side with the updates in the mdns.h file from: https://github.com/mjansson/mdns/ and does things according to the specs. (build up info from both A, AAAA and SRV records), not just assuming that the DNS server is the host. Signed-off-by: Robin Getz <[email protected]>
1 parent b1099c9 commit b336afb

File tree

1 file changed

+201
-36
lines changed

1 file changed

+201
-36
lines changed

dns_sd_windows.c

+201-36
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
/*
33
* libiio - Library for interfacing industrial I/O (IIO) devices
44
*
5-
* Copyright (C) 2014-2020 Analog Devices, Inc.
5+
* Copyright (C) 2014-2022 Analog Devices, Inc.
66
* Author: Adrian Suciu <[email protected]>
77
*
8-
* Based on https://github.com/mjansson/mdns/blob/ce2e4f789f06429008925ff8f18c22036e60201e/mdns.c
9-
* which is Licensed under Public Domain
8+
* Based on https://github.com/mjansson/mdns/blob/main/mdns.c
9+
* which should be sync'ed with the mdns.h file and is Licensed under Public Domain
1010
*/
1111

1212
#include <stdio.h>
@@ -47,6 +47,74 @@ static bool is_localhost4(const struct sockaddr_in *saddr)
4747
saddr->sin_addr.S_un.S_un_b.s_b4 == 1;
4848
}
4949

50+
static struct dns_sd_discovery_data *new_discovery_data(struct dns_sd_discovery_data *dd)
51+
{
52+
struct dns_sd_discovery_data *d;
53+
54+
d = zalloc(sizeof(*d));
55+
if (!d)
56+
return NULL;
57+
58+
if (dd)
59+
d->lock = dd->lock;
60+
61+
return d;
62+
}
63+
64+
static mdns_string_t ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr,
65+
size_t addrlen) {
66+
char host[NI_MAXHOST] = { 0 };
67+
char service[NI_MAXSERV] = { 0 };
68+
int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST,
69+
service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
70+
int len = 0;
71+
if (ret == 0) {
72+
if (addr->sin_port != 0 && strncmp(service, "5353", sizeof("5353")))
73+
len = snprintf(buffer, capacity, "%s:%s", host, service);
74+
else
75+
len = snprintf(buffer, capacity, "%s", host);
76+
}
77+
if (len >= (int)capacity)
78+
len = (int)capacity - 1;
79+
mdns_string_t str;
80+
str.str = buffer;
81+
str.length = len;
82+
return str;
83+
}
84+
85+
#ifdef HAVE_IPV6
86+
static mdns_string_t ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr,
87+
size_t addrlen) {
88+
char host[NI_MAXHOST] = { 0 };
89+
char service[NI_MAXSERV] = { 0 };
90+
int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST,
91+
service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
92+
int len = 0;
93+
if (ret == 0) {
94+
if (addr->sin6_port != 0 && strncmp(service, "5353", sizeof("5353")))
95+
len = snprintf(buffer, capacity, "[%s]:%s", host, service);
96+
else
97+
len = snprintf(buffer, capacity, "%s", host);
98+
}
99+
if (len >= (int)capacity)
100+
len = (int)capacity - 1;
101+
mdns_string_t str;
102+
str.str = buffer;
103+
str.length = len;
104+
return str;
105+
}
106+
#endif /* HAVE_IPV6 */
107+
108+
static mdns_string_t ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr, size_t addrlen) {
109+
#ifdef HAVE_IPV6
110+
if (addr->sa_family == AF_INET6)
111+
return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr, addrlen);
112+
#endif /* HAVE_IPV6 */
113+
return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr, addrlen);
114+
}
115+
116+
117+
50118
static int open_client_sockets(int *sockets, unsigned int max_sockets)
51119
{
52120
IP_ADAPTER_UNICAST_ADDRESS *unicast;
@@ -130,6 +198,14 @@ static int open_client_sockets(int *sockets, unsigned int max_sockets)
130198
return num_sockets;
131199
}
132200

201+
/* We should get:
202+
* - "service" record (SRV) specifying host (name) and port
203+
* - IPv4 "address" record (A) specifying IPv4 address of a given host
204+
* - IPv6 "address" record (AAAA) specifying IPv6 address of a given host
205+
* It's this routine that gets called, and needs to stitch things together
206+
* The DNS host doesn't necessary need to be the acutal host (but for
207+
* mdns - it usually is.
208+
*/
133209
static int query_callback(int sock, const struct sockaddr *from, size_t addrlen,
134210
mdns_entry_type_t entry, uint16_t query_id,
135211
uint16_t rtype, uint16_t rclass, uint32_t ttl,
@@ -140,52 +216,140 @@ static int query_callback(int sock, const struct sockaddr *from, size_t addrlen,
140216
{
141217
struct dns_sd_discovery_data *dd = user_data;
142218
char addrbuffer[64];
143-
char servicebuffer[64];
219+
char entrybuffer[256];
144220
char namebuffer[256];
145221
mdns_record_srv_t srv;
222+
bool found = false;
146223

147224
if (!dd) {
148225
IIO_ERROR("DNS SD: Missing info structure. Stop browsing.\n");
149226
goto quit;
150227
}
151228

152-
if (rtype != MDNS_RECORDTYPE_SRV)
229+
if (rtype != MDNS_RECORDTYPE_SRV && rtype != MDNS_RECORDTYPE_A && rtype != MDNS_RECORDTYPE_AAAA)
153230
goto quit;
154231

155-
getnameinfo(from, (socklen_t)addrlen, addrbuffer, NI_MAXHOST,
156-
servicebuffer, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
157-
158-
srv = mdns_record_parse_srv(data, size, name_offset, name_length,
159-
namebuffer, sizeof(namebuffer));
160-
IIO_DEBUG("%s : SRV %.*s priority %d weight %d port %d\n", addrbuffer,
161-
MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
162-
163-
/* Go to the last element in the list */
164-
while (dd->next)
165-
dd = dd->next;
166-
167-
if (srv.name.length > 1)
168-
{
169-
dd->hostname = malloc(srv.name.length);
170-
if (!dd->hostname)
171-
return -ENOMEM;
232+
if (entry != MDNS_ENTRYTYPE_ANSWER)
233+
goto quit;
172234

173-
iio_strlcpy(dd->hostname, srv.name.str, srv.name.length);
174-
}
235+
mdns_string_t entrystr =
236+
mdns_string_extract(data, size, &name_offset, entrybuffer, sizeof(entrybuffer));
175237

176-
iio_strlcpy(dd->addr_str, addrbuffer, DNS_SD_ADDRESS_STR_MAX);
177-
dd->port = srv.port;
238+
if (!strstr(entrystr.str, "_iio._tcp.local"))
239+
goto quit;
178240

179-
IIO_DEBUG("DNS SD: added %s (%s:%d)\n",
180-
dd->hostname, dd->addr_str, dd->port);
241+
mdns_string_t fromaddrstr =
242+
ip_address_to_string(addrbuffer, sizeof(addrbuffer), from, addrlen);
243+
244+
iio_mutex_lock(dd->lock);
245+
if (rtype == MDNS_RECORDTYPE_SRV) {
246+
srv = mdns_record_parse_srv(data, size, record_offset, record_length,
247+
namebuffer, sizeof(namebuffer));
248+
IIO_DEBUG("%.*s : %.*s SRV %.*s priority %d weight %d port %d\n",
249+
MDNS_STRING_FORMAT(fromaddrstr), MDNS_STRING_FORMAT(entrystr),
250+
MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
251+
252+
/* find a match based on name/port/ipv4 or 6 & update it, otherwise add it */
253+
while (dd->next) {
254+
if (dd->hostname && !strncmp(dd->hostname, srv.name.str, srv.name.length - 1) &&
255+
(!dd->port || dd->port == srv.port) && dd->found == (from->sa_family != AF_INET)) {
256+
dd->port = srv.port;
257+
IIO_DEBUG("DNS SD: updated SRV %s (%s port:%hu)\n", dd->hostname, dd->addr_str, dd->port);
258+
found = true;
259+
}
260+
dd = dd->next;
261+
}
262+
if (!found) {
263+
/* new hostname and port */
264+
if (srv.name.length > 1) {
265+
dd->hostname = iio_strndup(srv.name.str, srv.name.length - 1);
266+
if (!dd->hostname)
267+
goto mem_fail;
268+
}
181269

182-
/* A list entry was filled, prepare new item on the list */
183-
dd->next = zalloc(sizeof(*dd->next));
184-
if (!dd->next)
185-
IIO_ERROR("DNS SD mDNS Resolver : memory failure\n");
270+
iio_strlcpy(dd->addr_str, fromaddrstr.str, fromaddrstr.length + 1);
271+
dd->port = srv.port;
272+
dd->found = (from->sa_family != AF_INET);
273+
IIO_DEBUG("DNS SD: added SRV %s (%s port:%d)\n",
274+
dd->hostname, dd->addr_str, dd->port);
186275

276+
/* A list entry was filled, prepare new item on the list */
277+
dd->next = new_discovery_data(dd);
278+
if (!dd->next)
279+
goto mem_fail;
280+
}
281+
} else if (rtype == MDNS_RECORDTYPE_A) {
282+
struct sockaddr_in addr;
283+
mdns_record_parse_a(data, size, record_offset, record_length, &addr);
284+
mdns_string_t addrstr =
285+
ipv4_address_to_string(namebuffer, sizeof(namebuffer), &addr, sizeof(addr));
286+
IIO_DEBUG("%.*s : %.*s A %.*s\n", MDNS_STRING_FORMAT(fromaddrstr),
287+
MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr));
288+
289+
/* find a match based on name/ipv4 or 6 & update it, otherwise add it */
290+
while (dd->next) {
291+
if (dd->hostname && !strncmp(dd->hostname, entrystr.str, entrystr.length - 1) &&
292+
!dd->found) {
293+
iio_strlcpy(dd->addr_str, addrstr.str, addrstr.length + 1);
294+
IIO_DEBUG("DNS SD: updated A %s (%s port:%hu)\n", dd->hostname, dd->addr_str, dd->port);
295+
found = true;
296+
}
297+
dd = dd->next;
298+
}
299+
if (!found) {
300+
dd->hostname = iio_strndup(entrystr.str, entrystr.length - 1);
301+
if (!dd->hostname)
302+
goto mem_fail;
303+
iio_strlcpy(dd->addr_str, addrstr.str, addrstr.length + 1);
304+
dd->found = 0;
305+
306+
/* A list entry was filled, prepare new item on the list */
307+
dd->next = new_discovery_data(dd);
308+
if (!dd->next)
309+
goto mem_fail;
310+
}
311+
}
312+
#ifdef HAVE_IPV6
313+
else if (rtype == MDNS_RECORDTYPE_AAAA) {
314+
struct sockaddr_in6 addr;
315+
mdns_record_parse_aaaa(data, size, record_offset, record_length, &addr);
316+
mdns_string_t addrstr =
317+
ipv6_address_to_string(namebuffer, sizeof(namebuffer), &addr, sizeof(addr));
318+
IIO_DEBUG("%.*s : %.*s AAAA %.*s\n", MDNS_STRING_FORMAT(fromaddrstr),
319+
MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr));
320+
321+
/* find a match based on name/port/ipv4 or 6 & update it, otherwise add it */
322+
while (dd->next) {
323+
if (dd->hostname && !strncmp(dd->hostname, entrystr.str, entrystr.length - 1) &&
324+
dd->found) {
325+
iio_strlcpy(dd->addr_str, addrstr.str, addrstr.length + 1);
326+
IIO_DEBUG("DNS SD: updated AAAA %s (%s port:%hu)\n", dd->hostname, dd->addr_str, dd->port);
327+
found = true;
328+
}
329+
dd = dd->next;
330+
}
331+
if (!found) {
332+
dd->hostname = iio_strndup(entrystr.str, entrystr.length - 1);
333+
if (!dd->hostname)
334+
goto mem_fail;
335+
iio_strlcpy(dd->addr_str, addrstr.str, addrstr.length + 1);
336+
dd->found = 1;
337+
338+
/* A list entry was filled, prepare new item on the list */
339+
dd->next = new_discovery_data(dd);
340+
if (!dd->next)
341+
goto mem_fail;
342+
}
343+
}
344+
#endif /* HAVE_IPV6 */
345+
iio_mutex_unlock(dd->lock);
187346
quit:
188347
return 0;
348+
349+
mem_fail:
350+
iio_mutex_unlock(dd->lock);
351+
IIO_ERROR("DNS SD mDNS Resolver : memory failure\n");
352+
return -ENOMEM;
189353
}
190354

191355
int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
@@ -202,15 +366,16 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
202366
int ret = -ENOMEM;
203367

204368
if (WSAStartup(versionWanted, &wsaData)) {
205-
printf("Failed to initialize WinSock\n");
369+
IIO_ERROR("Failed to initialize WinSock\n");
206370
return -WSAGetLastError();
207371
}
208372

209373
IIO_DEBUG("DNS SD: Start service discovery.\n");
210374

211-
d = zalloc(sizeof(*d));
375+
d = new_discovery_data(NULL);
212376
if (!d)
213377
goto out_wsa_cleanup;
378+
214379
/* pass the structure back, so it can be freed if err */
215380
*ddata = d;
216381

@@ -241,7 +406,7 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
241406
ret = mdns_query_send(sockets[isock], MDNS_RECORDTYPE_PTR,
242407
service, sizeof(service)-1, buffer,
243408
capacity, 0);
244-
if (ret <= 0)
409+
if (ret < 0)
245410
IIO_ERROR("Failed to send mDNS query: errno %d\n", errno);
246411

247412
transaction_id[isock] = ret;
@@ -257,7 +422,7 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
257422
records = 0;
258423

259424
for (isock = 0; isock < num_sockets; isock++) {
260-
if (transaction_id[isock] <= 0)
425+
if (transaction_id[isock] < 0)
261426
continue;
262427

263428
records += mdns_query_recv(sockets[isock],

0 commit comments

Comments
 (0)