]> git.ozlabs.org Git - ccan/blob - ccan/net/test/run.c
tdb2: suppress failtest more than once on mmap.
[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 <stdio.h>
7 #include <err.h>
8
9 static unsigned int server(int protocol, int type)
10 {
11         int sock;
12         union {
13                 struct sockaddr addr;
14                 struct sockaddr_in ipv4;
15                 struct sockaddr_in6 ipv6;
16         } addr;
17         socklen_t addlen = sizeof(addr);
18
19         sock = socket(protocol, type, 0);
20
21         /* Bind to free port. */
22         listen(sock, 0);
23
24         /* Figure out what port it gave us. */
25         getsockname(sock, &addr.addr, &addlen);
26         fflush(stdout);
27
28         if (fork() == 0) {
29                 int ret, fd;
30
31                 alarm(3);
32                 fd = accept(sock, NULL, 0);
33                 if (fd < 0)
34                         err(1, "Accepting from socket %i", sock);
35
36                 ret = write(fd, "Yay!", strlen("Yay!"));
37                 if (ret != strlen("Yay!"))
38                         err(1, "Write returned %i", ret);
39                 exit(0);
40         }
41         close(sock);
42         return ntohs(protocol == AF_INET
43                      ? addr.ipv4.sin_port : addr.ipv6.sin6_port);
44 }
45
46 static bool we_faked_double = false;
47
48 /* Get a localhost on ipv4 and IPv6.  Fake it if we have to. */
49 static struct addrinfo* double_addr_lookup(char* buf)
50 {
51         struct addrinfo *addr, *addr2;
52
53         addr = net_client_lookup("localhost", buf, AF_UNSPEC, SOCK_STREAM);
54         if (!addr)
55                 return addr;
56
57         /* If we only got one, we need to fake up the other one. */
58         if (addr->ai_next) {
59                 addr2 = addr->ai_next;
60         } else {
61                 we_faked_double = true;
62
63                 /* OK, IPv4 only? */
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);
68                         if (!addr2)
69                                 addr2 = net_client_lookup("localhost6", buf,
70                                                           AF_UNSPEC,
71                                                           SOCK_STREAM);
72                         if (!addr2)
73                                 addr2 = net_client_lookup("::1", buf,
74                                                           AF_UNSPEC,
75                                                           SOCK_STREAM);
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);
80                 if (!addr2)
81                         return NULL;
82                 addr->ai_next = addr2;
83         }
84
85         /* More than two? */
86         if (addr2->ai_next)
87                 return NULL;
88         /* One IPv4 and one IPv6? */
89         if (addr->ai_family == AF_INET && addr2->ai_family == AF_INET6)
90                 return addr;
91         if (addr->ai_family == AF_INET6 && addr2->ai_family == AF_INET)
92                 return addr;
93         return NULL;
94 }
95
96 static void double_addr_free(struct addrinfo* addr)
97 {
98         struct addrinfo *addr2;
99         if (we_faked_double) {
100                 addr2 = addr->ai_next;
101                 addr->ai_next = NULL;
102         }
103         freeaddrinfo(addr);
104         if (we_faked_double)
105                 freeaddrinfo(addr2);
106 }
107
108 int main(void)
109 {
110         struct addrinfo *addr;
111         int fd, status;
112         struct sockaddr saddr;
113         socklen_t slen;
114         char buf[20];
115         unsigned int port;
116
117         plan_tests(14);
118         port = server(AF_INET, SOCK_STREAM);
119         sprintf(buf, "%u", port);
120
121         addr = double_addr_lookup(buf);
122         ok1(addr);
123         fd = net_connect(addr);
124         ok1(fd >= 0);
125
126         slen = sizeof(saddr);
127         ok1(getsockname(fd, &saddr, &slen) == 0);
128         diag("family = %d", saddr.sa_family);
129         ok1(saddr.sa_family == AF_INET);
130         status = read(fd, buf, sizeof(buf));
131         ok(status == strlen("Yay!"),
132            "Read returned %i (%s)", status, strerror(errno));
133         ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
134         close(fd);
135         double_addr_free(addr);
136
137         port = server(AF_INET6, SOCK_STREAM);
138         sprintf(buf, "%u", port);
139
140         addr = double_addr_lookup(buf);
141         ok1(addr);
142         fd = net_connect(addr);
143         ok1(fd >= 0);
144
145         slen = sizeof(saddr);
146         ok1(getsockname(fd, &saddr, &slen) == 0);
147         ok1(saddr.sa_family == AF_INET6);
148         status = read(fd, buf, sizeof(buf));
149         ok(status == strlen("Yay!"),
150            "Read returned %i (%s)", status, strerror(errno));
151         ok1(strncmp(buf, "Yay!", strlen("Yay!")) == 0);
152         close(fd);
153         double_addr_free(addr);
154
155         wait(&status);
156         ok1(WIFEXITED(status));
157         ok1(WEXITSTATUS(status) == 0);
158
159         /* This exits depending on whether all tests passed */
160         return exit_status();
161 }