f7a0ecab7f3871045458e4886c6653e865f0ec5f
[ccan] / ccan / io / test / run-12-bidir.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 "65012"
11 #endif
12
13 struct data {
14         struct io_listener *l;
15         int state;
16         char buf[4];
17         char wbuf[32];
18 };
19
20 static void finish_ok(struct io_conn *conn, struct data *d)
21 {
22         d->state++;
23 }
24
25 static struct io_plan write_done(struct io_conn *conn, struct data *d)
26 {
27         d->state++;
28         return io_idle();
29 }
30
31 static void init_conn(int fd, struct data *d)
32 {
33         struct io_conn *conn;
34
35         ok1(d->state == 0);
36         d->state++;
37
38         io_close_listener(d->l);
39
40         memset(d->wbuf, 7, sizeof(d->wbuf));
41
42         conn = io_new_conn(fd, io_read(d->buf, sizeof(d->buf), io_close_cb, d));
43         io_set_finish(conn, finish_ok, d);
44         conn = io_duplex(conn, io_write(d->wbuf, sizeof(d->wbuf), write_done, d));
45         ok1(conn);
46         io_set_finish(conn, finish_ok, d);
47 }
48
49 static int make_listen_fd(const char *port, struct addrinfo **info)
50 {
51         int fd, on = 1;
52         struct addrinfo *addrinfo, hints;
53
54         memset(&hints, 0, sizeof(hints));
55         hints.ai_family = AF_UNSPEC;
56         hints.ai_socktype = SOCK_STREAM;
57         hints.ai_flags = AI_PASSIVE;
58         hints.ai_protocol = 0;
59
60         if (getaddrinfo(NULL, port, &hints, &addrinfo) != 0)
61                 return -1;
62
63         fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
64                     addrinfo->ai_protocol);
65         if (fd < 0)
66                 return -1;
67
68         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
69         if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) {
70                 close(fd);
71                 return -1;
72         }
73         if (listen(fd, 1) != 0) {
74                 close(fd);
75                 return -1;
76         }
77         *info = addrinfo;
78         return fd;
79 }
80
81 int main(void)
82 {
83         struct data *d = malloc(sizeof(*d));
84         struct addrinfo *addrinfo;
85         int fd, status;
86
87         /* This is how many tests you plan to run */
88         plan_tests(10);
89         d->state = 0;
90         fd = make_listen_fd(PORT, &addrinfo);
91         ok1(fd >= 0);
92         d->l = io_new_listener(fd, init_conn, d);
93         ok1(d->l);
94         fflush(stdout);
95         if (!fork()) {
96                 int i;
97                 char buf[32];
98
99                 io_close_listener(d->l);
100                 free(d);
101                 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
102                             addrinfo->ai_protocol);
103                 if (fd < 0)
104                         exit(1);
105                 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
106                         exit(2);
107                 signal(SIGPIPE, SIG_IGN);
108                 for (i = 0; i < 32; i++) {
109                         if (read(fd, buf+i, 1) != 1)
110                                 break;
111                 }
112                 for (i = 0; i < strlen("hellothere"); i++) {
113                         if (write(fd, "hellothere" + i, 1) != 1)
114                                 break;
115                 }
116                 close(fd);
117                 freeaddrinfo(addrinfo);
118                 exit(0);
119         }
120         freeaddrinfo(addrinfo);
121         ok1(io_loop() == NULL);
122         ok1(d->state == 4);
123         ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
124         free(d);
125
126         ok1(wait(&status));
127         ok1(WIFEXITED(status));
128         ok1(WEXITSTATUS(status) == 0);
129
130         /* This exits depending on whether all tests passed */
131         return exit_status();
132 }