[ccan] [PATCH] net: fix tests on hosts where 'localhost' is v4 _and_ v6

Rusty Russell rusty at rustcorp.com.au
Mon Feb 7 15:32:47 EST 2011


On Sun, 6 Feb 2011 02:16:41 pm Sam Vilain wrote:
> If 'localhost' exists in /etc/hosts with a v4 and a v6 address, the hack
> which joins two addrinfo entries together is not necessary.  Detect to see
> if 'localhost' returned a v6 address, and if so, just return the single
> linked list result from getaddrinfo()
> 
> Signed-off-by: Sam Vilain <sam at vilain.net>

Cool!  My 32-bit Ubuntu doesn't have both (which surprised me), but perhaps
that's because I've upgraded over time...

Unfortunately your patch broke my setup, which says to me that it's time to
invoke The Elements of Programming Style and rewrite it.

This tries to even handle the future IPv6 only case, on top of your patch.
Does it work for you?

Thanks!
Rusty.

diff --git a/ccan/net/test/run.c b/ccan/net/test/run.c
index 74901f6..955550b 100644
--- a/ccan/net/test/run.c
+++ b/ccan/net/test/run.c
@@ -45,34 +45,48 @@ static unsigned int server(int protocol, int type)
 
 static bool we_faked_double = false;
 
-/* some systems (eg Ubuntu) already have 'localhost' defined as both
-   ipv6 and ipv4; our first lookup might return two addresses.  Given
-   this is the situation we are trying to support, allow it to happen
-   before looking up the 'ip6-localhost' name and faking it. */
+/* Get a localhost on ipv4 and IPv6.  Fake it if we have to. */
 static struct addrinfo* double_addr_lookup(char* buf)
 {
 	struct addrinfo *addr, *addr2;
+
 	addr = net_client_lookup("localhost", buf, AF_UNSPEC, SOCK_STREAM);
-	ok1(addr);
-	addr2 = addr;
-	while (addr2) {
-		/* assume that we're not running on a v6-only stack */
-		if (addr2->ai_family == AF_INET6) {
-			goto out;
-		}
+	if (!addr)
+		return addr;
+
+	/* If we only got one, we need to fake up the other one. */
+	if (addr->ai_next) {
+		addr2 = addr->ai_next;
+	} else {
+		we_faked_double = true;
+
+		/* OK, IPv4 only? */
+		if (addr->ai_family == AF_INET) {
+			/* These are the names I found on my Ubuntu system. */
+			addr2 = net_client_lookup("ip6-localhost", buf,
+						  AF_UNSPEC, SOCK_STREAM);
+			if (!addr2)
+				addr2 = net_client_lookup("localhost6", buf,
+							  AF_UNSPEC,
+							  SOCK_STREAM);
+		} else if (addr->ai_family == AF_INET6)
+			/* IPv6 only?  This is a guess... */
+			addr2 = net_client_lookup("ip4-localhost", buf,
+						  AF_UNSPEC, SOCK_STREAM);
+		if (!addr2)
+			return NULL;
+		addr->ai_next = addr2;
 	}
-	/* 'localhost' didn't resolve to a v6 address; try
-	 * 'ip6-localhost' */
-	addr2 = net_client_lookup("ip6-localhost", buf,
-				  AF_UNSPEC, SOCK_STREAM);
-	ok1(addr2);
-
-	/* Join them as if they were from one lookup. */
-	addr->ai_next = addr2;
-	we_faked_double = true;
-
-out:
-	return addr;
+
+	/* More than two? */
+	if (addr2->ai_next)
+		return NULL;
+	/* One IPv4 and one IPv6? */
+	if (addr->ai_family == AF_INET && addr2->ai_family == AF_INET6)
+		return addr;
+	if (addr->ai_family == AF_INET6 && addr2->ai_family == AF_INET)
+		return addr;
+	return NULL;
 }
 
 static void double_addr_free(struct addrinfo* addr)
@@ -84,7 +98,7 @@ static void double_addr_free(struct addrinfo* addr)
 	}
 	freeaddrinfo(addr);
 	if (we_faked_double)
-		freeaddrinfo(addr);
+		freeaddrinfo(addr2);
 }
 
 int main(void)
@@ -101,6 +115,7 @@ int main(void)
 	sprintf(buf, "%u", port);
 
 	addr = double_addr_lookup(buf);
+	ok1(addr);
 	fd = net_connect(addr);
 	ok1(fd >= 0);
 
@@ -118,6 +133,7 @@ int main(void)
 	sprintf(buf, "%u", port);
 
 	addr = double_addr_lookup(buf);
+	ok1(addr);
 	fd = net_connect(addr);
 	ok1(fd >= 0);
 



More information about the ccan mailing list