]> git.ozlabs.org Git - ccan/blob - ccan/io/test/run-47-exclusive-duplex.c
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / io / test / run-47-exclusive-duplex.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 "65047"
10
11 struct data {
12         struct io_listener *l;
13         char *pattern;
14         char buf[30];
15         size_t buflen;
16 };
17
18 static struct io_plan *read_more(struct io_conn *conn, struct data *d);
19 static struct io_plan *write_more(struct io_conn *conn, struct data *d);
20
21 static struct io_plan *read_done(struct io_conn *conn, struct data *d)
22 {
23         tal_resize(&d->pattern, tal_count(d->pattern) + 1 + strlen(d->buf));
24         strcat(d->pattern, "<");
25         strcat(d->pattern, d->buf);
26         return read_more(conn, d);
27 }
28
29 static struct io_plan *read_more(struct io_conn *conn, struct data *d)
30 {
31         memset(d->buf, 0, sizeof(d->buf));
32         return io_read_partial(conn, d->buf, sizeof(d->buf), &d->buflen,
33                                read_done, d);
34 }
35
36 static struct io_plan *write_done(struct io_conn *conn, struct data *d)
37 {
38         tal_resize(&d->pattern, tal_count(d->pattern) + 1);
39         strcat(d->pattern, ">");
40         return write_more(conn, d);
41 }
42
43 static struct io_plan *write_more(struct io_conn *conn, struct data *d)
44 {
45         return io_write_partial(conn, d->buf, 1, &d->buflen,
46                                 write_done, d);
47 }
48
49 static struct io_plan *read_priority_init(struct io_conn *conn, struct data *d)
50 {
51         /* This should suppress the write */
52         ok1(io_conn_exclusive(conn, true));
53         return read_more(conn, d);
54 }
55
56 static struct io_plan *init_conn(struct io_conn *conn, struct data *d)
57 {
58         /* Free listener so when conns close we exit io_loop */
59         io_close_listener(d->l);
60
61         return io_duplex(conn, read_priority_init(conn, d), write_more(conn, d));
62 }
63
64
65 static int make_listen_fd(const char *port, struct addrinfo **info)
66 {
67         int fd, on = 1;
68         struct addrinfo *addrinfo, hints;
69
70         memset(&hints, 0, sizeof(hints));
71         hints.ai_family = AF_UNSPEC;
72         hints.ai_socktype = SOCK_STREAM;
73         hints.ai_flags = AI_PASSIVE;
74         hints.ai_protocol = 0;
75
76         if (getaddrinfo(NULL, port, &hints, &addrinfo) != 0)
77                 return -1;
78
79         fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
80                     addrinfo->ai_protocol);
81         if (fd < 0)
82                 return -1;
83
84         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
85         if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) {
86                 close(fd);
87                 return -1;
88         }
89         if (listen(fd, 1) != 0) {
90                 close(fd);
91                 return -1;
92         }
93         *info = addrinfo;
94         return fd;
95 }
96
97 int main(void)
98 {
99         struct addrinfo *addrinfo = NULL;
100         int fd, status;
101         struct data d;
102
103         /* This is how many tests you plan to run */
104         plan_tests(8);
105         fd = make_listen_fd(PORT, &addrinfo);
106         ok1(fd >= 0);
107         d.l = io_new_listener(NULL, fd, init_conn, &d);
108         ok1(d.l);
109         fflush(stdout);
110
111         if (!fork()) {
112                 io_close_listener(d.l);
113                 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
114                             addrinfo->ai_protocol);
115                 if (fd < 0)
116                         exit(1);
117                 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
118                         exit(2);
119                 signal(SIGPIPE, SIG_IGN);
120
121                 if (write(fd, "1hellothere", strlen("1hellothere")) != strlen("1hellothere"))
122                         exit(3);
123                 sleep(1);
124                 if (write(fd, "1helloagain", strlen("1helloagain")) != strlen("1helloagain"))
125                         exit(4);
126                 close(fd);
127                 freeaddrinfo(addrinfo);
128                 exit(0);
129         }
130         freeaddrinfo(addrinfo);
131
132         d.pattern = tal_arrz(NULL, char, 1);
133         ok1(io_loop(NULL, NULL) == NULL);
134         /* No trace of writes */
135         ok1(strcmp(d.pattern, "<1hellothere<1helloagain") == 0);
136         tal_free(d.pattern);
137
138         ok1(wait(&status));
139         ok1(WIFEXITED(status));
140         ok1(WEXITSTATUS(status) == 0);
141
142         /* This exits depending on whether all tests passed */
143         return exit_status();
144 }