1*e389c7c6Svisa /* $OpenBSD: poll_iocond.c,v 1.3 2021/12/27 16:38:06 visa Exp $ */
2f7e6f7c5Svisa
3f7e6f7c5Svisa /*
4f7e6f7c5Svisa * Copyright (c) 2021 Visa Hankala
5f7e6f7c5Svisa *
6f7e6f7c5Svisa * Permission to use, copy, modify, and distribute this software for any
7f7e6f7c5Svisa * purpose with or without fee is hereby granted, provided that the above
8f7e6f7c5Svisa * copyright notice and this permission notice appear in all copies.
9f7e6f7c5Svisa *
10f7e6f7c5Svisa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f7e6f7c5Svisa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f7e6f7c5Svisa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f7e6f7c5Svisa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f7e6f7c5Svisa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15f7e6f7c5Svisa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16f7e6f7c5Svisa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f7e6f7c5Svisa */
18f7e6f7c5Svisa
19f7e6f7c5Svisa /*
20f7e6f7c5Svisa * Test poll(2) with various I/O conditions.
21f7e6f7c5Svisa */
22f7e6f7c5Svisa
23f7e6f7c5Svisa #include <sys/types.h>
24f7e6f7c5Svisa #include <sys/ioctl.h>
25f7e6f7c5Svisa #include <sys/socket.h>
26f7e6f7c5Svisa #include <sys/stat.h>
27f7e6f7c5Svisa #include <sys/wait.h>
28f7e6f7c5Svisa #include <netinet/in.h>
29f7e6f7c5Svisa #include <netinet/tcp.h>
30f7e6f7c5Svisa #include <arpa/inet.h>
31f7e6f7c5Svisa
32f7e6f7c5Svisa #include <assert.h>
33f7e6f7c5Svisa #include <err.h>
34f7e6f7c5Svisa #include <fcntl.h>
35f7e6f7c5Svisa #include <poll.h>
36f7e6f7c5Svisa #include <stdio.h>
37f7e6f7c5Svisa #include <stdlib.h>
38f7e6f7c5Svisa #include <string.h>
39f7e6f7c5Svisa #include <unistd.h>
40f7e6f7c5Svisa
41f7e6f7c5Svisa #if defined(__OpenBSD__)
42f7e6f7c5Svisa /* for pty */
43f7e6f7c5Svisa #include <termios.h>
44f7e6f7c5Svisa #include <util.h>
45f7e6f7c5Svisa #endif
46f7e6f7c5Svisa
47f7e6f7c5Svisa #if !defined(__linux__)
48f7e6f7c5Svisa #define HAVE_SOCKADDR_LEN 1
49f7e6f7c5Svisa #endif
50f7e6f7c5Svisa
51f7e6f7c5Svisa #define MIN(a, b) ((a) <= (b) ? (a) : (b))
52f7e6f7c5Svisa
53f7e6f7c5Svisa #define TEST_FIFO_NAME "iocond_fifo"
54f7e6f7c5Svisa
55f7e6f7c5Svisa enum filetype {
56f7e6f7c5Svisa FTYPE_NONE,
57f7e6f7c5Svisa FTYPE_FIFO,
58f7e6f7c5Svisa FTYPE_PIPE,
59f7e6f7c5Svisa FTYPE_PTY,
60f7e6f7c5Svisa FTYPE_SOCKET_TCP,
61f7e6f7c5Svisa FTYPE_SOCKET_UDP,
62f7e6f7c5Svisa FTYPE_SOCKET_UNIX,
63f7e6f7c5Svisa };
64f7e6f7c5Svisa
65f7e6f7c5Svisa static struct {
66f7e6f7c5Svisa const char *name;
67f7e6f7c5Svisa enum filetype type;
68f7e6f7c5Svisa } filetypes[] = {
69f7e6f7c5Svisa { "fifo", FTYPE_FIFO },
70f7e6f7c5Svisa { "pipe", FTYPE_PIPE },
71f7e6f7c5Svisa #if defined(__OpenBSD__)
72f7e6f7c5Svisa { "pty", FTYPE_PTY },
73f7e6f7c5Svisa #endif
74f7e6f7c5Svisa { "socket-tcp", FTYPE_SOCKET_TCP },
75f7e6f7c5Svisa { "socket-udp", FTYPE_SOCKET_UDP },
76f7e6f7c5Svisa { "socket-unix", FTYPE_SOCKET_UNIX },
77f7e6f7c5Svisa };
78f7e6f7c5Svisa
79f7e6f7c5Svisa static enum filetype filetype = FTYPE_NONE;
80f7e6f7c5Svisa
81f7e6f7c5Svisa static void cleanup(void);
82f7e6f7c5Svisa static void proc_barrier(int);
83f7e6f7c5Svisa static void proc_child(int, int);
84f7e6f7c5Svisa static void proc_parent(int, int);
85f7e6f7c5Svisa
86f7e6f7c5Svisa int
main(int argc,char * argv[])87f7e6f7c5Svisa main(int argc, char *argv[])
88f7e6f7c5Svisa {
89f7e6f7c5Svisa const char *ftname;
90f7e6f7c5Svisa int bfd[2], fds[2];
91f7e6f7c5Svisa int child_fd = -1;
92f7e6f7c5Svisa int parent_fd = -1;
93f7e6f7c5Svisa int sock = -1;
94f7e6f7c5Svisa unsigned int i;
95f7e6f7c5Svisa pid_t pid;
96f7e6f7c5Svisa
97f7e6f7c5Svisa /* Enforce test timeout. */
98f7e6f7c5Svisa alarm(10);
99f7e6f7c5Svisa
100f7e6f7c5Svisa if (argc != 2) {
101f7e6f7c5Svisa fprintf(stderr, "usage: %s filetype\n", argv[0]);
102f7e6f7c5Svisa return 1;
103f7e6f7c5Svisa }
104f7e6f7c5Svisa ftname = argv[1];
105f7e6f7c5Svisa
106f7e6f7c5Svisa for (i = 0; i < sizeof(filetypes) / sizeof(filetypes[0]); i++) {
107f7e6f7c5Svisa if (strcmp(ftname, filetypes[i].name) == 0) {
108f7e6f7c5Svisa filetype = filetypes[i].type;
109f7e6f7c5Svisa break;
110f7e6f7c5Svisa }
111f7e6f7c5Svisa }
112f7e6f7c5Svisa if (filetype == FTYPE_NONE)
113f7e6f7c5Svisa errx(1, "unknown filetype");
114f7e6f7c5Svisa
115f7e6f7c5Svisa /* Open barrier sockets. */
116f7e6f7c5Svisa if (socketpair(AF_UNIX, SOCK_STREAM, 0, bfd) == -1)
117f7e6f7c5Svisa err(1, "socketpair");
118f7e6f7c5Svisa
119f7e6f7c5Svisa atexit(cleanup);
120f7e6f7c5Svisa
121f7e6f7c5Svisa switch (filetype) {
122f7e6f7c5Svisa case FTYPE_FIFO:
123f7e6f7c5Svisa (void)unlink(TEST_FIFO_NAME);
124f7e6f7c5Svisa if (mkfifo(TEST_FIFO_NAME, 0644) == -1)
125f7e6f7c5Svisa err(1, "mkfifo");
126f7e6f7c5Svisa break;
127f7e6f7c5Svisa case FTYPE_PIPE:
128f7e6f7c5Svisa if (pipe(fds) == -1)
129f7e6f7c5Svisa err(1, "pipe");
130f7e6f7c5Svisa parent_fd = fds[0];
131f7e6f7c5Svisa child_fd = fds[1];
132f7e6f7c5Svisa break;
133f7e6f7c5Svisa #if defined(__OpenBSD__)
134f7e6f7c5Svisa case FTYPE_PTY:
135f7e6f7c5Svisa if (openpty(&parent_fd, &child_fd, NULL, NULL, NULL) == -1)
136f7e6f7c5Svisa err(1, "openpty");
137f7e6f7c5Svisa break;
138f7e6f7c5Svisa #endif
139f7e6f7c5Svisa case FTYPE_SOCKET_TCP: {
140f7e6f7c5Svisa struct sockaddr_in inaddr;
141f7e6f7c5Svisa
142f7e6f7c5Svisa sock = socket(AF_INET, SOCK_STREAM, 0);
143f7e6f7c5Svisa
144f7e6f7c5Svisa memset(&inaddr, 0, sizeof(inaddr));
145f7e6f7c5Svisa #ifdef HAVE_SOCKADDR_LEN
146f7e6f7c5Svisa inaddr.sin_len = sizeof(inaddr);
147f7e6f7c5Svisa #endif
148f7e6f7c5Svisa inaddr.sin_family = AF_INET;
149f7e6f7c5Svisa inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
150f7e6f7c5Svisa if (bind(sock, (struct sockaddr *)&inaddr,
151f7e6f7c5Svisa sizeof(inaddr)) == -1)
152f7e6f7c5Svisa err(1, "bind");
153f7e6f7c5Svisa if (listen(sock, 1) == -1)
154f7e6f7c5Svisa err(1, "listen");
155f7e6f7c5Svisa break;
156f7e6f7c5Svisa }
157f7e6f7c5Svisa case FTYPE_SOCKET_UDP: {
158f7e6f7c5Svisa struct sockaddr_in inaddr;
159f7e6f7c5Svisa
160f7e6f7c5Svisa sock = socket(AF_INET, SOCK_DGRAM, 0);
161f7e6f7c5Svisa
162f7e6f7c5Svisa memset(&inaddr, 0, sizeof(inaddr));
163f7e6f7c5Svisa #ifdef HAVE_SOCKADDR_LEN
164f7e6f7c5Svisa inaddr.sin_len = sizeof(inaddr);
165f7e6f7c5Svisa #endif
166f7e6f7c5Svisa inaddr.sin_family = AF_INET;
167f7e6f7c5Svisa inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
168f7e6f7c5Svisa if (bind(sock, (struct sockaddr *)&inaddr,
169f7e6f7c5Svisa sizeof(inaddr)) == -1)
170f7e6f7c5Svisa err(1, "bind");
171f7e6f7c5Svisa break;
172f7e6f7c5Svisa }
173f7e6f7c5Svisa case FTYPE_SOCKET_UNIX:
174f7e6f7c5Svisa if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1)
175f7e6f7c5Svisa err(1, "socketpair");
176f7e6f7c5Svisa parent_fd = fds[0];
177f7e6f7c5Svisa child_fd = fds[1];
178f7e6f7c5Svisa break;
179f7e6f7c5Svisa default:
180f7e6f7c5Svisa errx(1, "unhandled filetype");
181f7e6f7c5Svisa }
182f7e6f7c5Svisa
183f7e6f7c5Svisa pid = fork();
184f7e6f7c5Svisa switch (pid) {
185f7e6f7c5Svisa case -1:
186f7e6f7c5Svisa err(1, "fork");
187f7e6f7c5Svisa case 0:
188f7e6f7c5Svisa switch (filetype) {
189f7e6f7c5Svisa case FTYPE_FIFO:
190f7e6f7c5Svisa child_fd = open(TEST_FIFO_NAME, O_WRONLY);
191f7e6f7c5Svisa if (child_fd == -1)
192f7e6f7c5Svisa err(1, "child: open");
193f7e6f7c5Svisa break;
194f7e6f7c5Svisa case FTYPE_SOCKET_TCP: {
195f7e6f7c5Svisa struct sockaddr_in inaddr;
196f7e6f7c5Svisa socklen_t inaddrlen;
197f7e6f7c5Svisa int on = 1;
198f7e6f7c5Svisa
199f7e6f7c5Svisa /* Get the bound address. */
200f7e6f7c5Svisa inaddrlen = sizeof(inaddr);
201f7e6f7c5Svisa if (getsockname(sock, (struct sockaddr *)&inaddr,
202f7e6f7c5Svisa &inaddrlen) == -1)
203f7e6f7c5Svisa err(1, "child: getsockname");
204f7e6f7c5Svisa
205f7e6f7c5Svisa child_fd = socket(AF_INET, SOCK_STREAM, 0);
206f7e6f7c5Svisa if (child_fd == -1)
207f7e6f7c5Svisa err(1, "child: socket");
208f7e6f7c5Svisa if (connect(child_fd, (struct sockaddr *)&inaddr,
209f7e6f7c5Svisa sizeof(inaddr)) == -1)
210f7e6f7c5Svisa err(1, "child: connect");
211f7e6f7c5Svisa if (setsockopt(child_fd, IPPROTO_TCP, TCP_NODELAY,
212f7e6f7c5Svisa &on, sizeof(on)) == -1)
213f7e6f7c5Svisa err(1, "child: setsockopt(TCP_NODELAY)");
214f7e6f7c5Svisa break;
215f7e6f7c5Svisa }
216f7e6f7c5Svisa case FTYPE_SOCKET_UDP: {
217f7e6f7c5Svisa struct sockaddr_in inaddr;
218f7e6f7c5Svisa socklen_t inaddrlen;
219f7e6f7c5Svisa
220f7e6f7c5Svisa /* Get the bound address. */
221f7e6f7c5Svisa inaddrlen = sizeof(inaddr);
222f7e6f7c5Svisa if (getsockname(sock, (struct sockaddr *)&inaddr,
223f7e6f7c5Svisa &inaddrlen) == -1)
224f7e6f7c5Svisa err(1, "child: getsockname");
225f7e6f7c5Svisa
226f7e6f7c5Svisa child_fd = socket(AF_INET, SOCK_DGRAM, 0);
227f7e6f7c5Svisa if (child_fd == -1)
228f7e6f7c5Svisa err(1, "child: socket");
229f7e6f7c5Svisa if (connect(child_fd, (struct sockaddr *)&inaddr,
230f7e6f7c5Svisa sizeof(inaddr)) == -1)
231f7e6f7c5Svisa err(1, "child: connect");
232f7e6f7c5Svisa break;
233f7e6f7c5Svisa }
234f7e6f7c5Svisa default:
235f7e6f7c5Svisa break;
236f7e6f7c5Svisa }
237f7e6f7c5Svisa if (parent_fd != -1) {
238f7e6f7c5Svisa close(parent_fd);
239f7e6f7c5Svisa parent_fd = -1;
240f7e6f7c5Svisa }
241f7e6f7c5Svisa if (sock != -1) {
242f7e6f7c5Svisa close(sock);
243f7e6f7c5Svisa sock = -1;
244f7e6f7c5Svisa }
245f7e6f7c5Svisa proc_child(child_fd, bfd[1]);
246f7e6f7c5Svisa _exit(0);
247f7e6f7c5Svisa default:
248f7e6f7c5Svisa switch (filetype) {
249f7e6f7c5Svisa case FTYPE_FIFO:
250f7e6f7c5Svisa parent_fd = open(TEST_FIFO_NAME, O_RDONLY);
251f7e6f7c5Svisa if (parent_fd == -1)
252f7e6f7c5Svisa err(1, "parent: open");
253f7e6f7c5Svisa break;
254f7e6f7c5Svisa case FTYPE_SOCKET_TCP: {
255f7e6f7c5Svisa int on = 1;
256f7e6f7c5Svisa
257f7e6f7c5Svisa parent_fd = accept(sock, NULL, NULL);
258f7e6f7c5Svisa if (parent_fd == -1)
259f7e6f7c5Svisa err(1, "parent: accept");
260f7e6f7c5Svisa if (setsockopt(parent_fd, IPPROTO_TCP, TCP_NODELAY,
261f7e6f7c5Svisa &on, sizeof(on)) == -1)
262f7e6f7c5Svisa err(1, "parent: setsockopt(TCP_NODELAY)");
263f7e6f7c5Svisa break;
264f7e6f7c5Svisa }
265f7e6f7c5Svisa case FTYPE_SOCKET_UDP:
266f7e6f7c5Svisa parent_fd = sock;
267f7e6f7c5Svisa sock = -1;
268f7e6f7c5Svisa break;
269f7e6f7c5Svisa default:
270f7e6f7c5Svisa break;
271f7e6f7c5Svisa }
272f7e6f7c5Svisa if (child_fd != -1) {
273f7e6f7c5Svisa close(child_fd);
274f7e6f7c5Svisa child_fd = -1;
275f7e6f7c5Svisa }
276f7e6f7c5Svisa if (sock != -1) {
277f7e6f7c5Svisa close(sock);
278f7e6f7c5Svisa sock = -1;
279f7e6f7c5Svisa }
280f7e6f7c5Svisa proc_parent(parent_fd, bfd[0]);
281f7e6f7c5Svisa break;
282f7e6f7c5Svisa }
283f7e6f7c5Svisa
284f7e6f7c5Svisa if (waitpid(pid, NULL, 0) == -1)
285f7e6f7c5Svisa err(1, "waitpid");
286f7e6f7c5Svisa
287f7e6f7c5Svisa return 0;
288f7e6f7c5Svisa }
289f7e6f7c5Svisa
290f7e6f7c5Svisa static void
cleanup(void)291f7e6f7c5Svisa cleanup(void)
292f7e6f7c5Svisa {
293f7e6f7c5Svisa if (filetype == FTYPE_FIFO)
294f7e6f7c5Svisa (void)unlink(TEST_FIFO_NAME);
295f7e6f7c5Svisa }
296f7e6f7c5Svisa
297f7e6f7c5Svisa static void
proc_barrier(int fd)298f7e6f7c5Svisa proc_barrier(int fd)
299f7e6f7c5Svisa {
300f7e6f7c5Svisa int ret;
301f7e6f7c5Svisa char b = 0;
302f7e6f7c5Svisa
303f7e6f7c5Svisa ret = write(fd, &b, 1);
304f7e6f7c5Svisa assert(ret == 1);
305f7e6f7c5Svisa ret = read(fd, &b, 1);
306f7e6f7c5Svisa assert(ret == 1);
307f7e6f7c5Svisa }
308f7e6f7c5Svisa
309f7e6f7c5Svisa static void
proc_child(int fd,int bfd)310f7e6f7c5Svisa proc_child(int fd, int bfd)
311f7e6f7c5Svisa {
312f7e6f7c5Svisa struct pollfd pfd[2];
313f7e6f7c5Svisa char buf[1024];
314f7e6f7c5Svisa size_t nbytes;
315f7e6f7c5Svisa int ret;
316f7e6f7c5Svisa char b = 0;
317f7e6f7c5Svisa
318f7e6f7c5Svisa memset(&pfd, 0, sizeof(pfd));
319f7e6f7c5Svisa
320f7e6f7c5Svisa proc_barrier(bfd);
321f7e6f7c5Svisa
322f7e6f7c5Svisa pfd[0].fd = fd;
323f7e6f7c5Svisa pfd[0].events = POLLIN | POLLOUT | POLLPRI;
324f7e6f7c5Svisa
325f7e6f7c5Svisa ret = poll(pfd, 1, 1);
326f7e6f7c5Svisa assert(ret == 1);
327f7e6f7c5Svisa assert(pfd[0].revents == POLLOUT);
328f7e6f7c5Svisa
329f7e6f7c5Svisa proc_barrier(bfd);
330f7e6f7c5Svisa
331f7e6f7c5Svisa ret = write(fd, &b, 1);
332f7e6f7c5Svisa assert(ret == 1);
333f7e6f7c5Svisa
334f7e6f7c5Svisa proc_barrier(bfd);
335f7e6f7c5Svisa
336f7e6f7c5Svisa ret = poll(pfd, 1, 1);
337f7e6f7c5Svisa assert(ret == 1);
338f7e6f7c5Svisa assert(pfd[0].revents == POLLOUT);
339f7e6f7c5Svisa
340f7e6f7c5Svisa proc_barrier(bfd);
341f7e6f7c5Svisa
342f7e6f7c5Svisa /* parent: read */
343f7e6f7c5Svisa
344f7e6f7c5Svisa proc_barrier(bfd);
345f7e6f7c5Svisa
346f7e6f7c5Svisa if (filetype != FTYPE_SOCKET_UDP) {
347f7e6f7c5Svisa /* write until full */
348f7e6f7c5Svisa memset(buf, 0, sizeof(buf));
349f7e6f7c5Svisa nbytes = 0;
350f7e6f7c5Svisa for (;;) {
351f7e6f7c5Svisa pfd[0].fd = fd;
352f7e6f7c5Svisa pfd[0].events = POLLOUT;
353f7e6f7c5Svisa ret = poll(pfd, 1, 0);
354f7e6f7c5Svisa if (ret == 0)
355f7e6f7c5Svisa break;
356f7e6f7c5Svisa assert(ret == 1);
357f7e6f7c5Svisa assert(pfd[0].revents == POLLOUT);
358f7e6f7c5Svisa ret = write(fd, buf, sizeof(buf));
359f7e6f7c5Svisa assert(ret > 0);
360f7e6f7c5Svisa nbytes += ret;
361f7e6f7c5Svisa }
362f7e6f7c5Svisa ret = write(bfd, &nbytes, sizeof(nbytes));
363f7e6f7c5Svisa assert(ret == sizeof(nbytes));
364f7e6f7c5Svisa
365f7e6f7c5Svisa proc_barrier(bfd);
366f7e6f7c5Svisa
367f7e6f7c5Svisa /* parent: read until empty */
368f7e6f7c5Svisa }
369f7e6f7c5Svisa
370f7e6f7c5Svisa proc_barrier(bfd);
371f7e6f7c5Svisa
372f7e6f7c5Svisa /* Test out-of-band data. */
373f7e6f7c5Svisa switch (filetype) {
374f7e6f7c5Svisa #if defined(__OpenBSD__)
375f7e6f7c5Svisa case FTYPE_PTY: {
376f7e6f7c5Svisa /* parent: enable user ioctl command mode */
377f7e6f7c5Svisa
378f7e6f7c5Svisa proc_barrier(bfd);
379f7e6f7c5Svisa
380f7e6f7c5Svisa ret = write(fd, &b, 1);
381f7e6f7c5Svisa assert(ret == 1);
382f7e6f7c5Svisa
383f7e6f7c5Svisa if (ioctl(fd, UIOCCMD(42), NULL) == -1)
384f7e6f7c5Svisa err(1, "child: ioctl(UIOCCMD)");
385f7e6f7c5Svisa
386f7e6f7c5Svisa ret = write(fd, &b, 1);
387f7e6f7c5Svisa assert(ret == 1);
388f7e6f7c5Svisa
389f7e6f7c5Svisa proc_barrier(bfd);
390f7e6f7c5Svisa
391f7e6f7c5Svisa /* parent: read, and disable user ioctl command mode */
392f7e6f7c5Svisa
393f7e6f7c5Svisa proc_barrier(bfd);
394f7e6f7c5Svisa break;
395f7e6f7c5Svisa }
396f7e6f7c5Svisa #endif /* __OpenBSD__ */
397f7e6f7c5Svisa
398f7e6f7c5Svisa case FTYPE_SOCKET_TCP:
399*e389c7c6Svisa ret = send(fd, &b, 1, 0);
400*e389c7c6Svisa assert(ret == 1);
401f7e6f7c5Svisa
402f7e6f7c5Svisa ret = send(fd, &b, 1, MSG_OOB);
403f7e6f7c5Svisa assert(ret == 1);
404f7e6f7c5Svisa
405*e389c7c6Svisa ret = send(fd, &b, 1, 0);
406*e389c7c6Svisa assert(ret == 1);
407f7e6f7c5Svisa
408f7e6f7c5Svisa proc_barrier(bfd);
409f7e6f7c5Svisa
410f7e6f7c5Svisa /* parent: read */
411f7e6f7c5Svisa
412f7e6f7c5Svisa proc_barrier(bfd);
413f7e6f7c5Svisa break;
414f7e6f7c5Svisa
415f7e6f7c5Svisa default:
416f7e6f7c5Svisa break;
417f7e6f7c5Svisa }
418f7e6f7c5Svisa
419f7e6f7c5Svisa /* Test socket shutdown. */
420f7e6f7c5Svisa switch (filetype) {
421f7e6f7c5Svisa case FTYPE_SOCKET_TCP:
422f7e6f7c5Svisa case FTYPE_SOCKET_UNIX:
423f7e6f7c5Svisa ret = write(fd, &b, 1);
424f7e6f7c5Svisa assert(ret == 1);
425f7e6f7c5Svisa
426f7e6f7c5Svisa ret = shutdown(fd, SHUT_WR);
427f7e6f7c5Svisa assert(ret == 0);
428f7e6f7c5Svisa
429f7e6f7c5Svisa proc_barrier(bfd);
430f7e6f7c5Svisa
431f7e6f7c5Svisa /* parent: read and shutdown */
432f7e6f7c5Svisa
433f7e6f7c5Svisa proc_barrier(bfd);
434f7e6f7c5Svisa
435f7e6f7c5Svisa /* Let inet sockets take their time. */
436f7e6f7c5Svisa if (filetype == FTYPE_SOCKET_TCP)
437f7e6f7c5Svisa usleep(10000);
438f7e6f7c5Svisa
439f7e6f7c5Svisa pfd[0].fd = fd;
440f7e6f7c5Svisa pfd[0].events = POLLIN | POLLOUT | POLLPRI;
441f7e6f7c5Svisa pfd[1].fd = fd;
442f7e6f7c5Svisa pfd[1].events = 0;
443f7e6f7c5Svisa
444f7e6f7c5Svisa ret = poll(pfd, 2, 1);
445f7e6f7c5Svisa #if defined(__linux__)
446f7e6f7c5Svisa assert(ret == 2);
447f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP));
448f7e6f7c5Svisa assert(pfd[1].revents == POLLHUP);
449f7e6f7c5Svisa #else
450f7e6f7c5Svisa #if defined(__OpenBSD__)
451f7e6f7c5Svisa /* XXX */
452f7e6f7c5Svisa if (filetype == FTYPE_SOCKET_UNIX) {
453f7e6f7c5Svisa assert(ret == 1);
454f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT));
455f7e6f7c5Svisa assert(pfd[1].revents == 0);
456f7e6f7c5Svisa } else {
457f7e6f7c5Svisa #endif /* __OpenBSD__ */
458f7e6f7c5Svisa assert(ret == 2);
459f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLHUP));
460f7e6f7c5Svisa assert(pfd[1].revents == POLLHUP);
461f7e6f7c5Svisa #if defined(__OpenBSD__)
462f7e6f7c5Svisa }
463f7e6f7c5Svisa #endif /* __OpenBSD__ */
464f7e6f7c5Svisa #endif
465f7e6f7c5Svisa break;
466f7e6f7c5Svisa
467f7e6f7c5Svisa case FTYPE_FIFO:
468f7e6f7c5Svisa case FTYPE_PIPE:
469f7e6f7c5Svisa case FTYPE_PTY:
470f7e6f7c5Svisa case FTYPE_SOCKET_UDP:
471f7e6f7c5Svisa default:
472f7e6f7c5Svisa break;
473f7e6f7c5Svisa }
474f7e6f7c5Svisa
475f7e6f7c5Svisa proc_barrier(bfd);
476f7e6f7c5Svisa
477f7e6f7c5Svisa close(fd);
478f7e6f7c5Svisa
479f7e6f7c5Svisa proc_barrier(bfd);
480f7e6f7c5Svisa
481f7e6f7c5Svisa pfd[0].fd = fd;
482f7e6f7c5Svisa pfd[0].events = 0;
483f7e6f7c5Svisa
484f7e6f7c5Svisa ret = poll(pfd, 1, 1);
485f7e6f7c5Svisa assert(ret == 1);
486f7e6f7c5Svisa assert(pfd[0].revents == POLLNVAL);
487f7e6f7c5Svisa }
488f7e6f7c5Svisa
489f7e6f7c5Svisa static void
proc_parent(int fd,int bfd)490f7e6f7c5Svisa proc_parent(int fd, int bfd)
491f7e6f7c5Svisa {
492f7e6f7c5Svisa struct pollfd pfd[2];
493f7e6f7c5Svisa char buf[1024];
494f7e6f7c5Svisa size_t nbytes;
495f7e6f7c5Svisa int ret, retries;
496f7e6f7c5Svisa char b = 0;
497f7e6f7c5Svisa
498f7e6f7c5Svisa memset(&pfd, 0, sizeof(pfd));
499f7e6f7c5Svisa
500f7e6f7c5Svisa proc_barrier(bfd);
501f7e6f7c5Svisa
502f7e6f7c5Svisa pfd[0].fd = fd;
503f7e6f7c5Svisa pfd[0].events = POLLIN | POLLOUT | POLLPRI;
504f7e6f7c5Svisa if (filetype == FTYPE_FIFO || filetype == FTYPE_PIPE)
505f7e6f7c5Svisa pfd[0].events &= ~POLLOUT;
506f7e6f7c5Svisa
507f7e6f7c5Svisa ret = poll(pfd, 1, 1);
508f7e6f7c5Svisa switch (filetype) {
509f7e6f7c5Svisa case FTYPE_FIFO:
510f7e6f7c5Svisa case FTYPE_PIPE:
511f7e6f7c5Svisa assert(ret == 0);
512f7e6f7c5Svisa assert(pfd[0].revents == 0);
513f7e6f7c5Svisa break;
514f7e6f7c5Svisa default:
515f7e6f7c5Svisa assert(ret == 1);
516f7e6f7c5Svisa assert(pfd[0].revents == POLLOUT);
517f7e6f7c5Svisa break;
518f7e6f7c5Svisa }
519f7e6f7c5Svisa
520f7e6f7c5Svisa proc_barrier(bfd);
521f7e6f7c5Svisa
522f7e6f7c5Svisa /* child: write */
523f7e6f7c5Svisa
524f7e6f7c5Svisa proc_barrier(bfd);
525f7e6f7c5Svisa
526f7e6f7c5Svisa /* Let inet sockets take their time. */
527f7e6f7c5Svisa if (filetype == FTYPE_SOCKET_TCP ||
528f7e6f7c5Svisa filetype == FTYPE_SOCKET_UDP)
529f7e6f7c5Svisa usleep(10000);
530f7e6f7c5Svisa
531f7e6f7c5Svisa ret = poll(pfd, 1, 1);
532f7e6f7c5Svisa switch (filetype) {
533f7e6f7c5Svisa case FTYPE_FIFO:
534f7e6f7c5Svisa case FTYPE_PIPE:
535f7e6f7c5Svisa assert(ret == 1);
536f7e6f7c5Svisa assert(pfd[0].revents == POLLIN);
537f7e6f7c5Svisa break;
538f7e6f7c5Svisa case FTYPE_PTY:
539f7e6f7c5Svisa case FTYPE_SOCKET_TCP:
540f7e6f7c5Svisa case FTYPE_SOCKET_UDP:
541f7e6f7c5Svisa case FTYPE_SOCKET_UNIX:
542f7e6f7c5Svisa assert(ret == 1);
543f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT));
544f7e6f7c5Svisa break;
545f7e6f7c5Svisa default:
546f7e6f7c5Svisa assert(0);
547f7e6f7c5Svisa }
548f7e6f7c5Svisa
549f7e6f7c5Svisa proc_barrier(bfd);
550f7e6f7c5Svisa
551f7e6f7c5Svisa ret = read(fd, &b, 1);
552f7e6f7c5Svisa assert(ret == 1);
553f7e6f7c5Svisa
554f7e6f7c5Svisa pfd[0].fd = fd;
555f7e6f7c5Svisa pfd[0].events = POLLIN;
556f7e6f7c5Svisa
557f7e6f7c5Svisa ret = poll(pfd, 1, 1);
558f7e6f7c5Svisa assert(ret == 0);
559f7e6f7c5Svisa
560f7e6f7c5Svisa proc_barrier(bfd);
561f7e6f7c5Svisa
562f7e6f7c5Svisa if (filetype != FTYPE_SOCKET_UDP) {
563f7e6f7c5Svisa /* child: write until full */
564f7e6f7c5Svisa nbytes = 0;
565f7e6f7c5Svisa ret = read(bfd, &nbytes, sizeof(nbytes));
566f7e6f7c5Svisa assert(ret == sizeof(nbytes));
567f7e6f7c5Svisa
568f7e6f7c5Svisa proc_barrier(bfd);
569f7e6f7c5Svisa
570f7e6f7c5Svisa /* read until empty */
571f7e6f7c5Svisa retries = 5;
572f7e6f7c5Svisa while (retries > 0) {
573f7e6f7c5Svisa pfd[0].fd = fd;
574f7e6f7c5Svisa pfd[0].events = POLLIN;
575f7e6f7c5Svisa ret = poll(pfd, 1, 0);
576f7e6f7c5Svisa if (ret == 0) {
577f7e6f7c5Svisa retries--;
578f7e6f7c5Svisa /* Let inet sockets take their time. */
579f7e6f7c5Svisa if (nbytes > 0 && retries > 0)
580f7e6f7c5Svisa usleep(10000);
581f7e6f7c5Svisa continue;
582f7e6f7c5Svisa }
583f7e6f7c5Svisa assert(ret == 1);
584f7e6f7c5Svisa assert(pfd[0].revents == POLLIN);
585f7e6f7c5Svisa assert(nbytes > 0);
586f7e6f7c5Svisa ret = read(fd, buf, MIN(sizeof(buf), nbytes));
587f7e6f7c5Svisa assert(ret > 0);
588f7e6f7c5Svisa nbytes -= ret;
589f7e6f7c5Svisa }
590f7e6f7c5Svisa assert(nbytes == 0);
591f7e6f7c5Svisa }
592f7e6f7c5Svisa
593f7e6f7c5Svisa proc_barrier(bfd);
594f7e6f7c5Svisa
595f7e6f7c5Svisa /* Test out-of-band data. */
596f7e6f7c5Svisa switch (filetype) {
597f7e6f7c5Svisa #if defined(__OpenBSD__)
598f7e6f7c5Svisa case FTYPE_PTY: {
599f7e6f7c5Svisa int off = 0;
600f7e6f7c5Svisa int on = 1;
601f7e6f7c5Svisa
602f7e6f7c5Svisa if (ioctl(fd, TIOCUCNTL, &on) == -1)
603f7e6f7c5Svisa err(1, "parent: ioctl(TIOCUCNTL, 1)");
604f7e6f7c5Svisa
605f7e6f7c5Svisa proc_barrier(bfd);
606f7e6f7c5Svisa
607f7e6f7c5Svisa /* child: write */
608f7e6f7c5Svisa
609f7e6f7c5Svisa proc_barrier(bfd);
610f7e6f7c5Svisa
611f7e6f7c5Svisa pfd[0].fd = fd;
612f7e6f7c5Svisa pfd[0].events = POLLIN | POLLOUT | POLLPRI;
613f7e6f7c5Svisa pfd[1].fd = fd;
614f7e6f7c5Svisa pfd[1].events = 0;
615f7e6f7c5Svisa
616f7e6f7c5Svisa ret = poll(pfd, 2, 1);
617f7e6f7c5Svisa assert(ret == 1);
618f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI));
619f7e6f7c5Svisa assert(pfd[1].revents == 0);
620f7e6f7c5Svisa
621f7e6f7c5Svisa /* Read out-of-band data. */
622f7e6f7c5Svisa ret = read(fd, buf, sizeof(buf));
623f7e6f7c5Svisa assert(ret == 1);
624f7e6f7c5Svisa
625f7e6f7c5Svisa ret = poll(pfd, 2, 1);
626f7e6f7c5Svisa assert(ret == 1);
627f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT));
628f7e6f7c5Svisa assert(pfd[1].revents == 0);
629f7e6f7c5Svisa
630f7e6f7c5Svisa /* Read normal data. */
631f7e6f7c5Svisa ret = read(fd, buf, sizeof(buf));
632f7e6f7c5Svisa assert(ret == 3);
633f7e6f7c5Svisa
634f7e6f7c5Svisa ret = poll(pfd, 2, 1);
635f7e6f7c5Svisa assert(ret == 1);
636f7e6f7c5Svisa assert(pfd[0].revents == POLLOUT);
637f7e6f7c5Svisa assert(pfd[1].revents == 0);
638f7e6f7c5Svisa
639f7e6f7c5Svisa if (ioctl(fd, TIOCUCNTL, &off) == -1)
640f7e6f7c5Svisa err(1, "parent: ioctl(TIOCUCNTL, 0)");
641f7e6f7c5Svisa
642f7e6f7c5Svisa proc_barrier(bfd);
643f7e6f7c5Svisa break;
644f7e6f7c5Svisa }
645f7e6f7c5Svisa #endif /* __OpenBSD__ */
646f7e6f7c5Svisa
647f7e6f7c5Svisa case FTYPE_SOCKET_TCP: {
648f7e6f7c5Svisa int atmark;
649f7e6f7c5Svisa int on = 1;
650f7e6f7c5Svisa
651f7e6f7c5Svisa /* child: write */
652f7e6f7c5Svisa
653f7e6f7c5Svisa if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &on,
654f7e6f7c5Svisa sizeof(on)) == -1)
655f7e6f7c5Svisa err(1, "parent: setsockopt(SO_OOBINLINE)");
656f7e6f7c5Svisa
657f7e6f7c5Svisa proc_barrier(bfd);
658f7e6f7c5Svisa
659f7e6f7c5Svisa pfd[0].fd = fd;
660f7e6f7c5Svisa pfd[0].events = POLLIN | POLLOUT | POLLPRI;
661f7e6f7c5Svisa pfd[1].fd = fd;
662f7e6f7c5Svisa pfd[1].events = 0;
663f7e6f7c5Svisa
664f7e6f7c5Svisa ret = poll(pfd, 2, 1);
665f7e6f7c5Svisa assert(ret == 1);
666f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI));
667f7e6f7c5Svisa assert(pfd[1].revents == 0);
668f7e6f7c5Svisa
669f7e6f7c5Svisa /* Read normal data. */
670f7e6f7c5Svisa atmark = 0;
671f7e6f7c5Svisa if (ioctl(fd, SIOCATMARK, &atmark) == -1)
672f7e6f7c5Svisa err(1, "parent: ioctl(SIOCATMARK)");
673f7e6f7c5Svisa assert(atmark == 0);
674f7e6f7c5Svisa ret = recv(fd, buf, sizeof(buf), 0);
675*e389c7c6Svisa assert(ret == 1);
676f7e6f7c5Svisa
677f7e6f7c5Svisa ret = poll(pfd, 2, 1);
678f7e6f7c5Svisa assert(ret == 1);
679f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI));
680f7e6f7c5Svisa assert(pfd[1].revents == 0);
681f7e6f7c5Svisa
682f7e6f7c5Svisa /* Read out-of-band data. */
683f7e6f7c5Svisa atmark = 0;
684f7e6f7c5Svisa if (ioctl(fd, SIOCATMARK, &atmark) == -1)
685f7e6f7c5Svisa err(1, "parent: ioctl(SIOCATMARK)");
686f7e6f7c5Svisa assert(atmark != 0);
687f7e6f7c5Svisa ret = recv(fd, &b, 1, 0);
688f7e6f7c5Svisa assert(ret == 1);
689f7e6f7c5Svisa
690f7e6f7c5Svisa ret = poll(pfd, 2, 1);
691f7e6f7c5Svisa assert(ret == 1);
692f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT));
693f7e6f7c5Svisa assert(pfd[1].revents == 0);
694f7e6f7c5Svisa
695f7e6f7c5Svisa /* Read normal data. */
696f7e6f7c5Svisa atmark = 0;
697f7e6f7c5Svisa if (ioctl(fd, SIOCATMARK, &atmark) == -1)
698f7e6f7c5Svisa err(1, "parent: ioctl(SIOCATMARK)");
699f7e6f7c5Svisa assert(atmark == 0);
700f7e6f7c5Svisa ret = recv(fd, buf, sizeof(buf), 0);
701*e389c7c6Svisa assert(ret == 1);
702f7e6f7c5Svisa
703f7e6f7c5Svisa ret = poll(pfd, 2, 1);
704f7e6f7c5Svisa assert(ret == 1);
705f7e6f7c5Svisa assert(pfd[0].revents == POLLOUT);
706f7e6f7c5Svisa assert(pfd[1].revents == 0);
707f7e6f7c5Svisa
708f7e6f7c5Svisa proc_barrier(bfd);
709f7e6f7c5Svisa break;
710f7e6f7c5Svisa }
711f7e6f7c5Svisa
712f7e6f7c5Svisa default:
713f7e6f7c5Svisa break;
714f7e6f7c5Svisa }
715f7e6f7c5Svisa
716f7e6f7c5Svisa /* Test socket shutdown. */
717f7e6f7c5Svisa switch (filetype) {
718f7e6f7c5Svisa case FTYPE_SOCKET_TCP:
719f7e6f7c5Svisa case FTYPE_SOCKET_UNIX:
720f7e6f7c5Svisa /* child: write and shutdown */
721f7e6f7c5Svisa
722f7e6f7c5Svisa proc_barrier(bfd);
723f7e6f7c5Svisa
724f7e6f7c5Svisa /* Let inet sockets take their time. */
725f7e6f7c5Svisa if (filetype == FTYPE_SOCKET_TCP)
726f7e6f7c5Svisa usleep(10000);
727f7e6f7c5Svisa
728f7e6f7c5Svisa pfd[0].fd = fd;
729f7e6f7c5Svisa pfd[0].events = POLLIN | POLLOUT | POLLPRI;
730f7e6f7c5Svisa
731f7e6f7c5Svisa ret = poll(pfd, 1, 1);
732f7e6f7c5Svisa assert(ret == 1);
733f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT));
734f7e6f7c5Svisa
735f7e6f7c5Svisa ret = read(fd, &b, 1);
736f7e6f7c5Svisa assert(ret == 1);
737f7e6f7c5Svisa
738f7e6f7c5Svisa ret = poll(pfd, 1, 1);
739f7e6f7c5Svisa assert(ret == 1);
740f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT));
741f7e6f7c5Svisa
742f7e6f7c5Svisa ret = read(fd, &b, 1);
743f7e6f7c5Svisa assert(ret == 0);
744f7e6f7c5Svisa
745f7e6f7c5Svisa ret = shutdown(fd, SHUT_WR);
746f7e6f7c5Svisa assert(ret == 0);
747f7e6f7c5Svisa
748f7e6f7c5Svisa proc_barrier(bfd);
749f7e6f7c5Svisa
750f7e6f7c5Svisa pfd[0].fd = fd;
751f7e6f7c5Svisa pfd[0].events = POLLIN | POLLOUT | POLLPRI;
752f7e6f7c5Svisa pfd[1].fd = fd;
753f7e6f7c5Svisa pfd[1].events = 0;
754f7e6f7c5Svisa
755f7e6f7c5Svisa ret = poll(pfd, 2, 1);
756f7e6f7c5Svisa #if defined(__linux__)
757f7e6f7c5Svisa assert(ret == 2);
758f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP));
759f7e6f7c5Svisa assert(pfd[1].revents == POLLHUP);
760f7e6f7c5Svisa #else
761f7e6f7c5Svisa #if defined(__OpenBSD__)
762f7e6f7c5Svisa /* XXX */
763f7e6f7c5Svisa if (filetype == FTYPE_SOCKET_UNIX) {
764f7e6f7c5Svisa assert(ret == 1);
765f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT));
766f7e6f7c5Svisa assert(pfd[1].revents == 0);
767f7e6f7c5Svisa } else {
768f7e6f7c5Svisa #endif /* __OpenBSD__ */
769f7e6f7c5Svisa assert(ret == 2);
770f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLHUP));
771f7e6f7c5Svisa assert(pfd[1].revents == POLLHUP);
772f7e6f7c5Svisa #if defined(__OpenBSD__)
773f7e6f7c5Svisa }
774f7e6f7c5Svisa #endif /* __OpenBSD__ */
775f7e6f7c5Svisa #endif
776f7e6f7c5Svisa break;
777f7e6f7c5Svisa
778f7e6f7c5Svisa case FTYPE_FIFO:
779f7e6f7c5Svisa case FTYPE_PIPE:
780f7e6f7c5Svisa case FTYPE_PTY:
781f7e6f7c5Svisa case FTYPE_SOCKET_UDP:
782f7e6f7c5Svisa default:
783f7e6f7c5Svisa break;
784f7e6f7c5Svisa }
785f7e6f7c5Svisa
786f7e6f7c5Svisa proc_barrier(bfd);
787f7e6f7c5Svisa
788f7e6f7c5Svisa /* child: close */
789f7e6f7c5Svisa
790f7e6f7c5Svisa proc_barrier(bfd);
791f7e6f7c5Svisa
792f7e6f7c5Svisa pfd[0].fd = fd;
793f7e6f7c5Svisa pfd[0].events = POLLIN | POLLOUT | POLLPRI;
794f7e6f7c5Svisa pfd[1].fd = fd;
795f7e6f7c5Svisa pfd[1].events = 0;
796f7e6f7c5Svisa
797f7e6f7c5Svisa ret = poll(pfd, 2, 1);
798f7e6f7c5Svisa switch (filetype) {
799f7e6f7c5Svisa case FTYPE_FIFO:
800f7e6f7c5Svisa case FTYPE_PIPE:
801f7e6f7c5Svisa case FTYPE_PTY:
802f7e6f7c5Svisa assert(ret == 2);
803f7e6f7c5Svisa #if defined(__linux__)
804f7e6f7c5Svisa assert(pfd[0].revents == POLLHUP);
805f7e6f7c5Svisa assert(pfd[1].revents == POLLHUP);
806f7e6f7c5Svisa #else
807f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLHUP));
808f7e6f7c5Svisa assert(pfd[1].revents == POLLHUP);
809f7e6f7c5Svisa #endif
810f7e6f7c5Svisa break;
811f7e6f7c5Svisa case FTYPE_SOCKET_TCP:
812f7e6f7c5Svisa case FTYPE_SOCKET_UNIX:
813f7e6f7c5Svisa assert(ret == 2);
814f7e6f7c5Svisa #if defined(__linux__)
815f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP));
816f7e6f7c5Svisa assert(pfd[1].revents == POLLHUP);
817f7e6f7c5Svisa #else
818f7e6f7c5Svisa assert(pfd[0].revents == (POLLIN | POLLHUP));
819f7e6f7c5Svisa assert(pfd[1].revents == POLLHUP);
820f7e6f7c5Svisa #endif
821f7e6f7c5Svisa break;
822f7e6f7c5Svisa case FTYPE_SOCKET_UDP:
823f7e6f7c5Svisa assert(ret == 1);
824f7e6f7c5Svisa assert(pfd[0].revents == POLLOUT);
825f7e6f7c5Svisa assert(pfd[1].revents == 0);
826f7e6f7c5Svisa break;
827f7e6f7c5Svisa default:
828f7e6f7c5Svisa assert(0);
829f7e6f7c5Svisa }
830f7e6f7c5Svisa
831f7e6f7c5Svisa close(fd);
832f7e6f7c5Svisa }
833