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