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:
parent
c619644067
commit
0a27af918b
|
@ -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>
|
static int check_bind(struct sockaddr *sa, socklen_t salen, bool *has_proto)
|
||||||
#endif
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket(sa->sa_family, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(fd, sa, salen) < 0) {
|
||||||
|
close(fd);
|
||||||
|
if (errno == EADDRNOTAVAIL) {
|
||||||
|
*has_proto = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
*has_proto = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
|
static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IFADDRS_H
|
struct sockaddr_in sin = {
|
||||||
struct ifaddrs *ifaddr = NULL, *ifa;
|
.sin_family = AF_INET,
|
||||||
struct addrinfo hints = { 0 };
|
.sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) },
|
||||||
struct addrinfo *ai = NULL;
|
};
|
||||||
int gaierr;
|
struct sockaddr_in6 sin6 = {
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
|
||||||
|
};
|
||||||
|
|
||||||
*has_ipv4 = *has_ipv6 = false;
|
if (check_bind((struct sockaddr *)&sin, sizeof(sin), has_ipv4) < 0) {
|
||||||
|
|
||||||
if (getifaddrs(&ifaddr) < 0) {
|
|
||||||
g_printerr("Failed to lookup interface addresses: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (check_bind((struct sockaddr *)&sin6, sizeof(sin6), has_ipv6) < 0) {
|
||||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
|
||||||
if (!ifa->ifa_addr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ifa->ifa_addr->sa_family == AF_INET) {
|
|
||||||
*has_ipv4 = true;
|
|
||||||
}
|
|
||||||
if (ifa->ifa_addr->sa_family == AF_INET6) {
|
|
||||||
*has_ipv6 = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
freeifaddrs(ifaddr);
|
|
||||||
|
|
||||||
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
|
||||||
hints.ai_family = AF_INET6;
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
|
|
||||||
gaierr = getaddrinfo("::1", NULL, &hints, &ai);
|
|
||||||
if (gaierr != 0) {
|
|
||||||
if (gaierr == EAI_ADDRFAMILY ||
|
|
||||||
gaierr == EAI_FAMILY ||
|
|
||||||
gaierr == EAI_NONAME) {
|
|
||||||
*has_ipv6 = false;
|
|
||||||
} else {
|
|
||||||
g_printerr("Failed to resolve ::1 address: %s\n",
|
|
||||||
gai_strerror(gaierr));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
|
||||||
*has_ipv4 = *has_ipv6 = false;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue