Skip to content

Commit

Permalink
network: Improve context creation robustness
Browse files Browse the repository at this point in the history
It might happen that the uri passed to libiio is an avahi typical
hostname. In that case, is not guaranteed that `getaddrinfo()` will
succeed in resolving it. For that to happen there are dependencies
on the host configuration like the presence of the nss-mdns package.
This patch adds a "a last resort" attempt in resolving the hostname in
case `getaddrinfo()` fails, by directly using libavahi.

Signed-off-by: Nuno Sa <[email protected]>
  • Loading branch information
nunojsa authored and pcercuei committed Apr 16, 2021
1 parent 9786096 commit f7dccb5
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 0 deletions.
3 changes: 3 additions & 0 deletions dns_sd.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,7 @@ void remove_dup_discovery_data(struct dns_sd_discovery_data **ddata);
/* port knocks */
void port_knock_discovery_data(struct dns_sd_discovery_data **ddata);

/* Use dnssd to resolve a given hostname */
int dnssd_resolve_host(const char *hostname, char *ip_addr, const int addr_len);

#endif /* __IIO_DNS_SD_H */
107 changes: 107 additions & 0 deletions dns_sd_avahi.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,28 @@ static void __avahi_resolver_cb(AvahiServiceResolver *resolver,
avahi_service_resolver_free(resolver);
}

static void avahi_host_resolver(AvahiHostNameResolver *resolver, __notused AvahiIfIndex iface,
__notused AvahiProtocol proto, AvahiResolverEvent event,
const char *host_name, const AvahiAddress *address,
__notused AvahiLookupResultFlags flags, void *d)
{
struct dns_sd_discovery_data *ddata = (struct dns_sd_discovery_data *) d;

switch(event) {
case AVAHI_RESOLVER_FAILURE:
IIO_ERROR("Avahi Resolver: Failed to resolve host '%s' : %s\n", host_name,
avahi_strerror(avahi_client_errno(
avahi_host_name_resolver_get_client(resolver))));
break;
case AVAHI_RESOLVER_FOUND:
avahi_process_resolved(ddata, address, host_name, IIOD_PORT);
break;
}

avahi_host_name_resolver_free(resolver);
avahi_simple_poll_quit(ddata->poll);
}

static void __avahi_browser_cb(AvahiServiceBrowser *browser,
AvahiIfIndex iface, AvahiProtocol proto,
AvahiBrowserEvent event, const char *name,
Expand Down Expand Up @@ -258,3 +280,88 @@ int dnssd_find_hosts(struct dns_sd_discovery_data **ddata)

return ret;
}

static void avahi_resolve_host(struct dns_sd_discovery_data *d, const char *hostname,
const AvahiProtocol proto)
{
AvahiClient *client;
AvahiHostNameResolver *resolver;
int ret;

d->poll = avahi_simple_poll_new();
if (!d->poll)
return;

client = avahi_client_new(avahi_simple_poll_get(d->poll), 0, NULL, NULL, &ret);
if (!client) {
IIO_ERROR("Unable to create Avahi DNS-SD client :%s\n", avahi_strerror(ret));
goto err_free_poll;
}

resolver = avahi_host_name_resolver_new(client, AVAHI_IF_UNSPEC, proto, hostname, proto, 0,
avahi_host_resolver, d);
if (!resolver) {
ret = avahi_client_errno(client);
IIO_ERROR("Unable to create Avahi DNS-SD browser: %s\n", avahi_strerror(ret));
goto err_free_client;
}

IIO_DEBUG("Trying to resolve host: %s\n, proto: %d", hostname, proto);
avahi_simple_poll_loop(d->poll);

err_free_client:
avahi_client_free(client);
err_free_poll:
avahi_simple_poll_free(d->poll);
}

int dnssd_resolve_host(const char *hostname, char *ip_addr, const int addr_len)
{
struct dns_sd_discovery_data *d;
int ret = 0;

if (!hostname || hostname[0] == '\0')
return -EINVAL;

if (new_discovery_data(&d) < 0)
return -ENOMEM;

d->lock = iio_mutex_create();
if (!d->lock) {
ret = -ENOMEM;
goto err_free_data;
}
/*
* The reason not to use AVAHI_PROTO_UNSPEC is that avahi sometimes resolves the host
* to an ipv6 link local address which is not suitable to be used by connect. In fact,
* `port_knock_discovery_data()` would discard this entry. On the other hand, some users
* might really want to use ipv6 and have their environment correctly configured. Hence,
* we try to resolve both in ipv4 and ipv6...
*/
avahi_resolve_host(d, hostname, AVAHI_PROTO_INET);
#ifdef HAVE_IPV6
avahi_resolve_host(d, hostname, AVAHI_PROTO_INET6);
#endif

if (d->resolved) {
port_knock_discovery_data(&d);
remove_dup_discovery_data(&d);
} else {
ret = -ENXIO;
goto err_mutex_destroy;
}

/* If next is null it means that d is empty */
if (!d->next) {
ret = -ENXIO;
goto err_mutex_destroy;
}

iio_strlcpy(ip_addr, d->addr_str, addr_len);

err_mutex_destroy:
iio_mutex_destroy(d->lock);
err_free_data:
dnssd_free_all_discovery_data(d);
return ret;
}
5 changes: 5 additions & 0 deletions dns_sd_bonjour.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,8 @@ int dnssd_find_hosts(struct dns_sd_discovery_data ** ddata)
iio_mutex_destroy(d->lock);
return ret;
}

int dnssd_resolve_host(const char *hostname, char *ip_addr, const int addr_len)
{
return -ENOENT;
}
5 changes: 5 additions & 0 deletions dns_sd_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,8 @@ int dnssd_find_hosts(struct dns_sd_discovery_data** ddata)

return 0;
}

int dnssd_resolve_host(const char *hostname, char *ip_addr, const int addr_len)
{
return -ENOENT;
}
24 changes: 24 additions & 0 deletions network.c
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,30 @@ struct iio_context * network_create_context(const char *host)
ret = getaddrinfo(addr_str, port_str, &hints, &res);
} else {
ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res);
/*
* It might be an avahi hostname which means that getaddrinfo() will only work if
* nss-mdns is installed on the host and /etc/nsswitch.conf is correctly configured
* which might be not the case for some minimalist distros. In this case,
* as a last resort, let's try to resolve the host with avahi...
*/
if (ret && HAVE_DNS_SD) {
char addr_str[DNS_SD_ADDRESS_STR_MAX];

IIO_DEBUG("'getaddrinfo()' failed: %s. Trying dnssd as a last resort...\n",
gai_strerror(ret));

ret = dnssd_resolve_host(host, addr_str, sizeof(addr_str));
if (ret) {
char buf[256];

iio_strerror(-ret, buf, sizeof(buf));
IIO_DEBUG("Unable to find host: %s\n", buf);
errno = -ret;
return NULL;
}

ret = getaddrinfo(addr_str, IIOD_PORT_STR, &hints, &res);
}
}

if (ret) {
Expand Down

0 comments on commit f7dccb5

Please sign in to comment.