2
2
/*
3
3
* libiio - Library for interfacing industrial I/O (IIO) devices
4
4
*
5
- * Copyright (C) 2014-2020 Analog Devices, Inc.
5
+ * Copyright (C) 2014-2022 Analog Devices, Inc.
6
6
* Author: Adrian Suciu <[email protected] >
7
7
*
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
10
10
*/
11
11
12
12
#include <stdio.h>
@@ -47,6 +47,74 @@ static bool is_localhost4(const struct sockaddr_in *saddr)
47
47
saddr -> sin_addr .S_un .S_un_b .s_b4 == 1 ;
48
48
}
49
49
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
+
50
118
static int open_client_sockets (int * sockets , unsigned int max_sockets )
51
119
{
52
120
IP_ADAPTER_UNICAST_ADDRESS * unicast ;
@@ -130,6 +198,14 @@ static int open_client_sockets(int *sockets, unsigned int max_sockets)
130
198
return num_sockets ;
131
199
}
132
200
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
+ */
133
209
static int query_callback (int sock , const struct sockaddr * from , size_t addrlen ,
134
210
mdns_entry_type_t entry , uint16_t query_id ,
135
211
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,
140
216
{
141
217
struct dns_sd_discovery_data * dd = user_data ;
142
218
char addrbuffer [64 ];
143
- char servicebuffer [ 64 ];
219
+ char entrybuffer [ 256 ];
144
220
char namebuffer [256 ];
145
221
mdns_record_srv_t srv ;
222
+ bool found = false;
146
223
147
224
if (!dd ) {
148
225
IIO_ERROR ("DNS SD: Missing info structure. Stop browsing.\n" );
149
226
goto quit ;
150
227
}
151
228
152
- if (rtype != MDNS_RECORDTYPE_SRV )
229
+ if (rtype != MDNS_RECORDTYPE_SRV && rtype != MDNS_RECORDTYPE_A && rtype != MDNS_RECORDTYPE_AAAA )
153
230
goto quit ;
154
231
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 ;
172
234
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 ));
175
237
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 ;
178
240
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
+ }
181
269
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 );
186
275
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 );
187
346
quit :
188
347
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 ;
189
353
}
190
354
191
355
int dnssd_find_hosts (struct dns_sd_discovery_data * * ddata )
@@ -202,15 +366,16 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
202
366
int ret = - ENOMEM ;
203
367
204
368
if (WSAStartup (versionWanted , & wsaData )) {
205
- printf ("Failed to initialize WinSock\n" );
369
+ IIO_ERROR ("Failed to initialize WinSock\n" );
206
370
return - WSAGetLastError ();
207
371
}
208
372
209
373
IIO_DEBUG ("DNS SD: Start service discovery.\n" );
210
374
211
- d = zalloc ( sizeof ( * d ) );
375
+ d = new_discovery_data ( NULL );
212
376
if (!d )
213
377
goto out_wsa_cleanup ;
378
+
214
379
/* pass the structure back, so it can be freed if err */
215
380
* ddata = d ;
216
381
@@ -241,7 +406,7 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
241
406
ret = mdns_query_send (sockets [isock ], MDNS_RECORDTYPE_PTR ,
242
407
service , sizeof (service )- 1 , buffer ,
243
408
capacity , 0 );
244
- if (ret <= 0 )
409
+ if (ret < 0 )
245
410
IIO_ERROR ("Failed to send mDNS query: errno %d\n" , errno );
246
411
247
412
transaction_id [isock ] = ret ;
@@ -257,7 +422,7 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)
257
422
records = 0 ;
258
423
259
424
for (isock = 0 ; isock < num_sockets ; isock ++ ) {
260
- if (transaction_id [isock ] <= 0 )
425
+ if (transaction_id [isock ] < 0 )
261
426
continue ;
262
427
263
428
records += mdns_query_recv (sockets [isock ],
0 commit comments