net: new module to help IPv4/IPv6 transition.
[ccan] / ccan / net / test / run.c
1 #include <ccan/net/net.h>
2 #include <ccan/net/net.c>
3 #include <ccan/tap/tap.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6 #include <err.h>
7
8 static unsigned int server(int protocol, int type)
9 {
10         int sock;
11         union {
12                 struct sockaddr addr;
13                 struct sockaddr_in ipv4;
14                 struct sockaddr_in6 ipv6;
15         } addr;
16         socklen_t addlen = sizeof(addr);
17
18         sock = socket(protocol, type, 0);
19
20         /* Bind to free port. */
21         listen(sock, 0);
22
23         /* Figure out what port it gave us. */
24         getsockname(sock, &addr.addr, &addlen);
25         fflush(stdout);
26
27         if (fork() == 0) {
28                 int ret, fd;
29
30                 alarm(3);
31                 fd = accept(sock, NULL, 0);
32                 if (fd < 0)
33                         err(1, "Accepting from socket %i", sock);
34
35                 ret = write(fd, "Yay!", strlen("Yay!"));
36                 if (ret != strlen("Yay!"))
37                         err(1, "Write returned %i", ret);
38                 exit(0);
39         }
40         close(sock);
41         return ntohs(protocol == AF_INET
42                      ? addr.ipv4.sin_port : addr.ipv6.sin6_port);
43 }
44
45 int main(void)
46 {
47         struct addrinfo *addr, *addr2;
48         int fd, status;
49         struct sockaddr saddr;
50         socklen_t slen = sizeof(saddr);
51         char buf[20];
52         unsigned int port;
53
54         plan_tests(16);
55         port = server(AF_INET, SOCK_STREAM);
56         sprintf(buf, "%u", port);
57
58         addr = net_client_lookup("localhost", buf, AF_UNSPEC, SOCK_STREAM);
59         addr2 = net_client_lookup("ip6-localhost", buf,
60                                   AF_UNSPEC, SOCK_STREAM);
61         ok1(addr);
62         ok1(addr2);
63         /* Join them as if they were from one lookup. */
64         addr->ai_next = addr2;
65
66         fd = net_connect(addr);
67         ok1(fd >= 0);
68
69         ok1(getsockname(fd, &saddr, &slen) == 0);
70         ok1(saddr.sa_family == AF_INET);
71         status = read(fd, buf, sizeof(buf));
72         ok(status == strlen("Yay!"),
73            "Read returned %i (%s)", status, strerror(errno));
74         ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
75         close(fd);
76         addr->ai_next = NULL;
77         freeaddrinfo(addr);
78         freeaddrinfo(addr2);
79
80         port = server(AF_INET6, SOCK_STREAM);
81         sprintf(buf, "%u", port);
82
83         addr = net_client_lookup("localhost", buf, AF_UNSPEC, SOCK_STREAM);
84         addr2 = net_client_lookup("ip6-localhost", buf,
85                                   AF_UNSPEC, SOCK_STREAM);
86         ok1(addr);
87         ok1(addr2);
88         /* Join them as if they were from one lookup. */
89         addr->ai_next = addr2;
90
91         fd = net_connect(addr);
92         ok1(fd >= 0);
93
94         ok1(getsockname(fd, &saddr, &slen) == 0);
95         ok1(saddr.sa_family == AF_INET6);
96         status = read(fd, buf, sizeof(buf));
97         ok(status == strlen("Yay!"),
98            "Read returned %i (%s)", status, strerror(errno));
99         ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
100         close(fd);
101         addr->ai_next = NULL;
102         freeaddrinfo(addr);
103         freeaddrinfo(addr2);
104
105         wait(&status);
106         ok1(WIFEXITED(status));
107         ok1(WEXITSTATUS(status) == 0);
108
109         /* This exits depending on whether all tests passed */
110         return exit_status();
111 }