1 #include <ccan/net/net.h>
2 #include <ccan/net/net.c>
3 #include <ccan/tap/tap.h>
9 static int server(int protocol, int type)
14 struct sockaddr_in ipv4;
15 struct sockaddr_in6 ipv6;
17 socklen_t addlen = sizeof(addr);
19 sock = socket(protocol, type, 0);
23 /* Bind to free port. */
24 if (listen(sock, 0) != 0)
27 /* Figure out what port it gave us. */
28 getsockname(sock, &addr.addr, &addlen);
35 fd = accept(sock, NULL, 0);
37 err(1, "Accepting from socket %i", sock);
39 ret = write(fd, "Yay!", strlen("Yay!"));
40 if (ret != strlen("Yay!"))
41 err(1, "Write returned %i", ret);
45 return ntohs(protocol == AF_INET
46 ? addr.ipv4.sin_port : addr.ipv6.sin6_port);
49 /* Get a localhost on ipv4 and IPv6. Fake it if we can. */
50 static struct addrinfo* double_addr_lookup(char* buf, bool *fake_double)
52 struct addrinfo *addr, *addr2;
54 addr = net_client_lookup("localhost", buf, AF_UNSPEC, SOCK_STREAM);
58 /* If we only got one, we need to fake up the other one. */
60 addr2 = addr->ai_next;
64 if (addr->ai_family == AF_INET) {
65 /* These are the names I found on my Ubuntu system. */
66 addr2 = net_client_lookup("ip6-localhost", buf,
67 AF_UNSPEC, SOCK_STREAM);
69 addr2 = net_client_lookup("localhost6", buf,
73 addr2 = net_client_lookup("::1", buf,
76 } else if (addr->ai_family == AF_INET6)
77 /* IPv6 only? This is a guess... */
78 addr2 = net_client_lookup("ip4-localhost", buf,
79 AF_UNSPEC, SOCK_STREAM);
81 /* Perhaps no support on this system? Go ahead with one. */
88 addr->ai_next = addr2;
94 /* One IPv4 and one IPv6? */
95 if (addr->ai_family == AF_INET && addr2->ai_family == AF_INET6)
97 if (addr->ai_family == AF_INET6 && addr2->ai_family == AF_INET)
102 static void double_addr_free(struct addrinfo* addr, bool fake_double)
105 freeaddrinfo(addr->ai_next);
106 addr->ai_next = NULL;
113 struct addrinfo *addr;
115 struct sockaddr saddr;
123 port = server(AF_INET, SOCK_STREAM);
125 /* No IPv4 support? Maybe one day this will happen! */
126 if (errno == EAFNOSUPPORT)
127 skip(6, "No IPv4 socket support");
129 fail("Could not create IPv4 listening socket: %s",
132 sprintf(buf, "%u", port);
134 addr = double_addr_lookup(buf, &fake_double);
136 fd = net_connect(addr);
139 slen = sizeof(saddr);
140 ok1(getsockname(fd, &saddr, &slen) == 0);
141 diag("family = %d", saddr.sa_family);
142 ok1(saddr.sa_family == AF_INET);
143 status = read(fd, buf, sizeof(buf));
144 ok(status == strlen("Yay!"),
145 "Read returned %i (%s)", status, strerror(errno));
146 ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
148 double_addr_free(addr, fake_double);
151 port = server(AF_INET6, SOCK_STREAM);
153 /* No IPv6 support? */
154 if (errno == EAFNOSUPPORT)
155 skip(6, "No IPv6 socket support");
157 fail("Could not create IPv6 listening socket: %s",
160 sprintf(buf, "%u", port);
162 addr = double_addr_lookup(buf, &fake_double);
164 fd = net_connect(addr);
167 slen = sizeof(saddr);
168 ok1(getsockname(fd, &saddr, &slen) == 0);
169 ok1(saddr.sa_family == AF_INET6);
170 status = read(fd, buf, sizeof(buf));
171 ok(status == strlen("Yay!"),
172 "Read returned %i (%s)", status, strerror(errno));
173 ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
175 double_addr_free(addr, fake_double);
179 ok1(WIFEXITED(status));
180 ok1(WEXITSTATUS(status) == 0);
182 /* This exits depending on whether all tests passed */
183 return exit_status();