io: use bind() to check for IPv4/6 availability

Currently the test-io-channel-socket.c test uses getifaddrs
to see if an IPv4/6 address is present on any host NIC, as
a way to determine if IPv4/6 sockets can be used. This is
problematic because getifaddrs is not available on Win32.

Rather than testing indirectly via getifaddrs, just create
a socket and try to bind() to the loopback address instead.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2016-03-08 11:39:36 +00:00
parent c619644067
commit 0a27af918b

View file

@ -22,66 +22,49 @@
#include "io/channel-socket.h" #include "io/channel-socket.h"
#include "io/channel-util.h" #include "io/channel-util.h"
#include "io-channel-helpers.h" #include "io-channel-helpers.h"
#ifdef HAVE_IFADDRS_H
#include <ifaddrs.h>
#endif
static int check_protocol_support(bool *has_ipv4, bool *has_ipv6) static int check_bind(struct sockaddr *sa, socklen_t salen, bool *has_proto)
{ {
#ifdef HAVE_IFADDRS_H int fd;
struct ifaddrs *ifaddr = NULL, *ifa;
struct addrinfo hints = { 0 };
struct addrinfo *ai = NULL;
int gaierr;
*has_ipv4 = *has_ipv6 = false; fd = socket(sa->sa_family, SOCK_STREAM, 0);
if (fd < 0) {
if (getifaddrs(&ifaddr) < 0) {
g_printerr("Failed to lookup interface addresses: %s\n",
strerror(errno));
return -1; return -1;
} }
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (bind(fd, sa, salen) < 0) {
if (!ifa->ifa_addr) { close(fd);
continue; if (errno == EADDRNOTAVAIL) {
} *has_proto = false;
return 0;
if (ifa->ifa_addr->sa_family == AF_INET) {
*has_ipv4 = true;
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
*has_ipv6 = true;
} }
return -1;
} }
freeifaddrs(ifaddr); close(fd);
*has_proto = true;
return 0;
}
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
hints.ai_family = AF_INET6; {
hints.ai_socktype = SOCK_STREAM; struct sockaddr_in sin = {
.sin_family = AF_INET,
.sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
};
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
};
gaierr = getaddrinfo("::1", NULL, &hints, &ai); if (check_bind((struct sockaddr *)&sin, sizeof(sin), has_ipv4) < 0) {
if (gaierr != 0) { return -1;
if (gaierr == EAI_ADDRFAMILY || }
gaierr == EAI_FAMILY || if (check_bind((struct sockaddr *)&sin6, sizeof(sin6), has_ipv6) < 0) {
gaierr == EAI_NONAME) { return -1;
*has_ipv6 = false;
} else {
g_printerr("Failed to resolve ::1 address: %s\n",
gai_strerror(gaierr));
return -1;
}
} }
freeaddrinfo(ai);
return 0; return 0;
#else
*has_ipv4 = *has_ipv6 = false;
return -1;
#endif
} }