From 340849a9ff2a246bbc9a2da3f079c9fdbd2d5852 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 4 Apr 2016 17:22:00 +0100 Subject: util: retry getaddrinfo if getting EAI_BADFLAGS with AI_V4MAPPED The FreeBSD header files define the AI_V4MAPPED but its implementation of getaddrinfo() always returns an error when that flag is set. eg address resolution failed for localhost:9000: Invalid value for ai_flags There are also reports of the same problem on OS-X 10.6 Since AI_V4MAPPED is not critical functionality, if we get an EAI_BADFLAGS error then just retry without the AI_V4MAPPED flag set. Use a static var to cache this status so we don't have to retry on every single call. Also remove its use from the test suite since it serves no useful purpose there. Signed-off-by: Daniel P. Berrange Message-Id: <1459786920-15961-1-git-send-email-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- tests/test-io-channel-socket.c | 5 +---- util/qemu-sockets.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c index 9d94adb9ac..855306b8dd 100644 --- a/tests/test-io-channel-socket.c +++ b/tests/test-io-channel-socket.c @@ -27,9 +27,6 @@ #ifndef AI_ADDRCONFIG # define AI_ADDRCONFIG 0 #endif -#ifndef AI_V4MAPPED -# define AI_V4MAPPED 0 -#endif #ifndef EAI_ADDRFAMILY # define EAI_ADDRFAMILY 0 #endif @@ -42,7 +39,7 @@ static int check_bind(const char *hostname, bool *has_proto) int ret = -1; memset(&ai, 0, sizeof(ai)); - ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG; + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = AF_UNSPEC; ai.ai_socktype = SOCK_STREAM; diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index b87e17fa56..0d536911c9 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -29,6 +29,7 @@ #ifndef AI_ADDRCONFIG # define AI_ADDRCONFIG 0 #endif + #ifndef AI_V4MAPPED # define AI_V4MAPPED 0 #endif @@ -354,10 +355,14 @@ static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, struct addrinfo ai, *res; int rc; Error *err = NULL; + static int useV4Mapped = 1; memset(&ai, 0, sizeof(ai)); - ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG; + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; + if (atomic_read(&useV4Mapped)) { + ai.ai_flags |= AI_V4MAPPED; + } ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; @@ -373,6 +378,18 @@ static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, /* lookup */ rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); + + /* At least FreeBSD and OS-X 10.6 declare AI_V4MAPPED but + * then don't implement it in their getaddrinfo(). Detect + * this and retry without the flag since that's preferrable + * to a fatal error + */ + if (rc == EAI_BADFLAGS && + (ai.ai_flags & AI_V4MAPPED)) { + atomic_set(&useV4Mapped, 0); + ai.ai_flags &= ~AI_V4MAPPED; + rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); + } if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", saddr->host, saddr->port, gai_strerror(rc)); -- cgit v1.2.3