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

Sam Vilain sam at vilain.net
Sun Feb 6 14:44:57 EST 2011


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>
---
  (re-send, apologies if this doubles up)
 ccan/net/test/run.c |   75 ++++++++++++++++++++++++++++++++++----------------
 1 files changed, 51 insertions(+), 24 deletions(-)

diff --git a/ccan/net/test/run.c b/ccan/net/test/run.c
index 2e241cb..fe2ff99 100644
--- a/ccan/net/test/run.c
+++ b/ccan/net/test/run.c
@@ -42,52 +42,81 @@ static unsigned int server(int protocol, int type)
 		     ? addr.ipv4.sin_port : addr.ipv6.sin6_port);
 }
 
-int main(void)
+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. */
+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;
+		}
+	}
+	/* '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;
+}
+
+static void double_addr_free(struct addrinfo* addr)
+{
+	struct addrinfo *addr2;
+	if (we_faked_double) {
+		addr2 = addr->ai_next;
+		addr->ai_next = NULL;
+	}
+	freeaddrinfo(addr);
+	if (we_faked_double)
+		freeaddrinfo(addr);
+}
+
+int main(void)
+{
+	struct addrinfo *addr;
 	int fd, status;
 	struct sockaddr saddr;
 	socklen_t slen = sizeof(saddr);
 	char buf[20];
 	unsigned int port;
 
-	plan_tests(16);
+	plan_tests(14);
 	port = server(AF_INET, SOCK_STREAM);
 	sprintf(buf, "%u", port);
 
-	addr = net_client_lookup("localhost", buf, AF_UNSPEC, SOCK_STREAM);
-	addr2 = net_client_lookup("ip6-localhost", buf,
-				  AF_UNSPEC, SOCK_STREAM);
-	ok1(addr);
-	ok1(addr2);
-	/* Join them as if they were from one lookup. */
-	addr->ai_next = addr2;
-
+	addr = double_addr_lookup(buf);
 	fd = net_connect(addr);
 	ok1(fd >= 0);
 
 	ok1(getsockname(fd, &saddr, &slen) == 0);
+	diag("family = %d", saddr.sa_family);
 	ok1(saddr.sa_family == AF_INET);
 	status = read(fd, buf, sizeof(buf));
 	ok(status == strlen("Yay!"),
 	   "Read returned %i (%s)", status, strerror(errno));
 	ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
 	close(fd);
-	addr->ai_next = NULL;
-	freeaddrinfo(addr);
-	freeaddrinfo(addr2);
+	double_addr_free(addr);
 
 	port = server(AF_INET6, SOCK_STREAM);
 	sprintf(buf, "%u", port);
 
-	addr = net_client_lookup("localhost", buf, AF_UNSPEC, SOCK_STREAM);
-	addr2 = net_client_lookup("ip6-localhost", buf,
-				  AF_UNSPEC, SOCK_STREAM);
-	ok1(addr);
-	ok1(addr2);
-	/* Join them as if they were from one lookup. */
-	addr->ai_next = addr2;
-
+	addr = double_addr_lookup(buf);
 	fd = net_connect(addr);
 	ok1(fd >= 0);
 
@@ -98,9 +127,7 @@ int main(void)
 	   "Read returned %i (%s)", status, strerror(errno));
 	ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
 	close(fd);
-	addr->ai_next = NULL;
-	freeaddrinfo(addr);
-	freeaddrinfo(addr2);
+	double_addr_free(addr);
 
 	wait(&status);
 	ok1(WIFEXITED(status));
-- 
1.7.0.4



More information about the ccan mailing list