1 /*- 2 * Copyright (c) 2006 Robert N. M. Watson 3 * Copyright (c) 2011 Juniper Networks, Inc. 4 * All rights reserved. 5 * 6 * Portions of this software were developed by Robert N. M. Watson under 7 * contract to Juniper Networks, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 */ 32 33 /* 34 * TCP regression test that opens a loopback TCP session, then closes one end 35 * while shutting down the other. This triggers an unusual TCP stack case in 36 * which an open file descriptor / socket is associated with a closed TCP 37 * connection. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/socket.h> 42 43 #include <netinet/in.h> 44 45 #include <err.h> 46 #include <errno.h> 47 #include <signal.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 static void 54 tcp_server(pid_t partner, int listen_fd) 55 { 56 int error, accept_fd; 57 58 accept_fd = accept(listen_fd, NULL, NULL); 59 if (accept_fd < 0) { 60 error = errno; 61 (void)kill(partner, SIGTERM); 62 errno = error; 63 err(-1, "tcp_server: accept"); 64 } 65 close(accept_fd); 66 close(listen_fd); 67 } 68 69 static void 70 tcp_client(pid_t partner, u_short port, int secs) 71 { 72 struct sockaddr_in sin; 73 int error, sock; 74 75 sleep(1); 76 77 sock = socket(PF_INET, SOCK_STREAM, 0); 78 if (sock < 0) { 79 error = errno; 80 (void)kill(partner, SIGTERM); 81 errno = error; 82 err(-1, "socket"); 83 } 84 85 bzero(&sin, sizeof(sin)); 86 sin.sin_family = AF_INET; 87 sin.sin_len = sizeof(sin); 88 sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK); 89 sin.sin_port = port; 90 91 if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 92 error = errno; 93 (void)kill(partner, SIGTERM); 94 errno = error; 95 err(-1, "connect"); 96 } 97 98 if (shutdown(sock, SHUT_RDWR) < 0) { 99 error = errno; 100 (void)kill(partner, SIGTERM); 101 errno = error; 102 err(-1, "shutdown"); 103 } 104 105 sleep(secs); 106 close(sock); 107 } 108 109 int 110 main(int argc, char *argv[]) 111 { 112 struct sockaddr_in sin; 113 pid_t child_pid, parent_pid; 114 int listen_fd; 115 socklen_t len; 116 u_short port; 117 118 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) 119 err(-1, "signal"); 120 121 /* 122 * Run the whole thing twice: once, with a short sleep in the client, 123 * so that we close before time wait runs out, and once with a long 124 * sleep so that the time wait terminates while the socket is open. 125 * We don't reuse listen sockets between runs. 126 */ 127 listen_fd = socket(PF_INET, SOCK_STREAM, 0); 128 if (listen_fd < 0) 129 err(-1, "socket"); 130 131 /* 132 * We use the loopback, but let the kernel select a port for the 133 * server socket. 134 */ 135 bzero(&sin, sizeof(sin)); 136 sin.sin_family = AF_INET; 137 sin.sin_len = sizeof(sin); 138 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 139 140 if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) 141 err(-1, "bind"); 142 143 if (listen(listen_fd, -1) < 0) 144 err(-1, "listen"); 145 146 /* 147 * Query the port so that the client can use it. 148 */ 149 bzero(&sin, sizeof(sin)); 150 sin.sin_family = AF_INET; 151 sin.sin_len = sizeof(sin); 152 len = sizeof(sin); 153 if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0) 154 err(-1, "getsockname"); 155 port = sin.sin_port; 156 printf("Using port %d\n", ntohs(port)); 157 158 parent_pid = getpid(); 159 child_pid = fork(); 160 if (child_pid < 0) 161 err(-1, "fork"); 162 if (child_pid == 0) { 163 child_pid = getpid(); 164 tcp_server(child_pid, listen_fd); 165 exit(0); 166 } else 167 tcp_client(parent_pid, port, 1); 168 (void)kill(child_pid, SIGTERM); 169 close(listen_fd); 170 sleep(5); 171 172 /* 173 * Start again, this time long sleep. 174 */ 175 listen_fd = socket(PF_INET, SOCK_STREAM, 0); 176 if (listen_fd < 0) 177 err(-1, "socket"); 178 179 /* 180 * We use the loopback, but let the kernel select a port for the 181 * server socket. 182 */ 183 bzero(&sin, sizeof(sin)); 184 sin.sin_family = AF_INET; 185 sin.sin_len = sizeof(sin); 186 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 187 188 if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) 189 err(-1, "bind"); 190 191 if (listen(listen_fd, -1) < 0) 192 err(-1, "listen"); 193 194 /* 195 * Query the port so that the client can use it. 196 */ 197 bzero(&sin, sizeof(sin)); 198 sin.sin_family = AF_INET; 199 sin.sin_len = sizeof(sin); 200 len = sizeof(sin); 201 if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0) 202 err(-1, "getsockname"); 203 port = sin.sin_port; 204 printf("Using port %d\n", ntohs(port)); 205 206 parent_pid = getpid(); 207 child_pid = fork(); 208 if (child_pid < 0) 209 err(-1, "fork"); 210 if (child_pid == 0) { 211 child_pid = getpid(); 212 tcp_server(parent_pid, listen_fd); 213 } else 214 tcp_client(child_pid, port, 800); 215 216 return (0); 217 } 218