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