]> git.ozlabs.org Git - ccan/commitdiff
net: fix tests on hosts where 'localhost' is v4 _and_ v6
authorSam Vilain <sam@vilain.net>
Tue, 22 Feb 2011 04:56:36 +0000 (15:26 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 22 Feb 2011 04:56:36 +0000 (15:26 +1030)
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 <sam@vilain.net>
ccan/net/test/run.c

index 57fc985554ec7b5bbc4c157c00df9c13bc42b61a..955550bcf8f88b010aa89dac8479aa5d1143e777 100644 (file)
@@ -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));