Skip to content

Commit a4c0551

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 a4c0551

File tree

1 file changed

+196
-39
lines changed

1 file changed

+196
-39
lines changed

dns_sd_windows.c

+196-39
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,50 @@ 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 ip_address_to_string(char *buffer, size_t capacity,
65+
const struct sockaddr *addr, size_t addrlen)
66+
{
67+
char host[NI_MAXHOST] = { 0 };
68+
char service[NI_MAXSERV] = { 0 };
69+
int ret, len = 0;
70+
ret = getnameinfo((const struct sockaddr *)addr, (socklen_t)addrlen, host,
71+
NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
72+
73+
if (ret == 0) {
74+
if (addr->sa_family == AF_INET6 &&
75+
((struct sockaddr_in6 *)addr)->sin6_port != 0 &&
76+
strncmp(service, "5353", sizeof("5353")))
77+
len = snprintf(buffer, capacity, "[%s]:%s", host, service);
78+
else if (((struct sockaddr_in *)addr)->sin_port != 0 &&
79+
strncmp(service, "5353", sizeof("5353")))
80+
len = snprintf(buffer, capacity, "%s:%s", host, service);
81+
else
82+
len = snprintf(buffer, capacity, "%s", host);
83+
}
84+
85+
if (len >= (int)capacity)
86+
len = (int)capacity - 1;
87+
mdns_string_t str;
88+
str.str = buffer;
89+
str.length = len;
90+
91+
return str;
92+
}
93+
5094
static int open_client_sockets(int *sockets, unsigned int max_sockets)
5195
{
5296
IP_ADAPTER_UNICAST_ADDRESS *unicast;
@@ -130,6 +174,14 @@ static int open_client_sockets(int *sockets, unsigned int max_sockets)
130174
return num_sockets;
131175
}
132176

177+
/* We should get:
178+
* - "service" record (SRV) specifying host (name) and port
179+
* - IPv4 "address" record (A) specifying IPv4 address of a given host
180+
* - IPv6 "address" record (AAAA) specifying IPv6 address of a given host
181+
* It's this routine that gets called, and needs to stitch things together
182+
* The DNS host doesn't necessary need to be the acutal host (but for
183+
* mdns - it usually is.
184+
*/
133185
static int query_callback(int sock, const struct sockaddr *from, size_t addrlen,
134186
mdns_entry_type_t entry, uint16_t query_id,
135187
uint16_t rtype, uint16_t rclass, uint32_t ttl,
@@ -140,52 +192,155 @@ static int query_callback(int sock, const struct sockaddr *from, size_t addrlen,
140192
{
141193
struct dns_sd_discovery_data *dd = user_data;
142194
char addrbuffer[64];
143-
char servicebuffer[64];
195+
char entrybuffer[256];
144196
char namebuffer[256];
145197
mdns_record_srv_t srv;
198+
bool found = false;
199+
200+
mdns_string_t entrystr, fromaddrstr;
146201

147202
if (!dd) {
148203
IIO_ERROR("DNS SD: Missing info structure. Stop browsing.\n");
149204
goto quit;
150205
}
151206

152-
if (rtype != MDNS_RECORDTYPE_SRV)
207+
if (rtype != MDNS_RECORDTYPE_SRV && rtype != MDNS_RECORDTYPE_A &&
208+
rtype != MDNS_RECORDTYPE_AAAA)
153209
goto quit;
154210

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;
211+
if (entry != MDNS_ENTRYTYPE_ANSWER)
212+
goto quit;
172213

173-
iio_strlcpy(dd->hostname, srv.name.str, srv.name.length);
174-
}
214+
entrystr = mdns_string_extract(data, size, &name_offset,
215+
entrybuffer, sizeof(entrybuffer));
175216

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

179-
IIO_DEBUG("DNS SD: added %s (%s:%d)\n",
180-
dd->hostname, dd->addr_str, dd->port);
220+
fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer),
221+
from, addrlen);
222+
223+
iio_mutex_lock(dd->lock);
224+
if (rtype == MDNS_RECORDTYPE_SRV) {
225+
srv = mdns_record_parse_srv(data, size, record_offset, record_length,
226+
namebuffer, sizeof(namebuffer));
227+
IIO_DEBUG("%.*s : %.*s SRV %.*s priority %d weight %d port %d\n",
228+
MDNS_STRING_FORMAT(fromaddrstr), MDNS_STRING_FORMAT(entrystr),
229+
MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
230+
231+
/* find a match based on name/port/ipv[46] & update it, otherwise add it */
232+
while (dd->next) {
233+
if (dd->hostname &&
234+
!strncmp(dd->hostname, srv.name.str, srv.name.length - 1) &&
235+
(!dd->port || dd->port == srv.port) &&
236+
dd->found == (from->sa_family != AF_INET)) {
237+
dd->port = srv.port;
238+
IIO_DEBUG("DNS SD: updated SRV %s (%s port:%hu)\n",
239+
dd->hostname, dd->addr_str, dd->port);
240+
found = true;
241+
}
242+
dd = dd->next;
243+
}
244+
if (!found) {
245+
/* new hostname and port */
246+
if (srv.name.length > 1) {
247+
dd->hostname = iio_strndup(srv.name.str,
248+
srv.name.length - 1);
249+
if (!dd->hostname)
250+
goto mem_fail;
251+
}
181252

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");
253+
iio_strlcpy(dd->addr_str, fromaddrstr.str, fromaddrstr.length + 1);
254+
dd->port = srv.port;
255+
dd->found = (from->sa_family != AF_INET);
256+
IIO_DEBUG("DNS SD: added SRV %s (%s port:%d)\n",
257+
dd->hostname, dd->addr_str, dd->port);
186258

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

191346
int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
@@ -202,15 +357,16 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
202357
int ret = -ENOMEM;
203358

204359
if (WSAStartup(versionWanted, &wsaData)) {
205-
printf("Failed to initialize WinSock\n");
360+
IIO_ERROR("Failed to initialize WinSock\n");
206361
return -WSAGetLastError();
207362
}
208363

209364
IIO_DEBUG("DNS SD: Start service discovery.\n");
210365

211-
d = zalloc(sizeof(*d));
366+
d = new_discovery_data(NULL);
212367
if (!d)
213368
goto out_wsa_cleanup;
369+
214370
/* pass the structure back, so it can be freed if err */
215371
*ddata = d;
216372

@@ -241,23 +397,24 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
241397
ret = mdns_query_send(sockets[isock], MDNS_RECORDTYPE_PTR,
242398
service, sizeof(service)-1, buffer,
243399
capacity, 0);
244-
if (ret <= 0)
400+
if (ret < 0)
245401
IIO_ERROR("Failed to send mDNS query: errno %d\n", errno);
246402

247403
transaction_id[isock] = ret;
248404
}
249405

250-
/* This is a simple implementation that loops for 10 seconds or as long as we get replies
251-
* A real world implementation would probably use select, poll or similar syscall to wait
252-
* until data is available on a socket and then read it */
406+
/* This is a simple implementation that loops as long as we get replies
407+
* A better implementation would probably use select, poll or similar
408+
* syscall to wait until data is available on a socket and then read it
409+
*/
253410
IIO_DEBUG("Reading mDNS query replies\n");
254411

255412
for (i = 0; i < 10; i++) {
256413
do {
257414
records = 0;
258415

259416
for (isock = 0; isock < num_sockets; isock++) {
260-
if (transaction_id[isock] <= 0)
417+
if (transaction_id[isock] < 0)
261418
continue;
262419

263420
records += mdns_query_recv(sockets[isock],

0 commit comments

Comments
 (0)