2 * Copyright (c) 2006 Robert N. M. Watson
3 * Copyright (c) 2011 Juniper Networks, Inc.
6 * Portions of this software were developed by Robert N. M. Watson under
7 * contract to Juniper Networks, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
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
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #include <netinet/in.h>
54 tcp_server(pid_t partner, int listen_fd)
58 accept_fd = accept(listen_fd, NULL, NULL);
61 (void)kill(partner, SIGTERM);
63 err(-1, "tcp_server: accept");
70 tcp_client(pid_t partner, u_short port, int secs)
72 struct sockaddr_in sin;
77 sock = socket(PF_INET, SOCK_STREAM, 0);
80 (void)kill(partner, SIGTERM);
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);
91 if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
93 (void)kill(partner, SIGTERM);
98 if (shutdown(sock, SHUT_RDWR) < 0) {
100 (void)kill(partner, SIGTERM);
110 main(int argc, char *argv[])
112 struct sockaddr_in sin;
113 pid_t child_pid, parent_pid;
118 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
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.
127 listen_fd = socket(PF_INET, SOCK_STREAM, 0);
132 * We use the loopback, but let the kernel select a port for the
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);
140 if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
143 if (listen(listen_fd, -1) < 0)
147 * Query the port so that the client can use it.
149 bzero(&sin, sizeof(sin));
150 sin.sin_family = AF_INET;
151 sin.sin_len = sizeof(sin);
153 if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
154 err(-1, "getsockname");
156 printf("Using port %d\n", ntohs(port));
158 parent_pid = getpid();
162 if (child_pid == 0) {
163 child_pid = getpid();
164 tcp_server(child_pid, listen_fd);
167 tcp_client(parent_pid, port, 1);
168 (void)kill(child_pid, SIGTERM);
173 * Start again, this time long sleep.
175 listen_fd = socket(PF_INET, SOCK_STREAM, 0);
180 * We use the loopback, but let the kernel select a port for the
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);
188 if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
191 if (listen(listen_fd, -1) < 0)
195 * Query the port so that the client can use it.
197 bzero(&sin, sizeof(sin));
198 sin.sin_family = AF_INET;
199 sin.sin_len = sizeof(sin);
201 if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
202 err(-1, "getsockname");
204 printf("Using port %d\n", ntohs(port));
206 parent_pid = getpid();
210 if (child_pid == 0) {
211 child_pid = getpid();
212 tcp_server(parent_pid, listen_fd);
214 tcp_client(child_pid, port, 800);