|
|
@@ -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));
|