2 * Copyright (c) 2007 Robert N. M. Watson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/select.h>
30 #include <sys/socket.h>
33 #include <netinet/in.h>
35 #include <arpa/inet.h>
49 try_0send(const char *test, int fd)
55 len = send(fd, &ch, 0, 0);
57 err(1, "%s: try_0send", test);
59 errx(1, "%s: try_0send: returned %zd", test, len);
63 try_0write(const char *test, int fd)
69 len = write(fd, &ch, 0);
71 err(1, "%s: try_0write", test);
73 errx(1, "%s: try_0write: returned %zd", test, len);
77 setup_udp(const char *test, int *fdp, int port1, int port2)
79 struct sockaddr_in sin;
82 bzero(&sin, sizeof(sin));
83 sin.sin_len = sizeof(sin);
84 sin.sin_family = AF_INET;
85 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
87 sin.sin_port = htons(port1);
88 sock1 = socket(PF_INET, SOCK_DGRAM, 0);
90 err(1, "%s: setup_udp: socket", test);
91 if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)
92 err(1, "%s: setup_udp: bind(%s, %d)", test,
93 inet_ntoa(sin.sin_addr), PORT1);
94 sin.sin_port = htons(port2);
95 if (connect(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)
96 err(1, "%s: setup_udp: connect(%s, %d)", test,
97 inet_ntoa(sin.sin_addr), PORT2);
99 sock2 = socket(PF_INET, SOCK_DGRAM, 0);
101 err(1, "%s: setup_udp: socket", test);
102 if (bind(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0)
103 err(1, "%s: setup_udp: bind(%s, %d)", test,
104 inet_ntoa(sin.sin_addr), PORT2);
105 sin.sin_port = htons(port1);
106 if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0)
107 err(1, "%s: setup_udp: connect(%s, %d)", test,
108 inet_ntoa(sin.sin_addr), PORT1);
115 setup_tcp(const char *test, int *fdp, int port)
117 fd_set writefds, exceptfds;
118 struct sockaddr_in sin;
119 int ret, sock1, sock2, sock3;
122 bzero(&sin, sizeof(sin));
123 sin.sin_len = sizeof(sin);
124 sin.sin_family = AF_INET;
125 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
128 * First set up the listen socket.
130 sin.sin_port = htons(port);
131 sock1 = socket(PF_INET, SOCK_STREAM, 0);
133 err(1, "%s: setup_tcp: socket", test);
134 if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)
135 err(1, "%s: bind(%s, %d)", test, inet_ntoa(sin.sin_addr),
137 if (listen(sock1, -1) < 0)
138 err(1, "%s: listen", test);
141 * Now connect to it, non-blocking so that we don't deadlock against
144 sock2 = socket(PF_INET, SOCK_STREAM, 0);
146 err(1, "%s: setup_tcp: socket", test);
147 if (fcntl(sock2, F_SETFL, O_NONBLOCK) < 0)
148 err(1, "%s: setup_tcp: fcntl(O_NONBLOCK)", test);
149 if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0 &&
150 errno != EINPROGRESS)
151 err(1, "%s: setup_tcp: connect(%s, %d)", test,
152 inet_ntoa(sin.sin_addr), PORT1);
155 * Now pick up the connection after sleeping a moment to make sure
156 * there's been time for some packets to go back and forth.
159 err(1, "%s: sleep(1)", test);
160 sock3 = accept(sock1, NULL, NULL);
162 err(1, "%s: accept", test);
164 err(1, "%s: sleep(1)", test);
167 FD_SET(sock2, &writefds);
169 FD_SET(sock2, &exceptfds);
172 ret = select(sock2 + 1, NULL, &writefds, &exceptfds, &tv);
174 err(1, "%s: setup_tcp: select", test);
175 if (FD_ISSET(sock2, &exceptfds))
176 errx(1, "%s: setup_tcp: select: exception", test);
177 if (!FD_ISSET(sock2, &writefds))
178 errx(1, "%s: setup_tcp: select: not writable", test);
186 setup_udsstream(const char *test, int *fdp)
189 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fdp) < 0)
190 err(1, "%s: setup_udsstream: socketpair", test);
194 setup_udsdgram(const char *test, int *fdp)
197 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fdp) < 0)
198 err(1, "%s: setup_udsdgram: socketpair", test);
202 setup_pipe(const char *test, int *fdp)
206 err(1, "%s: setup_pipe: pipe", test);
210 setup_fifo(const char *test, int *fdp)
212 char path[] = "0send_fifo.XXXXXXX";
215 if (mkstemp(path) == -1)
216 err(1, "%s: setup_fifo: mktemp", test);
219 if (mkfifo(path, 0600) < 0)
220 err(1, "%s: setup_fifo: mkfifo(%s)", test, path);
222 fd1 = open(path, O_RDONLY | O_NONBLOCK);
224 err(1, "%s: setup_fifo: open(%s, O_RDONLY)", test, path);
226 fd2 = open(path, O_WRONLY | O_NONBLOCK);
228 err(1, "%s: setup_fifo: open(%s, O_WRONLY)", test, path);
249 setup_udp("udp_0send", fd, PORT1, PORT2);
250 try_0send("udp_0send", fd[0]);
253 setup_udp("udp_0write", fd, PORT1 + 10, PORT2 + 10);
254 try_0write("udp_0write", fd[0]);
257 setup_tcp("tcp_0send", fd, PORT1);
258 try_0send("tcp_0send", fd[0]);
261 setup_tcp("tcp_0write", fd, PORT1 + 10);
262 try_0write("tcp_0write", fd[0]);
265 setup_udsstream("udsstream_0send", fd);
266 try_0send("udsstream_0send", fd[0]);
269 setup_udsstream("udsstream_0write", fd);
270 try_0write("udsstream_0write", fd[0]);
273 setup_udsdgram("udsdgram_0send", fd);
274 try_0send("udsdgram_0send", fd[0]);
277 setup_udsdgram("udsdgram_0write", fd);
278 try_0write("udsdgram_0write", fd[0]);
281 setup_pipe("pipe_0write", fd);
282 try_0write("pipd_0write", fd[0]);
285 setup_fifo("fifo_0write", fd);
286 try_0write("fifo_0write", fd[0]);