1143409Srwatson/*- 2143409Srwatson * Copyright (c) 2005 Robert N. M. Watson 3143409Srwatson * All rights reserved. 4143409Srwatson * 5143409Srwatson * Redistribution and use in source and binary forms, with or without 6143409Srwatson * modification, are permitted provided that the following conditions 7143409Srwatson * are met: 8143409Srwatson * 1. Redistributions of source code must retain the above copyright 9143409Srwatson * notice, this list of conditions and the following disclaimer. 10143409Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11143409Srwatson * notice, this list of conditions and the following disclaimer in the 12143409Srwatson * documentation and/or other materials provided with the distribution. 13143409Srwatson * 14143409Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15143409Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16143409Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17143409Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18143409Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19143409Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20143409Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21143409Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22143409Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23143409Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24143409Srwatson * SUCH DAMAGE. 25143409Srwatson * 26143409Srwatson * $FreeBSD$ 27143409Srwatson */ 28143409Srwatson 29143409Srwatson#include <sys/types.h> 30143409Srwatson#include <sys/socket.h> 31143409Srwatson 32143409Srwatson#include <netinet/in.h> 33143409Srwatson 34143409Srwatson#include <err.h> 35143409Srwatson#include <errno.h> 36143409Srwatson#include <signal.h> 37143409Srwatson#include <stdio.h> 38143409Srwatson#include <stdlib.h> 39143409Srwatson#include <string.h> 40143409Srwatson#include <unistd.h> 41143409Srwatson 42143409Srwatson/* 43143409Srwatson * This regression test is intended to verify whether or not SIGPIPE is 44143409Srwatson * properly generated in several simple test cases, as well as testing 45143409Srwatson * whether SO_NOSIGPIPE disables SIGPIPE, if available on the system. 46143409Srwatson * SIGPIPE is generated if a write or send is attempted on a socket that has 47143409Srwatson * been shutdown for write. This test runs several test cases with UNIX 48143409Srwatson * domain sockets and TCP sockets to confirm that either EPIPE or SIGPIPE is 49143409Srwatson * properly returned. 50143409Srwatson * 51143409Srwatson * For the purposes of testing TCP, an unused port number must be specified. 52143409Srwatson */ 53143409Srwatsonstatic void 54143409Srwatsonusage(void) 55143409Srwatson{ 56143409Srwatson 57143409Srwatson errx(-1, "usage: sigpipe tcpport"); 58143409Srwatson} 59143409Srwatson 60143409Srwatson/* 61143409Srwatson * Signal catcher. Set a global flag that can be tested by the caller. 62143409Srwatson */ 63143409Srwatsonstatic int signaled; 64143409Srwatsonstatic int 65143409Srwatsongot_signal(void) 66143409Srwatson{ 67143409Srwatson 68143409Srwatson return (signaled); 69143409Srwatson} 70143409Srwatson 71143409Srwatsonstatic void 72143409Srwatsonsignal_handler(int signum) 73143409Srwatson{ 74143409Srwatson 75143409Srwatson signaled = 1; 76143409Srwatson} 77143409Srwatson 78143409Srwatsonstatic void 79143409Srwatsonsignal_setup(const char *testname) 80143409Srwatson{ 81143409Srwatson 82143409Srwatson signaled = 0; 83143409Srwatson if (signal(SIGPIPE, signal_handler) == SIG_ERR) 84143409Srwatson err(-1, "%s: signal(SIGPIPE)", testname); 85143409Srwatson} 86143409Srwatson 87143409Srwatsonstatic void 88143409Srwatsontest_send(const char *testname, int sock) 89143409Srwatson{ 90143409Srwatson ssize_t len; 91143409Srwatson char ch; 92143409Srwatson 93143409Srwatson ch = 0; 94143409Srwatson len = send(sock, &ch, sizeof(ch), 0); 95143409Srwatson if (len < 0) { 96143409Srwatson if (errno == EPIPE) 97143409Srwatson return; 98143409Srwatson err(-1, "%s: send", testname); 99143409Srwatson } 100143409Srwatson errx(-1, "%s: send: returned %d", testname, len); 101143409Srwatson} 102143409Srwatson 103143409Srwatsonstatic void 104143409Srwatsontest_write(const char *testname, int sock) 105143409Srwatson{ 106143409Srwatson ssize_t len; 107143409Srwatson char ch; 108143409Srwatson 109143409Srwatson ch = 0; 110143409Srwatson len = write(sock, &ch, sizeof(ch)); 111143409Srwatson if (len < 0) { 112143409Srwatson if (errno == EPIPE) 113143409Srwatson return; 114143409Srwatson err(-1, "%s: write", testname); 115143409Srwatson } 116143409Srwatson errx(-1, "%s: write: returned %d", testname, len); 117143409Srwatson} 118143409Srwatson 119143409Srwatsonstatic void 120143409Srwatsontest_send_wantsignal(const char *testname, int sock1, int sock2) 121143409Srwatson{ 122143409Srwatson 123143413Srwatson if (shutdown(sock2, SHUT_WR) < 0) 124143413Srwatson err(-1, "%s: shutdown", testname); 125143409Srwatson signal_setup(testname); 126143409Srwatson test_send(testname, sock2); 127143409Srwatson if (!got_signal()) 128143409Srwatson errx(-1, "%s: send: didn't receive SIGPIPE", testname); 129143409Srwatson close(sock1); 130143409Srwatson close(sock2); 131143409Srwatson} 132143409Srwatson 133143409Srwatson#ifdef SO_NOSIGPIPE 134143409Srwatsonstatic void 135143409Srwatsontest_send_dontsignal(const char *testname, int sock1, int sock2) 136143409Srwatson{ 137143409Srwatson int i; 138143409Srwatson 139143409Srwatson i = 1; 140143409Srwatson if (setsockopt(sock2, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0) 141143409Srwatson err(-1, "%s: setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", testname); 142143413Srwatson if (shutdown(sock2, SHUT_WR) < 0) 143143413Srwatson err(-1, "%s: shutdown", testname); 144143409Srwatson signal_setup(testname); 145143409Srwatson test_send(testname, sock2); 146143409Srwatson if (got_signal()) 147143409Srwatson errx(-1, "%s: send: got SIGPIPE", testname); 148143409Srwatson close(sock1); 149143409Srwatson close(sock2); 150143409Srwatson} 151143409Srwatson#endif 152143409Srwatson 153143409Srwatsonstatic void 154143409Srwatsontest_write_wantsignal(const char *testname, int sock1, int sock2) 155143409Srwatson{ 156143409Srwatson 157143413Srwatson if (shutdown(sock2, SHUT_WR) < 0) 158143413Srwatson err(-1, "%s: shutdown", testname); 159143409Srwatson signal_setup(testname); 160143409Srwatson test_write(testname, sock2); 161143409Srwatson if (!got_signal()) 162143409Srwatson errx(-1, "%s: write: didn't receive SIGPIPE", testname); 163143409Srwatson close(sock1); 164143409Srwatson close(sock2); 165143409Srwatson} 166143409Srwatson 167143409Srwatson#ifdef SO_NOSIGPIPE 168143409Srwatsonstatic void 169143409Srwatsontest_write_dontsignal(const char *testname, int sock1, int sock2) 170143409Srwatson{ 171143409Srwatson int i; 172143409Srwatson 173143409Srwatson i = 1; 174143409Srwatson if (setsockopt(sock2, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0) 175143409Srwatson err(-1, "%s: setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", testname); 176143413Srwatson if (shutdown(sock2, SHUT_WR) < 0) 177143413Srwatson err(-1, "%s: shutdown", testname); 178143409Srwatson signal_setup(testname); 179143409Srwatson test_write(testname, sock2); 180143409Srwatson if (got_signal()) 181143409Srwatson errx(-1, "%s: write: got SIGPIPE", testname); 182143409Srwatson close(sock1); 183143409Srwatson close(sock2); 184143409Srwatson} 185143409Srwatson#endif 186143409Srwatson 187143409Srwatsonstatic int listen_sock; 188143409Srwatsonstatic void 189143409Srwatsontcp_setup(u_short port) 190143409Srwatson{ 191143409Srwatson struct sockaddr_in sin; 192143409Srwatson 193143409Srwatson listen_sock = socket(PF_INET, SOCK_STREAM, 0); 194143409Srwatson if (listen_sock < 0) 195143409Srwatson err(-1, "tcp_setup: listen"); 196143409Srwatson 197143409Srwatson bzero(&sin, sizeof(sin)); 198143409Srwatson sin.sin_len = sizeof(sin); 199143409Srwatson sin.sin_family = AF_INET; 200143409Srwatson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 201143409Srwatson sin.sin_port = htons(port); 202143409Srwatson 203143409Srwatson if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 204143409Srwatson err(-1, "tcp_setup: bind"); 205143409Srwatson 206143409Srwatson if (listen(listen_sock, -1) < 0) 207143409Srwatson err(-1, "tcp_setup: listen"); 208143409Srwatson} 209143409Srwatson 210143409Srwatsonstatic void 211143409Srwatsontcp_teardown(void) 212143409Srwatson{ 213143409Srwatson 214143409Srwatson close(listen_sock); 215143409Srwatson} 216143409Srwatson 217143409Srwatsonstatic void 218143409Srwatsontcp_pair(u_short port, int sock[2]) 219143409Srwatson{ 220143409Srwatson int accept_sock, connect_sock; 221143409Srwatson struct sockaddr_in sin; 222143409Srwatson socklen_t len; 223143409Srwatson 224143409Srwatson connect_sock = socket(PF_INET, SOCK_STREAM, 0); 225143409Srwatson if (connect_sock < 0) 226143409Srwatson err(-1, "tcp_pair: socket"); 227143409Srwatson 228143409Srwatson bzero(&sin, sizeof(sin)); 229143409Srwatson sin.sin_len = sizeof(sin); 230143409Srwatson sin.sin_family = AF_INET; 231143409Srwatson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 232143409Srwatson sin.sin_port = htons(port); 233143409Srwatson 234143409Srwatson if (connect(connect_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 235143409Srwatson err(-1, "tcp_pair: connect"); 236143409Srwatson 237143409Srwatson sleep(1); /* Time for TCP to settle. */ 238143409Srwatson 239143409Srwatson len = sizeof(sin); 240143409Srwatson accept_sock = accept(listen_sock, (struct sockaddr *)&sin, &len); 241143409Srwatson if (accept_sock < 0) 242143409Srwatson err(-1, "tcp_pair: accept"); 243143409Srwatson 244143409Srwatson sleep(1); /* Time for TCP to settle. */ 245143409Srwatson 246143409Srwatson sock[0] = accept_sock; 247143409Srwatson sock[1] = connect_sock; 248143409Srwatson} 249143409Srwatson 250143409Srwatsonint 251143409Srwatsonmain(int argc, char *argv[]) 252143409Srwatson{ 253143409Srwatson char *dummy; 254143409Srwatson int sock[2]; 255143409Srwatson long port; 256143409Srwatson 257143409Srwatson if (argc != 2) 258143409Srwatson usage(); 259143409Srwatson 260143409Srwatson port = strtol(argv[1], &dummy, 10); 261143409Srwatson if (port < 0 || port > 65535 || *dummy != '\0') 262143409Srwatson usage(); 263143409Srwatson 264143409Srwatson#ifndef SO_NOSIGPIPE 265143409Srwatson warnx("sigpipe: SO_NOSIGPIPE not defined, skipping some tests"); 266143409Srwatson#endif 267143409Srwatson 268143409Srwatson /* 269143409Srwatson * UNIX domain socketpair(). 270143409Srwatson */ 271143409Srwatson if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0) 272143409Srwatson err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)"); 273143409Srwatson test_send_wantsignal("test_send_wantsignal(PF_LOCAL)", sock[0], 274143409Srwatson sock[1]); 275143409Srwatson 276143409Srwatson#ifdef SO_NOSIGPIPE 277143409Srwatson if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0) 278143409Srwatson err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)"); 279143409Srwatson test_send_dontsignal("test_send_dontsignal(PF_LOCAL)", sock[0], 280143409Srwatson sock[1]); 281143409Srwatson#endif 282143409Srwatson 283143409Srwatson if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0) 284143409Srwatson err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)"); 285143409Srwatson test_write_wantsignal("test_write_wantsignal(PF_LOCAL)", sock[0], 286143409Srwatson sock[1]); 287143409Srwatson 288143409Srwatson#ifdef SO_NOSIGPIPE 289143409Srwatson if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0) 290143409Srwatson err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)"); 291143409Srwatson test_write_dontsignal("test_write_dontsignal(PF_LOCAL)", sock[0], 292143409Srwatson sock[1]); 293143409Srwatson#endif 294143409Srwatson 295143409Srwatson /* 296143409Srwatson * TCP. 297143409Srwatson */ 298143409Srwatson tcp_setup(port); 299143409Srwatson tcp_pair(port, sock); 300143409Srwatson test_send_wantsignal("test_send_wantsignal(PF_INET)", sock[0], 301143409Srwatson sock[1]); 302143409Srwatson 303143409Srwatson#ifdef SO_NOSIGPIPE 304143409Srwatson tcp_pair(port, sock); 305143409Srwatson test_send_dontsignal("test_send_dontsignal(PF_INET)", sock[0], 306143409Srwatson sock[1]); 307143409Srwatson#endif 308143409Srwatson 309143409Srwatson tcp_pair(port, sock); 310143409Srwatson test_write_wantsignal("test_write_wantsignal(PF_INET)", sock[0], 311143409Srwatson sock[1]); 312143409Srwatson 313143409Srwatson#ifdef SO_NOSIGPIPE 314143409Srwatson tcp_pair(port, sock); 315143409Srwatson test_write_dontsignal("test_write_dontsignal(PF_INET)", sock[0], 316143409Srwatson sock[1]); 317143409Srwatson#endif 318143409Srwatson tcp_teardown(); 319143409Srwatson 320143409Srwatson fprintf(stderr, "PASS\n"); 321143409Srwatson return (0); 322143409Srwatson} 323