timer: handle time going backwards.
[ccan] / ccan / io / test / run-18-errno.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 #define PORT "65018"
10
11 static void finish_100(struct io_conn *conn, int *state)
12 {
13         ok1(errno == 100);
14         ok1(*state == 1);
15         (*state)++;
16 }
17
18 static void finish_EBADF(struct io_conn *conn, int *state)
19 {
20         ok1(errno == EBADF);
21         ok1(*state == 3);
22         (*state)++;
23         io_break(state + 1);
24 }
25
26 static struct io_plan *init_conn(struct io_conn *conn, int *state)
27 {
28         if (*state == 0) {
29                 (*state)++;
30                 io_set_finish(conn, finish_100, state);
31                 errno = 100;
32                 return io_close(conn);
33         } else {
34                 ok1(*state == 2);
35                 (*state)++;
36                 close(io_conn_fd(conn));
37                 errno = 0;
38                 io_set_finish(conn, finish_EBADF, state);
39
40                 return io_read(conn, state, 1, io_close_cb, NULL);
41         }
42 }
43
44 static int make_listen_fd(const char *port, struct addrinfo **info)
45 {
46         int fd, on = 1;
47         struct addrinfo *addrinfo, hints;
48
49         memset(&hints, 0, sizeof(hints));
50         hints.ai_family = AF_UNSPEC;
51         hints.ai_socktype = SOCK_STREAM;
52         hints.ai_flags = AI_PASSIVE;
53         hints.ai_protocol = 0;
54
55         if (getaddrinfo(NULL, port, &hints, &addrinfo) != 0)
56                 return -1;
57
58         fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
59                     addrinfo->ai_protocol);
60         if (fd < 0)
61                 return -1;
62
63         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
64         if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) {
65                 close(fd);
66                 return -1;
67         }
68         if (listen(fd, 1) != 0) {
69                 close(fd);
70                 return -1;
71         }
72         *info = addrinfo;
73         return fd;
74 }
75
76 int main(void)
77 {
78         int state = 0;
79         struct addrinfo *addrinfo;
80         struct io_listener *l;
81         int fd;
82
83         /* This is how many tests you plan to run */
84         plan_tests(12);
85         fd = make_listen_fd(PORT, &addrinfo);
86         ok1(fd >= 0);
87         l = io_new_listener(NULL, fd, init_conn, &state);
88         ok1(l);
89         fflush(stdout);
90         if (!fork()) {
91                 io_close_listener(l);
92                 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
93                             addrinfo->ai_protocol);
94                 if (fd < 0)
95                         exit(1);
96                 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
97                         exit(2);
98                 close(fd);
99                 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
100                             addrinfo->ai_protocol);
101                 if (fd < 0)
102                         exit(3);
103                 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
104                         exit(4);
105                 close(fd);
106                 freeaddrinfo(addrinfo);
107                 exit(0);
108         }
109         freeaddrinfo(addrinfo);
110         ok1(io_loop(NULL, NULL) == &state + 1);
111         ok1(state == 4);
112         io_close_listener(l);
113         ok1(wait(&state));
114         ok1(WIFEXITED(state));
115         ok1(WEXITSTATUS(state) == 0);
116
117         /* This exits depending on whether all tests passed */
118         return exit_status();
119 }