tcpsocktimewait.c revision 222486
1157387Srwatson/*- 2157387Srwatson * Copyright (c) 2006 Robert N. M. Watson 3222486Srwatson * Copyright (c) 2011 Juniper Networks, Inc. 4157387Srwatson * All rights reserved. 5157387Srwatson * 6222486Srwatson * Portions of this software were developed by Robert N. M. Watson under 7222486Srwatson * contract to Juniper Networks, Inc. 8222486Srwatson * 9157387Srwatson * Redistribution and use in source and binary forms, with or without 10157387Srwatson * modification, are permitted provided that the following conditions 11157387Srwatson * are met: 12157387Srwatson * 1. Redistributions of source code must retain the above copyright 13157387Srwatson * notice, this list of conditions and the following disclaimer. 14157387Srwatson * 2. Redistributions in binary form must reproduce the above copyright 15157387Srwatson * notice, this list of conditions and the following disclaimer in the 16157387Srwatson * documentation and/or other materials provided with the distribution. 17157387Srwatson * 18157387Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19157387Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20157387Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21157387Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22157387Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23157387Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24157387Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25157387Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26157387Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27157387Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28157387Srwatson * SUCH DAMAGE. 29157387Srwatson * 30157387Srwatson * $FreeBSD: head/tools/regression/netinet/tcpsocktimewait/tcpsocktimewait.c 222486 2011-05-30 09:34:15Z rwatson $ 31157387Srwatson */ 32157387Srwatson 33157387Srwatson/* 34157387Srwatson * TCP regression test that opens a loopback TCP session, then closes one end 35157387Srwatson * while shutting down the other. This triggers an unusual TCP stack case in 36157387Srwatson * which an open file descriptor / socket is associated with a closed TCP 37157387Srwatson * connection. 38157387Srwatson */ 39157387Srwatson 40157387Srwatson#include <sys/types.h> 41157387Srwatson#include <sys/socket.h> 42157387Srwatson 43157387Srwatson#include <netinet/in.h> 44157387Srwatson 45157387Srwatson#include <err.h> 46157387Srwatson#include <errno.h> 47157387Srwatson#include <signal.h> 48222486Srwatson#include <stdio.h> 49157387Srwatson#include <stdlib.h> 50157387Srwatson#include <string.h> 51157387Srwatson#include <unistd.h> 52157387Srwatson 53157387Srwatsonstatic void 54222486Srwatsontcp_server(pid_t partner, int listen_fd) 55157387Srwatson{ 56222486Srwatson int error, accept_fd; 57157387Srwatson 58157387Srwatson accept_fd = accept(listen_fd, NULL, NULL); 59157387Srwatson if (accept_fd < 0) { 60157387Srwatson error = errno; 61157402Srwatson (void)kill(partner, SIGTERM); 62157387Srwatson errno = error; 63157387Srwatson err(-1, "tcp_server: accept"); 64157387Srwatson } 65157387Srwatson close(accept_fd); 66157387Srwatson close(listen_fd); 67157387Srwatson} 68157387Srwatson 69157387Srwatsonstatic void 70222486Srwatsontcp_client(pid_t partner, u_short port, int secs) 71157387Srwatson{ 72157387Srwatson struct sockaddr_in sin; 73157387Srwatson int error, sock; 74157387Srwatson 75157387Srwatson sleep(1); 76157387Srwatson 77157387Srwatson sock = socket(PF_INET, SOCK_STREAM, 0); 78157387Srwatson if (sock < 0) { 79157387Srwatson error = errno; 80157402Srwatson (void)kill(partner, SIGTERM); 81157387Srwatson errno = error; 82157387Srwatson err(-1, "socket"); 83157387Srwatson } 84157387Srwatson 85157387Srwatson bzero(&sin, sizeof(sin)); 86157387Srwatson sin.sin_family = AF_INET; 87157387Srwatson sin.sin_len = sizeof(sin); 88157387Srwatson sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK); 89222486Srwatson sin.sin_port = port; 90157387Srwatson 91157387Srwatson if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 92157387Srwatson error = errno; 93157402Srwatson (void)kill(partner, SIGTERM); 94157387Srwatson errno = error; 95157387Srwatson err(-1, "connect"); 96157387Srwatson } 97157387Srwatson 98157387Srwatson if (shutdown(sock, SHUT_RDWR) < 0) { 99157387Srwatson error = errno; 100157402Srwatson (void)kill(partner, SIGTERM); 101157387Srwatson errno = error; 102157387Srwatson err(-1, "shutdown"); 103157387Srwatson } 104157387Srwatson 105157387Srwatson sleep(secs); 106157387Srwatson close(sock); 107157387Srwatson} 108157387Srwatson 109157387Srwatsonint 110157387Srwatsonmain(int argc, char *argv[]) 111157387Srwatson{ 112222486Srwatson struct sockaddr_in sin; 113157387Srwatson pid_t child_pid, parent_pid; 114222486Srwatson int listen_fd; 115222486Srwatson socklen_t len; 116222486Srwatson u_short port; 117157387Srwatson 118157387Srwatson if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) 119157387Srwatson err(-1, "signal"); 120157387Srwatson 121157387Srwatson /* 122157387Srwatson * Run the whole thing twice: once, with a short sleep in the client, 123157387Srwatson * so that we close before time wait runs out, and once with a long 124157387Srwatson * sleep so that the time wait terminates while the socket is open. 125222486Srwatson * We don't reuse listen sockets between runs. 126157387Srwatson */ 127222486Srwatson listen_fd = socket(PF_INET, SOCK_STREAM, 0); 128222486Srwatson if (listen_fd < 0) 129222486Srwatson err(-1, "socket"); 130222486Srwatson 131222486Srwatson /* 132222486Srwatson * We use the loopback, but let the kernel select a port for the 133222486Srwatson * server socket. 134222486Srwatson */ 135222486Srwatson bzero(&sin, sizeof(sin)); 136222486Srwatson sin.sin_family = AF_INET; 137222486Srwatson sin.sin_len = sizeof(sin); 138222486Srwatson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 139222486Srwatson 140222486Srwatson if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) 141222486Srwatson err(-1, "bind"); 142222486Srwatson 143222486Srwatson if (listen(listen_fd, -1) < 0) 144222486Srwatson err(-1, "listen"); 145222486Srwatson 146222486Srwatson /* 147222486Srwatson * Query the port so that the client can use it. 148222486Srwatson */ 149222486Srwatson bzero(&sin, sizeof(sin)); 150222486Srwatson sin.sin_family = AF_INET; 151222486Srwatson sin.sin_len = sizeof(sin); 152222486Srwatson len = sizeof(sin); 153222486Srwatson if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0) 154222486Srwatson err(-1, "getsockname"); 155222486Srwatson port = sin.sin_port; 156222486Srwatson printf("Using port %d\n", ntohs(port)); 157222486Srwatson 158157387Srwatson parent_pid = getpid(); 159157387Srwatson child_pid = fork(); 160157387Srwatson if (child_pid < 0) 161157387Srwatson err(-1, "fork"); 162157387Srwatson if (child_pid == 0) { 163157387Srwatson child_pid = getpid(); 164222486Srwatson tcp_server(child_pid, listen_fd); 165157402Srwatson exit(0); 166157387Srwatson } else 167222486Srwatson tcp_client(parent_pid, port, 1); 168157402Srwatson (void)kill(child_pid, SIGTERM); 169222486Srwatson close(listen_fd); 170157402Srwatson sleep(5); 171157387Srwatson 172222486Srwatson /* 173222486Srwatson * Start again, this time long sleep. 174222486Srwatson */ 175222486Srwatson listen_fd = socket(PF_INET, SOCK_STREAM, 0); 176222486Srwatson if (listen_fd < 0) 177222486Srwatson err(-1, "socket"); 178222486Srwatson 179222486Srwatson /* 180222486Srwatson * We use the loopback, but let the kernel select a port for the 181222486Srwatson * server socket. 182222486Srwatson */ 183222486Srwatson bzero(&sin, sizeof(sin)); 184222486Srwatson sin.sin_family = AF_INET; 185222486Srwatson sin.sin_len = sizeof(sin); 186222486Srwatson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 187222486Srwatson 188222486Srwatson if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) 189222486Srwatson err(-1, "bind"); 190222486Srwatson 191222486Srwatson if (listen(listen_fd, -1) < 0) 192222486Srwatson err(-1, "listen"); 193222486Srwatson 194222486Srwatson /* 195222486Srwatson * Query the port so that the client can use it. 196222486Srwatson */ 197222486Srwatson bzero(&sin, sizeof(sin)); 198222486Srwatson sin.sin_family = AF_INET; 199222486Srwatson sin.sin_len = sizeof(sin); 200222486Srwatson len = sizeof(sin); 201222486Srwatson if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0) 202222486Srwatson err(-1, "getsockname"); 203222486Srwatson port = sin.sin_port; 204222486Srwatson printf("Using port %d\n", ntohs(port)); 205222486Srwatson 206157387Srwatson parent_pid = getpid(); 207157387Srwatson child_pid = fork(); 208157387Srwatson if (child_pid < 0) 209157387Srwatson err(-1, "fork"); 210157387Srwatson if (child_pid == 0) { 211157387Srwatson child_pid = getpid(); 212222486Srwatson tcp_server(parent_pid, listen_fd); 213157387Srwatson } else 214222486Srwatson tcp_client(child_pid, port, 800); 215157387Srwatson 216157387Srwatson return (0); 217157387Srwatson} 218