X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fnet%2Ftest%2Frun.c;h=bdd5f1de8e49d82d3cb46460098e60cc3955e30a;hp=57fc985554ec7b5bbc4c157c00df9c13bc42b61a;hb=HEAD;hpb=708b846815c758645cf19f905513c67f7a024491 diff --git a/ccan/net/test/run.c b/ccan/net/test/run.c index 57fc9855..bdd5f1de 100644 --- a/ccan/net/test/run.c +++ b/ccan/net/test/run.c @@ -6,7 +6,7 @@ #include #include -static unsigned int server(int protocol, int type) +static int server(int protocol, int type) { int sock; union { @@ -17,9 +17,12 @@ static unsigned int server(int protocol, int type) socklen_t addlen = sizeof(addr); sock = socket(protocol, type, 0); + if (sock < 0) + return -1; /* Bind to free port. */ - listen(sock, 0); + if (listen(sock, 0) != 0) + return -1; /* Figure out what port it gave us. */ getsockname(sock, &addr.addr, &addlen); @@ -43,65 +46,134 @@ static unsigned int server(int protocol, int type) ? addr.ipv4.sin_port : addr.ipv6.sin6_port); } -int main(void) +/* Get a localhost on ipv4 and IPv6. Fake it if we can. */ +static struct addrinfo* double_addr_lookup(char* buf, bool *fake_double) { 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; + *fake_double = false; + } else { + /* 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); + if (!addr2) + addr2 = net_client_lookup("::1", 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); + + /* Perhaps no support on this system? Go ahead with one. */ + if (!addr2) { + *fake_double = false; + return addr; + } + + *fake_double = true; + 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, bool fake_double) +{ + if (fake_double) { + freeaddrinfo(addr->ai_next); + addr->ai_next = NULL; + } + freeaddrinfo(addr); +} + +int main(void) +{ + struct addrinfo *addr; int fd, status; struct sockaddr saddr; - socklen_t slen = sizeof(saddr); + socklen_t slen; char buf[20]; - unsigned int port; + int port; + bool fake_double; - plan_tests(16); - port = server(AF_INET, SOCK_STREAM); - sprintf(buf, "%u", port); + plan_tests(14); - 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; - - fd = net_connect(addr); - ok1(fd >= 0); - - ok1(getsockname(fd, &saddr, &slen) == 0); - 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); + port = server(AF_INET, SOCK_STREAM); + if (port == -1) { + /* No IPv4 support? Maybe one day this will happen! */ + if (errno == EAFNOSUPPORT) + skip(6, "No IPv4 socket support"); + else + fail("Could not create IPv4 listening socket: %s", + strerror(errno)); + } else { + sprintf(buf, "%u", port); + + addr = double_addr_lookup(buf, &fake_double); + ok1(addr); + fd = net_connect(addr); + ok1(fd >= 0); + + slen = sizeof(saddr); + 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); + double_addr_free(addr, fake_double); + } 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; - - fd = net_connect(addr); - ok1(fd >= 0); - - ok1(getsockname(fd, &saddr, &slen) == 0); - ok1(saddr.sa_family == AF_INET6); - 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); + if (port == -1) { + /* No IPv6 support? */ + if (errno == EAFNOSUPPORT) + skip(6, "No IPv6 socket support"); + else + fail("Could not create IPv6 listening socket: %s", + strerror(errno)); + } else { + sprintf(buf, "%u", port); + + addr = double_addr_lookup(buf, &fake_double); + ok1(addr); + fd = net_connect(addr); + ok1(fd >= 0); + + slen = sizeof(saddr); + ok1(getsockname(fd, &saddr, &slen) == 0); + ok1(saddr.sa_family == AF_INET6); + 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); + double_addr_free(addr, fake_double); + } wait(&status); ok1(WIFEXITED(status));