1*89233cfdSJohn Marino /*-
2*89233cfdSJohn Marino * Copyright (c) 2005 Robert N. M. Watson
3*89233cfdSJohn Marino * All rights reserved.
4*89233cfdSJohn Marino *
5*89233cfdSJohn Marino * Redistribution and use in source and binary forms, with or without
6*89233cfdSJohn Marino * modification, are permitted provided that the following conditions
7*89233cfdSJohn Marino * are met:
8*89233cfdSJohn Marino * 1. Redistributions of source code must retain the above copyright
9*89233cfdSJohn Marino * notice, this list of conditions and the following disclaimer.
10*89233cfdSJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
11*89233cfdSJohn Marino * notice, this list of conditions and the following disclaimer in the
12*89233cfdSJohn Marino * documentation and/or other materials provided with the distribution.
13*89233cfdSJohn Marino *
14*89233cfdSJohn Marino * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*89233cfdSJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*89233cfdSJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*89233cfdSJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*89233cfdSJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*89233cfdSJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*89233cfdSJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*89233cfdSJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*89233cfdSJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*89233cfdSJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*89233cfdSJohn Marino * SUCH DAMAGE.
25*89233cfdSJohn Marino *
26*89233cfdSJohn Marino * $FreeBSD$
27*89233cfdSJohn Marino */
28*89233cfdSJohn Marino
29*89233cfdSJohn Marino #include <sys/types.h>
30*89233cfdSJohn Marino #include <sys/socket.h>
31*89233cfdSJohn Marino
32*89233cfdSJohn Marino #include <netinet/in.h>
33*89233cfdSJohn Marino
34*89233cfdSJohn Marino #include <err.h>
35*89233cfdSJohn Marino #include <errno.h>
36*89233cfdSJohn Marino #include <signal.h>
37*89233cfdSJohn Marino #include <stdio.h>
38*89233cfdSJohn Marino #include <stdlib.h>
39*89233cfdSJohn Marino #include <string.h>
40*89233cfdSJohn Marino #include <unistd.h>
41*89233cfdSJohn Marino
42*89233cfdSJohn Marino /*
43*89233cfdSJohn Marino * This regression test is intended to verify whether or not SIGPIPE is
44*89233cfdSJohn Marino * properly generated in several simple test cases, as well as testing
45*89233cfdSJohn Marino * whether SO_NOSIGPIPE disables SIGPIPE, if available on the system.
46*89233cfdSJohn Marino * SIGPIPE is generated if a write or send is attempted on a socket that has
47*89233cfdSJohn Marino * been shutdown for write. This test runs several test cases with UNIX
48*89233cfdSJohn Marino * domain sockets and TCP sockets to confirm that either EPIPE or SIGPIPE is
49*89233cfdSJohn Marino * properly returned.
50*89233cfdSJohn Marino *
51*89233cfdSJohn Marino * For the purposes of testing TCP, an unused port number must be specified.
52*89233cfdSJohn Marino */
53*89233cfdSJohn Marino static void
usage(void)54*89233cfdSJohn Marino usage(void)
55*89233cfdSJohn Marino {
56*89233cfdSJohn Marino
57*89233cfdSJohn Marino errx(-1, "usage: sigpipe tcpport");
58*89233cfdSJohn Marino }
59*89233cfdSJohn Marino
60*89233cfdSJohn Marino /*
61*89233cfdSJohn Marino * Signal catcher. Set a global flag that can be tested by the caller.
62*89233cfdSJohn Marino */
63*89233cfdSJohn Marino static int signaled;
64*89233cfdSJohn Marino static int
got_signal(void)65*89233cfdSJohn Marino got_signal(void)
66*89233cfdSJohn Marino {
67*89233cfdSJohn Marino
68*89233cfdSJohn Marino return (signaled);
69*89233cfdSJohn Marino }
70*89233cfdSJohn Marino
71*89233cfdSJohn Marino static void
signal_handler(int signum)72*89233cfdSJohn Marino signal_handler(int signum)
73*89233cfdSJohn Marino {
74*89233cfdSJohn Marino
75*89233cfdSJohn Marino signaled = 1;
76*89233cfdSJohn Marino }
77*89233cfdSJohn Marino
78*89233cfdSJohn Marino static void
signal_setup(const char * testname)79*89233cfdSJohn Marino signal_setup(const char *testname)
80*89233cfdSJohn Marino {
81*89233cfdSJohn Marino
82*89233cfdSJohn Marino signaled = 0;
83*89233cfdSJohn Marino if (signal(SIGPIPE, signal_handler) == SIG_ERR)
84*89233cfdSJohn Marino err(-1, "%s: signal(SIGPIPE)", testname);
85*89233cfdSJohn Marino }
86*89233cfdSJohn Marino
87*89233cfdSJohn Marino static void
test_send(const char * testname,int sock)88*89233cfdSJohn Marino test_send(const char *testname, int sock)
89*89233cfdSJohn Marino {
90*89233cfdSJohn Marino ssize_t len;
91*89233cfdSJohn Marino char ch;
92*89233cfdSJohn Marino
93*89233cfdSJohn Marino ch = 0;
94*89233cfdSJohn Marino len = send(sock, &ch, sizeof(ch), 0);
95*89233cfdSJohn Marino if (len < 0) {
96*89233cfdSJohn Marino if (errno == EPIPE)
97*89233cfdSJohn Marino return;
98*89233cfdSJohn Marino err(-1, "%s: send", testname);
99*89233cfdSJohn Marino }
100*89233cfdSJohn Marino errx(-1, "%s: send: returned %d", testname, len);
101*89233cfdSJohn Marino }
102*89233cfdSJohn Marino
103*89233cfdSJohn Marino static void
test_write(const char * testname,int sock)104*89233cfdSJohn Marino test_write(const char *testname, int sock)
105*89233cfdSJohn Marino {
106*89233cfdSJohn Marino ssize_t len;
107*89233cfdSJohn Marino char ch;
108*89233cfdSJohn Marino
109*89233cfdSJohn Marino ch = 0;
110*89233cfdSJohn Marino len = write(sock, &ch, sizeof(ch));
111*89233cfdSJohn Marino if (len < 0) {
112*89233cfdSJohn Marino if (errno == EPIPE)
113*89233cfdSJohn Marino return;
114*89233cfdSJohn Marino err(-1, "%s: write", testname);
115*89233cfdSJohn Marino }
116*89233cfdSJohn Marino errx(-1, "%s: write: returned %d", testname, len);
117*89233cfdSJohn Marino }
118*89233cfdSJohn Marino
119*89233cfdSJohn Marino static void
test_send_wantsignal(const char * testname,int sock1,int sock2)120*89233cfdSJohn Marino test_send_wantsignal(const char *testname, int sock1, int sock2)
121*89233cfdSJohn Marino {
122*89233cfdSJohn Marino
123*89233cfdSJohn Marino if (shutdown(sock2, SHUT_WR) < 0)
124*89233cfdSJohn Marino err(-1, "%s: shutdown", testname);
125*89233cfdSJohn Marino signal_setup(testname);
126*89233cfdSJohn Marino test_send(testname, sock2);
127*89233cfdSJohn Marino if (!got_signal())
128*89233cfdSJohn Marino errx(-1, "%s: send: didn't receive SIGPIPE", testname);
129*89233cfdSJohn Marino close(sock1);
130*89233cfdSJohn Marino close(sock2);
131*89233cfdSJohn Marino }
132*89233cfdSJohn Marino
133*89233cfdSJohn Marino #ifdef SO_NOSIGPIPE
134*89233cfdSJohn Marino static void
test_send_dontsignal(const char * testname,int sock1,int sock2)135*89233cfdSJohn Marino test_send_dontsignal(const char *testname, int sock1, int sock2)
136*89233cfdSJohn Marino {
137*89233cfdSJohn Marino int i;
138*89233cfdSJohn Marino
139*89233cfdSJohn Marino i = 1;
140*89233cfdSJohn Marino if (setsockopt(sock2, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0)
141*89233cfdSJohn Marino err(-1, "%s: setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", testname);
142*89233cfdSJohn Marino if (shutdown(sock2, SHUT_WR) < 0)
143*89233cfdSJohn Marino err(-1, "%s: shutdown", testname);
144*89233cfdSJohn Marino signal_setup(testname);
145*89233cfdSJohn Marino test_send(testname, sock2);
146*89233cfdSJohn Marino if (got_signal())
147*89233cfdSJohn Marino errx(-1, "%s: send: got SIGPIPE", testname);
148*89233cfdSJohn Marino close(sock1);
149*89233cfdSJohn Marino close(sock2);
150*89233cfdSJohn Marino }
151*89233cfdSJohn Marino #endif
152*89233cfdSJohn Marino
153*89233cfdSJohn Marino static void
test_write_wantsignal(const char * testname,int sock1,int sock2)154*89233cfdSJohn Marino test_write_wantsignal(const char *testname, int sock1, int sock2)
155*89233cfdSJohn Marino {
156*89233cfdSJohn Marino
157*89233cfdSJohn Marino if (shutdown(sock2, SHUT_WR) < 0)
158*89233cfdSJohn Marino err(-1, "%s: shutdown", testname);
159*89233cfdSJohn Marino signal_setup(testname);
160*89233cfdSJohn Marino test_write(testname, sock2);
161*89233cfdSJohn Marino if (!got_signal())
162*89233cfdSJohn Marino errx(-1, "%s: write: didn't receive SIGPIPE", testname);
163*89233cfdSJohn Marino close(sock1);
164*89233cfdSJohn Marino close(sock2);
165*89233cfdSJohn Marino }
166*89233cfdSJohn Marino
167*89233cfdSJohn Marino #ifdef SO_NOSIGPIPE
168*89233cfdSJohn Marino static void
test_write_dontsignal(const char * testname,int sock1,int sock2)169*89233cfdSJohn Marino test_write_dontsignal(const char *testname, int sock1, int sock2)
170*89233cfdSJohn Marino {
171*89233cfdSJohn Marino int i;
172*89233cfdSJohn Marino
173*89233cfdSJohn Marino i = 1;
174*89233cfdSJohn Marino if (setsockopt(sock2, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0)
175*89233cfdSJohn Marino err(-1, "%s: setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", testname);
176*89233cfdSJohn Marino if (shutdown(sock2, SHUT_WR) < 0)
177*89233cfdSJohn Marino err(-1, "%s: shutdown", testname);
178*89233cfdSJohn Marino signal_setup(testname);
179*89233cfdSJohn Marino test_write(testname, sock2);
180*89233cfdSJohn Marino if (got_signal())
181*89233cfdSJohn Marino errx(-1, "%s: write: got SIGPIPE", testname);
182*89233cfdSJohn Marino close(sock1);
183*89233cfdSJohn Marino close(sock2);
184*89233cfdSJohn Marino }
185*89233cfdSJohn Marino #endif
186*89233cfdSJohn Marino
187*89233cfdSJohn Marino static int listen_sock;
188*89233cfdSJohn Marino static void
tcp_setup(u_short port)189*89233cfdSJohn Marino tcp_setup(u_short port)
190*89233cfdSJohn Marino {
191*89233cfdSJohn Marino struct sockaddr_in sin;
192*89233cfdSJohn Marino
193*89233cfdSJohn Marino listen_sock = socket(PF_INET, SOCK_STREAM, 0);
194*89233cfdSJohn Marino if (listen_sock < 0)
195*89233cfdSJohn Marino err(-1, "tcp_setup: listen");
196*89233cfdSJohn Marino
197*89233cfdSJohn Marino bzero(&sin, sizeof(sin));
198*89233cfdSJohn Marino sin.sin_len = sizeof(sin);
199*89233cfdSJohn Marino sin.sin_family = AF_INET;
200*89233cfdSJohn Marino sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
201*89233cfdSJohn Marino sin.sin_port = htons(port);
202*89233cfdSJohn Marino
203*89233cfdSJohn Marino if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
204*89233cfdSJohn Marino err(-1, "tcp_setup: bind");
205*89233cfdSJohn Marino
206*89233cfdSJohn Marino if (listen(listen_sock, -1) < 0)
207*89233cfdSJohn Marino err(-1, "tcp_setup: listen");
208*89233cfdSJohn Marino }
209*89233cfdSJohn Marino
210*89233cfdSJohn Marino static void
tcp_teardown(void)211*89233cfdSJohn Marino tcp_teardown(void)
212*89233cfdSJohn Marino {
213*89233cfdSJohn Marino
214*89233cfdSJohn Marino close(listen_sock);
215*89233cfdSJohn Marino }
216*89233cfdSJohn Marino
217*89233cfdSJohn Marino static void
tcp_pair(u_short port,int sock[2])218*89233cfdSJohn Marino tcp_pair(u_short port, int sock[2])
219*89233cfdSJohn Marino {
220*89233cfdSJohn Marino int accept_sock, connect_sock;
221*89233cfdSJohn Marino struct sockaddr_in sin;
222*89233cfdSJohn Marino socklen_t len;
223*89233cfdSJohn Marino
224*89233cfdSJohn Marino connect_sock = socket(PF_INET, SOCK_STREAM, 0);
225*89233cfdSJohn Marino if (connect_sock < 0)
226*89233cfdSJohn Marino err(-1, "tcp_pair: socket");
227*89233cfdSJohn Marino
228*89233cfdSJohn Marino bzero(&sin, sizeof(sin));
229*89233cfdSJohn Marino sin.sin_len = sizeof(sin);
230*89233cfdSJohn Marino sin.sin_family = AF_INET;
231*89233cfdSJohn Marino sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
232*89233cfdSJohn Marino sin.sin_port = htons(port);
233*89233cfdSJohn Marino
234*89233cfdSJohn Marino if (connect(connect_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
235*89233cfdSJohn Marino err(-1, "tcp_pair: connect");
236*89233cfdSJohn Marino
237*89233cfdSJohn Marino sleep(1); /* Time for TCP to settle. */
238*89233cfdSJohn Marino
239*89233cfdSJohn Marino len = sizeof(sin);
240*89233cfdSJohn Marino accept_sock = accept(listen_sock, (struct sockaddr *)&sin, &len);
241*89233cfdSJohn Marino if (accept_sock < 0)
242*89233cfdSJohn Marino err(-1, "tcp_pair: accept");
243*89233cfdSJohn Marino
244*89233cfdSJohn Marino sleep(1); /* Time for TCP to settle. */
245*89233cfdSJohn Marino
246*89233cfdSJohn Marino sock[0] = accept_sock;
247*89233cfdSJohn Marino sock[1] = connect_sock;
248*89233cfdSJohn Marino }
249*89233cfdSJohn Marino
250*89233cfdSJohn Marino int
main(int argc,char * argv[])251*89233cfdSJohn Marino main(int argc, char *argv[])
252*89233cfdSJohn Marino {
253*89233cfdSJohn Marino char *dummy;
254*89233cfdSJohn Marino int sock[2];
255*89233cfdSJohn Marino long port;
256*89233cfdSJohn Marino
257*89233cfdSJohn Marino if (argc != 2)
258*89233cfdSJohn Marino usage();
259*89233cfdSJohn Marino
260*89233cfdSJohn Marino port = strtol(argv[1], &dummy, 10);
261*89233cfdSJohn Marino if (port < 0 || port > 65535 || *dummy != '\0')
262*89233cfdSJohn Marino usage();
263*89233cfdSJohn Marino
264*89233cfdSJohn Marino #ifndef SO_NOSIGPIPE
265*89233cfdSJohn Marino warnx("sigpipe: SO_NOSIGPIPE not defined, skipping some tests");
266*89233cfdSJohn Marino #endif
267*89233cfdSJohn Marino
268*89233cfdSJohn Marino /*
269*89233cfdSJohn Marino * UNIX domain socketpair().
270*89233cfdSJohn Marino */
271*89233cfdSJohn Marino if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0)
272*89233cfdSJohn Marino err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)");
273*89233cfdSJohn Marino test_send_wantsignal("test_send_wantsignal(PF_LOCAL)", sock[0],
274*89233cfdSJohn Marino sock[1]);
275*89233cfdSJohn Marino
276*89233cfdSJohn Marino #ifdef SO_NOSIGPIPE
277*89233cfdSJohn Marino if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0)
278*89233cfdSJohn Marino err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)");
279*89233cfdSJohn Marino test_send_dontsignal("test_send_dontsignal(PF_LOCAL)", sock[0],
280*89233cfdSJohn Marino sock[1]);
281*89233cfdSJohn Marino #endif
282*89233cfdSJohn Marino
283*89233cfdSJohn Marino if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0)
284*89233cfdSJohn Marino err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)");
285*89233cfdSJohn Marino test_write_wantsignal("test_write_wantsignal(PF_LOCAL)", sock[0],
286*89233cfdSJohn Marino sock[1]);
287*89233cfdSJohn Marino
288*89233cfdSJohn Marino #ifdef SO_NOSIGPIPE
289*89233cfdSJohn Marino if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0)
290*89233cfdSJohn Marino err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)");
291*89233cfdSJohn Marino test_write_dontsignal("test_write_dontsignal(PF_LOCAL)", sock[0],
292*89233cfdSJohn Marino sock[1]);
293*89233cfdSJohn Marino #endif
294*89233cfdSJohn Marino
295*89233cfdSJohn Marino /*
296*89233cfdSJohn Marino * TCP.
297*89233cfdSJohn Marino */
298*89233cfdSJohn Marino tcp_setup(port);
299*89233cfdSJohn Marino tcp_pair(port, sock);
300*89233cfdSJohn Marino test_send_wantsignal("test_send_wantsignal(PF_INET)", sock[0],
301*89233cfdSJohn Marino sock[1]);
302*89233cfdSJohn Marino
303*89233cfdSJohn Marino #ifdef SO_NOSIGPIPE
304*89233cfdSJohn Marino tcp_pair(port, sock);
305*89233cfdSJohn Marino test_send_dontsignal("test_send_dontsignal(PF_INET)", sock[0],
306*89233cfdSJohn Marino sock[1]);
307*89233cfdSJohn Marino #endif
308*89233cfdSJohn Marino
309*89233cfdSJohn Marino tcp_pair(port, sock);
310*89233cfdSJohn Marino test_write_wantsignal("test_write_wantsignal(PF_INET)", sock[0],
311*89233cfdSJohn Marino sock[1]);
312*89233cfdSJohn Marino
313*89233cfdSJohn Marino #ifdef SO_NOSIGPIPE
314*89233cfdSJohn Marino tcp_pair(port, sock);
315*89233cfdSJohn Marino test_write_dontsignal("test_write_dontsignal(PF_INET)", sock[0],
316*89233cfdSJohn Marino sock[1]);
317*89233cfdSJohn Marino #endif
318*89233cfdSJohn Marino tcp_teardown();
319*89233cfdSJohn Marino
320*89233cfdSJohn Marino fprintf(stderr, "PASS\n");
321*89233cfdSJohn Marino return (0);
322*89233cfdSJohn Marino }
323