]> git.ozlabs.org Git - ccan/blob - ccan/io/test/run-14-duplex-both-read.c
ccan/io: io_halfclose.
[ccan] / ccan / io / test / run-14-duplex-both-read.c
1 /* Check a bug where we have just completed a read, then set up a duplex
2  * which tries to do a read. */
3 #include <ccan/io/io.h>
4 /* Include the C files directly. */
5 #include <ccan/io/poll.c>
6 #include <ccan/io/io.c>
7 #include <ccan/tap/tap.h>
8 #include <sys/wait.h>
9 #include <stdio.h>
10
11 #ifdef DEBUG_CONN
12 #define PORT "64014"
13 #else
14 #define PORT "65014"
15 #endif
16
17 struct data {
18         struct io_listener *l;
19         int state;
20         char buf[4];
21         char wbuf[32];
22 };
23
24 static void finish_ok(struct io_conn *conn, struct data *d)
25 {
26         d->state++;
27 }
28
29 static struct io_plan *end(struct io_conn *conn, struct data *d)
30 {
31         d->state++;
32         /* Close on top of halfclose should work. */
33         if (d->state == 4)
34                 return io_close(conn);
35         else
36                 return io_halfclose(conn);
37 }
38
39 static struct io_plan *make_duplex(struct io_conn *conn, struct data *d)
40 {
41         d->state++;
42         /* Have duplex read the rest of the buffer. */
43         return io_duplex(conn,
44                          io_read(conn, d->buf+1, sizeof(d->buf)-1, end, d),
45                          io_write(conn, d->wbuf, sizeof(d->wbuf), end, d));
46 }
47
48 static struct io_plan *init_conn(struct io_conn *conn, struct data *d)
49 {
50 #ifdef DEBUG_CONN
51         io_set_debug(conn, true);
52 #endif
53         ok1(d->state == 0);
54         d->state++;
55
56         io_close_listener(d->l);
57
58         memset(d->wbuf, 7, sizeof(d->wbuf));
59         io_set_finish(conn, finish_ok, d);
60         return io_read(conn, d->buf, 1, make_duplex, d);
61 }
62
63 static int make_listen_fd(const char *port, struct addrinfo **info)
64 {
65         int fd, on = 1;
66         struct addrinfo *addrinfo, hints;
67
68         memset(&hints, 0, sizeof(hints));
69         hints.ai_family = AF_UNSPEC;
70         hints.ai_socktype = SOCK_STREAM;
71         hints.ai_flags = AI_PASSIVE;
72         hints.ai_protocol = 0;
73
74         if (getaddrinfo(NULL, port, &hints, &addrinfo) != 0)
75                 return -1;
76
77         fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
78                     addrinfo->ai_protocol);
79         if (fd < 0)
80                 return -1;
81
82         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
83         if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) {
84                 close(fd);
85                 return -1;
86         }
87         if (listen(fd, 1) != 0) {
88                 close(fd);
89                 return -1;
90         }
91         *info = addrinfo;
92         return fd;
93 }
94
95 int main(void)
96 {
97         struct data *d = malloc(sizeof(*d));
98         struct addrinfo *addrinfo;
99         int fd, status;
100
101         /* This is how many tests you plan to run */
102         plan_tests(9);
103         d->state = 0;
104         fd = make_listen_fd(PORT, &addrinfo);
105         ok1(fd >= 0);
106         d->l = io_new_listener(NULL, fd, init_conn, d);
107         ok1(d->l);
108         fflush(stdout);
109         if (!fork()) {
110                 int i;
111                 char buf[32];
112
113                 io_close_listener(d->l);
114                 free(d);
115                 fd = socket(addrinfo->ai_family, addrinfo->ai_socktype,
116                             addrinfo->ai_protocol);
117                 if (fd < 0)
118                         exit(1);
119                 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0)
120                         exit(2);
121                 signal(SIGPIPE, SIG_IGN);
122                 for (i = 0; i < strlen("hellothere"); i++) {
123                         if (write(fd, "hellothere" + i, 1) != 1)
124                                 break;
125                 }
126                 for (i = 0; i < 32; i++) {
127                         if (read(fd, buf+i, 1) != 1)
128                                 break;
129                 }
130                 close(fd);
131                 freeaddrinfo(addrinfo);
132                 exit(0);
133         }
134         freeaddrinfo(addrinfo);
135         ok1(io_loop(NULL, NULL) == NULL);
136         ok1(d->state == 5);
137         ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
138         free(d);
139
140         ok1(wait(&status));
141         ok1(WIFEXITED(status));
142         ok1(WEXITSTATUS(status) == 0);
143
144         /* This exits depending on whether all tests passed */
145         return exit_status();
146 }