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$
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