timer: handle time going backwards.
[ccan] / ccan / net / test / run-bind.c
1 #include <ccan/net/net.h>
2 #include <ccan/tap/tap.h>
3 #include <sys/time.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/wait.h>
7 #include <stdio.h>
8 #include <err.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12
13 static int ipv6_only;
14
15 #ifdef IPV6_V6ONLY
16 static int my_setsockopt(int sockfd, int level, int optname,
17                          const void *optval, socklen_t optlen)
18 {
19         int ret;
20         setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only,
21                    sizeof(ipv6_only));
22         ret = setsockopt(sockfd, level, optname, optval, optlen);
23         return ret;
24 }
25 #define setsockopt my_setsockopt
26 #endif
27
28 #include <ccan/net/net.c>
29
30 #define TEST_PORT "65001"
31
32 static void do_connect(int family, int type)
33 {
34         int fd, ret;
35         struct addrinfo *addr;
36         char buf[8];
37
38         /* Just in case... */
39         alarm(5);
40         addr = net_client_lookup(NULL, TEST_PORT, family, type);
41         fd = net_connect(addr);
42         if (fd < 0)
43                 err(1, "Failed net_connect");
44         freeaddrinfo(addr);
45
46         ret = write(fd, "Yay!", strlen("Yay!"));
47         if (ret != strlen("Yay!"))
48                 err(1, "Write returned %i", ret);
49         ret = read(fd, buf, sizeof(buf));
50         if (ret != 5)
51                 err(1, "Read returned %i", ret);
52         if (memcmp(buf, "metoo", ret) != 0)
53                 err(1, "Read returned '%.*s'", ret, buf);
54         close(fd);
55 }
56
57 static int wait_for_readable(int fds[2], int num_fds)
58 {
59         int i, max_fd = -1;
60         fd_set set;
61
62         FD_ZERO(&set);
63         for (i = 0; i < num_fds; i++) {
64                 if (fds[i] > max_fd)
65                         max_fd = fds[i];
66                 FD_SET(fds[i], &set);
67         }
68
69         select(max_fd+1, &set, NULL, NULL, NULL);
70         for (i = 0; i < num_fds; i++) {
71                 if (FD_ISSET(fds[i], &set))
72                         return i;
73         }
74         return num_fds+1;
75 }
76
77 int main(void)
78 {
79         struct addrinfo *addr;
80         int fds[2], num_fds, i, fd, status, ret;
81         char buf[20];
82         union {
83                 struct sockaddr addr;
84                 struct sockaddr_in ipv4;
85                 struct sockaddr_in6 ipv6;
86         } remote_addr;
87         socklen_t addlen = sizeof(remote_addr);
88
89         plan_tests(35);
90
91         /* Simple TCP test. */
92         addr = net_server_lookup(TEST_PORT, AF_UNSPEC, SOCK_STREAM);
93         ok1(addr);
94         num_fds = net_bind(addr, fds);
95         ok1(num_fds == 1 || num_fds == 2);
96
97         if (!fork()) {
98                 for (i = 0; i < num_fds; i++)
99                         close(fds[i]);
100                 do_connect(AF_UNSPEC, SOCK_STREAM);
101                 exit(0);
102         }
103
104         i = wait_for_readable(fds, num_fds);
105         ok1(i < num_fds);
106         fd = accept(fds[i], NULL, NULL);
107         ok1(fd >= 0);
108
109         ret = read(fd, buf, strlen("Yay!"));
110         ok1(ret == strlen("Yay!"));
111         ok1(memcmp(buf, "Yay!", ret) == 0);
112         ret = write(fd, "metoo", strlen("metoo"));
113         ok1(ret == strlen("metoo"));
114         ok1(wait(&status) != -1);
115         ok1(WIFEXITED(status));
116         ok1(WEXITSTATUS(status) == 0);
117         close(fd);
118         for (i = 0; i < num_fds; i++)
119                 close(fds[i]);
120         freeaddrinfo(addr);
121
122         /* Simple UDP test. */
123         addr = net_server_lookup(TEST_PORT, AF_UNSPEC, SOCK_DGRAM);
124         ok1(addr);
125         num_fds = net_bind(addr, fds);
126         ok1(num_fds == 1 || num_fds == 2);
127
128         if (!fork()) {
129                 for (i = 0; i < num_fds; i++)
130                         close(fds[i]);
131                 do_connect(AF_UNSPEC, SOCK_DGRAM);
132                 exit(0);
133         }
134
135         i = wait_for_readable(fds, num_fds);
136         ok1(i < num_fds);
137         fd = fds[i];
138
139         ret = recvfrom(fd, buf, strlen("Yay!"), 0,
140                        (void *)&remote_addr, &addlen);
141         ok1(ret == strlen("Yay!"));
142         ok1(memcmp(buf, "Yay!", ret) == 0);
143         ret = sendto(fd, "metoo", strlen("metoo"), 0,
144                      (void *)&remote_addr, addlen);
145         ok1(ret == strlen("metoo"));
146         ok1(wait(&status) >= 0);
147         ok1(WIFEXITED(status));
148         ok1(WEXITSTATUS(status) == 0);
149         close(fd);
150         for (i = 0; i < num_fds; i++)
151                 close(fds[i]);
152
153 /* This seems like a Linux-only extension */
154 #ifdef IPV6_V6ONLY
155         /* Try to force separate sockets for IPv4/IPv6, if we can. */
156         if (addr->ai_next)
157                 ipv6_only = true;
158 #endif
159         freeaddrinfo(addr);
160
161         if (ipv6_only) {
162                 int j;
163
164                 addr = net_server_lookup(TEST_PORT, AF_UNSPEC, SOCK_STREAM);
165                 ok1(addr);
166                 num_fds = net_bind(addr, fds);
167                 ok1(num_fds == 2);
168                 freeaddrinfo(addr);
169
170                 if (!fork()) {
171                         for (i = 0; i < num_fds; i++)
172                                 close(fds[i]);
173                         do_connect(AF_INET, SOCK_STREAM);
174                         do_connect(AF_INET6, SOCK_STREAM);
175                         exit(0);
176                 }
177
178                 i = wait_for_readable(fds, num_fds);
179                 ok1(i < num_fds);
180                 fd = accept(fds[i], NULL, NULL);
181                 ok1(fd >= 0);
182
183                 ret = read(fd, buf, strlen("Yay!"));
184                 ok1(ret == strlen("Yay!"));
185                 ok1(memcmp(buf, "Yay!", ret) == 0);
186                 ret = write(fd, "metoo", strlen("metoo"));
187                 ok1(ret == strlen("metoo"));
188                 close(fd);
189
190                 j = wait_for_readable(fds, num_fds);
191                 ok1(j < num_fds);
192                 ok1(j != i);
193                 fd = accept(fds[j], NULL, NULL);
194                 ok1(fd >= 0);
195
196                 ret = read(fd, buf, strlen("Yay!"));
197                 ok1(ret == strlen("Yay!"));
198                 ok1(memcmp(buf, "Yay!", ret) == 0);
199                 ret = write(fd, "metoo", strlen("metoo"));
200                 ok1(ret == strlen("metoo"));
201
202                 ok1(wait(&status) >= 0);
203                 ok1(WIFEXITED(status));
204                 ok1(WEXITSTATUS(status) == 0);
205                 close(fd);
206         } else
207                 skip(16, "No support for IPv6-only binding");
208
209         for (i = 0; i < num_fds; i++)
210                 close(fds[i]);
211
212         /* This exits depending on whether all tests passed */
213         return exit_status();
214 }