-
Notifications
You must be signed in to change notification settings - Fork 319
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
Showing
1 changed file
with
201 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,11 +2,11 @@ | |
/* | ||
* libiio - Library for interfacing industrial I/O (IIO) devices | ||
* | ||
* Copyright (C) 2014-2020 Analog Devices, Inc. | ||
* Copyright (C) 2014-2022 Analog Devices, Inc. | ||
* Author: Adrian Suciu <[email protected]> | ||
* | ||
* Based on https://github.com/mjansson/mdns/blob/ce2e4f789f06429008925ff8f18c22036e60201e/mdns.c | ||
* which is Licensed under Public Domain | ||
* Based on https://github.com/mjansson/mdns/blob/main/mdns.c | ||
* which should be sync'ed with the mdns.h file and is Licensed under Public Domain | ||
*/ | ||
|
||
#include <stdio.h> | ||
|
@@ -47,6 +47,74 @@ static bool is_localhost4(const struct sockaddr_in *saddr) | |
saddr->sin_addr.S_un.S_un_b.s_b4 == 1; | ||
} | ||
|
||
static struct dns_sd_discovery_data *new_discovery_data(struct dns_sd_discovery_data *dd) | ||
{ | ||
struct dns_sd_discovery_data *d; | ||
|
||
d = zalloc(sizeof(*d)); | ||
if (!d) | ||
return NULL; | ||
|
||
if (dd) | ||
d->lock = dd->lock; | ||
|
||
return d; | ||
} | ||
|
||
static mdns_string_t ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr, | ||
size_t addrlen) { | ||
char host[NI_MAXHOST] = { 0 }; | ||
char service[NI_MAXSERV] = { 0 }; | ||
int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST, | ||
service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST); | ||
int len = 0; | ||
if (ret == 0) { | ||
if (addr->sin_port != 0 && strncmp(service, "5353", sizeof("5353"))) | ||
len = snprintf(buffer, capacity, "%s:%s", host, service); | ||
else | ||
len = snprintf(buffer, capacity, "%s", host); | ||
} | ||
if (len >= (int)capacity) | ||
len = (int)capacity - 1; | ||
mdns_string_t str; | ||
str.str = buffer; | ||
str.length = len; | ||
return str; | ||
} | ||
|
||
#ifdef HAVE_IPV6 | ||
static mdns_string_t ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr, | ||
size_t addrlen) { | ||
char host[NI_MAXHOST] = { 0 }; | ||
char service[NI_MAXSERV] = { 0 }; | ||
int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST, | ||
service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST); | ||
int len = 0; | ||
if (ret == 0) { | ||
if (addr->sin6_port != 0 && strncmp(service, "5353", sizeof("5353"))) | ||
len = snprintf(buffer, capacity, "[%s]:%s", host, service); | ||
else | ||
len = snprintf(buffer, capacity, "%s", host); | ||
} | ||
if (len >= (int)capacity) | ||
len = (int)capacity - 1; | ||
mdns_string_t str; | ||
str.str = buffer; | ||
str.length = len; | ||
return str; | ||
} | ||
#endif /* HAVE_IPV6 */ | ||
|
||
static mdns_string_t ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr, size_t addrlen) { | ||
#ifdef HAVE_IPV6 | ||
if (addr->sa_family == AF_INET6) | ||
return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr, addrlen); | ||
#endif /* HAVE_IPV6 */ | ||
return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr, addrlen); | ||
} | ||
|
||
|
||
|
||
static int open_client_sockets(int *sockets, unsigned int max_sockets) | ||
{ | ||
IP_ADAPTER_UNICAST_ADDRESS *unicast; | ||
|
@@ -130,6 +198,14 @@ static int open_client_sockets(int *sockets, unsigned int max_sockets) | |
return num_sockets; | ||
} | ||
|
||
/* We should get: | ||
* - "service" record (SRV) specifying host (name) and port | ||
* - IPv4 "address" record (A) specifying IPv4 address of a given host | ||
* - IPv6 "address" record (AAAA) specifying IPv6 address of a given host | ||
* It's this routine that gets called, and needs to stitch things together | ||
* The DNS host doesn't necessary need to be the acutal host (but for | ||
* mdns - it usually is. | ||
*/ | ||
static int query_callback(int sock, const struct sockaddr *from, size_t addrlen, | ||
mdns_entry_type_t entry, uint16_t query_id, | ||
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, | |
{ | ||
struct dns_sd_discovery_data *dd = user_data; | ||
char addrbuffer[64]; | ||
char servicebuffer[64]; | ||
char entrybuffer[256]; | ||
char namebuffer[256]; | ||
mdns_record_srv_t srv; | ||
bool found = false; | ||
|
||
if (!dd) { | ||
IIO_ERROR("DNS SD: Missing info structure. Stop browsing.\n"); | ||
goto quit; | ||
} | ||
|
||
if (rtype != MDNS_RECORDTYPE_SRV) | ||
if (rtype != MDNS_RECORDTYPE_SRV && rtype != MDNS_RECORDTYPE_A && rtype != MDNS_RECORDTYPE_AAAA) | ||
goto quit; | ||
|
||
getnameinfo(from, (socklen_t)addrlen, addrbuffer, NI_MAXHOST, | ||
servicebuffer, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST); | ||
|
||
srv = mdns_record_parse_srv(data, size, name_offset, name_length, | ||
namebuffer, sizeof(namebuffer)); | ||
IIO_DEBUG("%s : SRV %.*s priority %d weight %d port %d\n", addrbuffer, | ||
MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port); | ||
|
||
/* Go to the last element in the list */ | ||
while (dd->next) | ||
dd = dd->next; | ||
|
||
if (srv.name.length > 1) | ||
{ | ||
dd->hostname = malloc(srv.name.length); | ||
if (!dd->hostname) | ||
return -ENOMEM; | ||
if (entry != MDNS_ENTRYTYPE_ANSWER) | ||
goto quit; | ||
|
||
iio_strlcpy(dd->hostname, srv.name.str, srv.name.length); | ||
} | ||
mdns_string_t entrystr = | ||
mdns_string_extract(data, size, &name_offset, entrybuffer, sizeof(entrybuffer)); | ||
|
||
iio_strlcpy(dd->addr_str, addrbuffer, DNS_SD_ADDRESS_STR_MAX); | ||
dd->port = srv.port; | ||
if (!strstr(entrystr.str, "_iio._tcp.local")) | ||
goto quit; | ||
|
||
IIO_DEBUG("DNS SD: added %s (%s:%d)\n", | ||
dd->hostname, dd->addr_str, dd->port); | ||
mdns_string_t fromaddrstr = | ||
ip_address_to_string(addrbuffer, sizeof(addrbuffer), from, addrlen); | ||
|
||
iio_mutex_lock(dd->lock); | ||
if (rtype == MDNS_RECORDTYPE_SRV) { | ||
srv = mdns_record_parse_srv(data, size, record_offset, record_length, | ||
namebuffer, sizeof(namebuffer)); | ||
IIO_DEBUG("%.*s : %.*s SRV %.*s priority %d weight %d port %d\n", | ||
MDNS_STRING_FORMAT(fromaddrstr), MDNS_STRING_FORMAT(entrystr), | ||
MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port); | ||
|
||
/* find a match based on name/port/ipv4 or 6 & update it, otherwise add it */ | ||
while (dd->next) { | ||
if (dd->hostname && !strncmp(dd->hostname, srv.name.str, srv.name.length - 1) && | ||
(!dd->port || dd->port == srv.port) && dd->found == (from->sa_family != AF_INET)) { | ||
dd->port = srv.port; | ||
IIO_DEBUG("DNS SD: updated SRV %s (%s port:%hu)\n", dd->hostname, dd->addr_str, dd->port); | ||
found = true; | ||
} | ||
dd = dd->next; | ||
} | ||
if (!found) { | ||
/* new hostname and port */ | ||
if (srv.name.length > 1) { | ||
dd->hostname = iio_strndup(srv.name.str, srv.name.length - 1); | ||
if (!dd->hostname) | ||
goto mem_fail; | ||
} | ||
|
||
/* A list entry was filled, prepare new item on the list */ | ||
dd->next = zalloc(sizeof(*dd->next)); | ||
if (!dd->next) | ||
IIO_ERROR("DNS SD mDNS Resolver : memory failure\n"); | ||
iio_strlcpy(dd->addr_str, fromaddrstr.str, fromaddrstr.length + 1); | ||
dd->port = srv.port; | ||
dd->found = (from->sa_family != AF_INET); | ||
IIO_DEBUG("DNS SD: added SRV %s (%s port:%d)\n", | ||
dd->hostname, dd->addr_str, dd->port); | ||
|
||
/* A list entry was filled, prepare new item on the list */ | ||
dd->next = new_discovery_data(dd); | ||
if (!dd->next) | ||
goto mem_fail; | ||
} | ||
} else if (rtype == MDNS_RECORDTYPE_A) { | ||
struct sockaddr_in addr; | ||
mdns_record_parse_a(data, size, record_offset, record_length, &addr); | ||
mdns_string_t addrstr = | ||
ipv4_address_to_string(namebuffer, sizeof(namebuffer), &addr, sizeof(addr)); | ||
IIO_DEBUG("%.*s : %.*s A %.*s\n", MDNS_STRING_FORMAT(fromaddrstr), | ||
MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr)); | ||
|
||
/* find a match based on name/ipv4 or 6 & update it, otherwise add it */ | ||
while (dd->next) { | ||
if (dd->hostname && !strncmp(dd->hostname, entrystr.str, entrystr.length - 1) && | ||
!dd->found) { | ||
iio_strlcpy(dd->addr_str, addrstr.str, addrstr.length + 1); | ||
IIO_DEBUG("DNS SD: updated A %s (%s port:%hu)\n", dd->hostname, dd->addr_str, dd->port); | ||
found = true; | ||
} | ||
dd = dd->next; | ||
} | ||
if (!found) { | ||
dd->hostname = iio_strndup(entrystr.str, entrystr.length - 1); | ||
if (!dd->hostname) | ||
goto mem_fail; | ||
iio_strlcpy(dd->addr_str, addrstr.str, addrstr.length + 1); | ||
dd->found = 0; | ||
|
||
/* A list entry was filled, prepare new item on the list */ | ||
dd->next = new_discovery_data(dd); | ||
if (!dd->next) | ||
goto mem_fail; | ||
} | ||
} | ||
#ifdef HAVE_IPV6 | ||
else if (rtype == MDNS_RECORDTYPE_AAAA) { | ||
struct sockaddr_in6 addr; | ||
mdns_record_parse_aaaa(data, size, record_offset, record_length, &addr); | ||
mdns_string_t addrstr = | ||
ipv6_address_to_string(namebuffer, sizeof(namebuffer), &addr, sizeof(addr)); | ||
IIO_DEBUG("%.*s : %.*s AAAA %.*s\n", MDNS_STRING_FORMAT(fromaddrstr), | ||
MDNS_STRING_FORMAT(entrystr), MDNS_STRING_FORMAT(addrstr)); | ||
|
||
/* find a match based on name/port/ipv4 or 6 & update it, otherwise add it */ | ||
while (dd->next) { | ||
if (dd->hostname && !strncmp(dd->hostname, entrystr.str, entrystr.length - 1) && | ||
dd->found) { | ||
iio_strlcpy(dd->addr_str, addrstr.str, addrstr.length + 1); | ||
IIO_DEBUG("DNS SD: updated AAAA %s (%s port:%hu)\n", dd->hostname, dd->addr_str, dd->port); | ||
found = true; | ||
} | ||
dd = dd->next; | ||
} | ||
if (!found) { | ||
dd->hostname = iio_strndup(entrystr.str, entrystr.length - 1); | ||
if (!dd->hostname) | ||
goto mem_fail; | ||
iio_strlcpy(dd->addr_str, addrstr.str, addrstr.length + 1); | ||
dd->found = 1; | ||
|
||
/* A list entry was filled, prepare new item on the list */ | ||
dd->next = new_discovery_data(dd); | ||
if (!dd->next) | ||
goto mem_fail; | ||
} | ||
} | ||
#endif /* HAVE_IPV6 */ | ||
iio_mutex_unlock(dd->lock); | ||
quit: | ||
return 0; | ||
|
||
mem_fail: | ||
iio_mutex_unlock(dd->lock); | ||
IIO_ERROR("DNS SD mDNS Resolver : memory failure\n"); | ||
return -ENOMEM; | ||
} | ||
|
||
int dnssd_find_hosts(struct dns_sd_discovery_data **ddata) | ||
|
@@ -202,15 +366,16 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata) | |
int ret = -ENOMEM; | ||
|
||
if (WSAStartup(versionWanted, &wsaData)) { | ||
printf("Failed to initialize WinSock\n"); | ||
IIO_ERROR("Failed to initialize WinSock\n"); | ||
return -WSAGetLastError(); | ||
} | ||
|
||
IIO_DEBUG("DNS SD: Start service discovery.\n"); | ||
|
||
d = zalloc(sizeof(*d)); | ||
d = new_discovery_data(NULL); | ||
if (!d) | ||
goto out_wsa_cleanup; | ||
|
||
/* pass the structure back, so it can be freed if err */ | ||
*ddata = d; | ||
|
||
|
@@ -241,7 +406,7 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata) | |
ret = mdns_query_send(sockets[isock], MDNS_RECORDTYPE_PTR, | ||
service, sizeof(service)-1, buffer, | ||
capacity, 0); | ||
if (ret <= 0) | ||
if (ret < 0) | ||
IIO_ERROR("Failed to send mDNS query: errno %d\n", errno); | ||
|
||
transaction_id[isock] = ret; | ||
|
@@ -257,7 +422,7 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata) | |
records = 0; | ||
|
||
for (isock = 0; isock < num_sockets; isock++) { | ||
if (transaction_id[isock] <= 0) | ||
if (transaction_id[isock] < 0) | ||
continue; | ||
|
||
records += mdns_query_recv(sockets[isock], | ||
|