Merge branch 'master' of ozlabs.org:ccan
[ccan] / ccan / io / test / run-01-start-finish.c
1 #include <ccan/io/io.h>
2 /* Include the C files directly. */
3 #include <ccan/io/poll.c>
4 #include <ccan/io/io.c>
5 #include <ccan/tap/tap.h>
6 #include <sys/wait.h>
7 #include <stdio.h>
8
9 #ifndef PORT
10 #define PORT "65001"
11 #endif
12
13 static void finish_ok(struct io_conn *conn, int *state)
14 {
15         ok1(*state == 1);
16         (*state)++;
17         io_break(state + 1, io_idle());
18 }
19
20 static void init_conn(int fd, int *state)
21 {
22         ok1(*state == 0);
23         (*state)++;
24         io_set_finish(io_new_conn(fd, io_close()), finish_ok, state);
25 }
26
27 static int make_listen_fd(const char *port, struct addrinfo **info)
28 {
29         int fd, on = 1;
30         struct addrinfo *addrinfo, hints;
31
32         memset(&hints, 0, sizeof(hints));
33         hints.ai_family = AF_UNSPEC;
34         hints.ai_socktype = SOCK_STREAM;
35         hints.ai_flags = AI_PASSIVE;
36         hints.ai_protocol = 0;
37
38         if (getaddrinfo(NULL, port, &hints, &addrinfo) != 0)
39                 return -1;
40
41         fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
42                     addrinfo->ai_protocol);
43         if (fd < 0)
44                 return -1;
45
46         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
47         if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) {
48                 close(fd);
49                 return -1;
50         }
51         if (listen(fd, 1) != 0) {
52                 close(fd);
53                 return -1;
54         }
55         *info = addrinfo;
56         return fd;
57 }
58
59 int main(void)
60 {
61         int state = 0;
62         struct addrinfo *addrinfo;
63         struct io_listener *l;
64         int fd;
65
66         /* This is how many tests you plan to run */
67         plan_tests(9);
68         fd = make_listen_fd(PORT, &addrinfo);
69         ok1(fd >= 0);
70         l = io_new_listener(fd, init_conn, &state);
71         ok1(l);
72         fflush(stdout);
73         if (!fork()) {
74                 io_close_listener(l);
75                 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
76                             addrinfo->ai_protocol);
77                 if (fd < 0)
78                         exit(1);
79                 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
80                         exit(2);
81                 close(fd);
82                 freeaddrinfo(addrinfo);
83                 exit(0);
84         }
85         freeaddrinfo(addrinfo);
86         ok1(io_loop() == &state + 1);
87         ok1(state == 2);
88         io_close_listener(l);
89         ok1(wait(&state));
90         ok1(WIFEXITED(state));
91         ok1(WEXITSTATUS(state) == 0);
92
93         /* This exits depending on whether all tests passed */
94         return exit_status();
95 }