2 * Copyright (c) 2005 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/types.h>
30 #include <sys/socket.h>
32 #include <netinet/in.h>
43 * This regression test is intended to verify whether or not SIGPIPE is
44 * properly generated in several simple test cases, as well as testing
45 * whether SO_NOSIGPIPE disables SIGPIPE, if available on the system.
46 * SIGPIPE is generated if a write or send is attempted on a socket that has
47 * been shutdown for write. This test runs several test cases with UNIX
48 * domain sockets and TCP sockets to confirm that either EPIPE or SIGPIPE is
51 * For the purposes of testing TCP, an unused port number must be specified.
57 errx(-1, "usage: sigpipe tcpport");
61 * Signal catcher. Set a global flag that can be tested by the caller.
72 signal_handler(int signum)
79 signal_setup(const char *testname)
83 if (signal(SIGPIPE, signal_handler) == SIG_ERR)
84 err(-1, "%s: signal(SIGPIPE)", testname);
88 test_send(const char *testname, int sock)
94 len = send(sock, &ch, sizeof(ch), 0);
98 err(-1, "%s: send", testname);
100 errx(-1, "%s: send: returned %zd", testname, len);
104 test_write(const char *testname, int sock)
110 len = write(sock, &ch, sizeof(ch));
114 err(-1, "%s: write", testname);
116 errx(-1, "%s: write: returned %zd", testname, len);
120 test_send_wantsignal(const char *testname, int sock1, int sock2)
123 if (shutdown(sock2, SHUT_WR) < 0)
124 err(-1, "%s: shutdown", testname);
125 signal_setup(testname);
126 test_send(testname, sock2);
128 errx(-1, "%s: send: didn't receive SIGPIPE", testname);
135 test_send_dontsignal(const char *testname, int sock1, int sock2)
140 if (setsockopt(sock2, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0)
141 err(-1, "%s: setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", testname);
142 if (shutdown(sock2, SHUT_WR) < 0)
143 err(-1, "%s: shutdown", testname);
144 signal_setup(testname);
145 test_send(testname, sock2);
147 errx(-1, "%s: send: got SIGPIPE", testname);
154 test_write_wantsignal(const char *testname, int sock1, int sock2)
157 if (shutdown(sock2, SHUT_WR) < 0)
158 err(-1, "%s: shutdown", testname);
159 signal_setup(testname);
160 test_write(testname, sock2);
162 errx(-1, "%s: write: didn't receive SIGPIPE", testname);
169 test_write_dontsignal(const char *testname, int sock1, int sock2)
174 if (setsockopt(sock2, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0)
175 err(-1, "%s: setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", testname);
176 if (shutdown(sock2, SHUT_WR) < 0)
177 err(-1, "%s: shutdown", testname);
178 signal_setup(testname);
179 test_write(testname, sock2);
181 errx(-1, "%s: write: got SIGPIPE", testname);
187 static int listen_sock;
189 tcp_setup(u_short port)
191 struct sockaddr_in sin;
193 listen_sock = socket(PF_INET, SOCK_STREAM, 0);
195 err(-1, "tcp_setup: listen");
197 bzero(&sin, sizeof(sin));
198 sin.sin_len = sizeof(sin);
199 sin.sin_family = AF_INET;
200 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
201 sin.sin_port = htons(port);
203 if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
204 err(-1, "tcp_setup: bind");
206 if (listen(listen_sock, -1) < 0)
207 err(-1, "tcp_setup: listen");
218 tcp_pair(u_short port, int sock[2])
220 int accept_sock, connect_sock;
221 struct sockaddr_in sin;
224 connect_sock = socket(PF_INET, SOCK_STREAM, 0);
225 if (connect_sock < 0)
226 err(-1, "tcp_pair: socket");
228 bzero(&sin, sizeof(sin));
229 sin.sin_len = sizeof(sin);
230 sin.sin_family = AF_INET;
231 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
232 sin.sin_port = htons(port);
234 if (connect(connect_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
235 err(-1, "tcp_pair: connect");
237 sleep(1); /* Time for TCP to settle. */
240 accept_sock = accept(listen_sock, (struct sockaddr *)&sin, &len);
242 err(-1, "tcp_pair: accept");
244 sleep(1); /* Time for TCP to settle. */
246 sock[0] = accept_sock;
247 sock[1] = connect_sock;
251 main(int argc, char *argv[])
260 port = strtol(argv[1], &dummy, 10);
261 if (port < 0 || port > 65535 || *dummy != '\0')
265 warnx("sigpipe: SO_NOSIGPIPE not defined, skipping some tests");
269 * UNIX domain socketpair().
271 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0)
272 err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)");
273 test_send_wantsignal("test_send_wantsignal(PF_LOCAL)", sock[0],
277 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0)
278 err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)");
279 test_send_dontsignal("test_send_dontsignal(PF_LOCAL)", sock[0],
283 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0)
284 err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)");
285 test_write_wantsignal("test_write_wantsignal(PF_LOCAL)", sock[0],
289 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0)
290 err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)");
291 test_write_dontsignal("test_write_dontsignal(PF_LOCAL)", sock[0],
299 tcp_pair(port, sock);
300 test_send_wantsignal("test_send_wantsignal(PF_INET)", sock[0],
304 tcp_pair(port, sock);
305 test_send_dontsignal("test_send_dontsignal(PF_INET)", sock[0],
309 tcp_pair(port, sock);
310 test_write_wantsignal("test_write_wantsignal(PF_INET)", sock[0],
314 tcp_pair(port, sock);
315 test_write_dontsignal("test_write_dontsignal(PF_INET)", sock[0],
320 fprintf(stderr, "PASS\n");