From c95e517b59710347e99e07f6e73a6aeee46adb9a Mon Sep 17 00:00:00 2001 From: Sam Vilain Date: Tue, 22 Feb 2011 15:26:36 +1030 Subject: [PATCH] net: fix tests on hosts where 'localhost' is v4 _and_ v6 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() (Reworked by Rusty Russell) Signed-off-by: Sam Vilain --- ccan/net/test/run.c | 87 +++++++++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/ccan/net/test/run.c b/ccan/net/test/run.c index 57fc9855..955550bc 100644 --- a/ccan/net/test/run.c +++ b/ccan/net/test/run.c @@ -43,52 +43,97 @@ 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; + +/* 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); + 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; + } + + /* 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) +{ + struct addrinfo *addr2; + if (we_faked_double) { + addr2 = addr->ai_next; + addr->ai_next = NULL; + } + freeaddrinfo(addr); + if (we_faked_double) + freeaddrinfo(addr2); +} + +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); + addr = double_addr_lookup(buf); ok1(addr); - ok1(addr2); - /* Join them as if they were from one lookup. */ - addr->ai_next = addr2; - 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); + addr = double_addr_lookup(buf); ok1(addr); - ok1(addr2); - /* Join them as if they were from one lookup. */ - addr->ai_next = addr2; - fd = net_connect(addr); ok1(fd >= 0); @@ -99,9 +144,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)); -- 2.39.2