xref: /freebsd-src/tools/regression/netinet/tcpsockclosebeforeaccept/tcpsockclosebeforeaccept.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
14f29da19SRobert Watson /*-
24f29da19SRobert Watson  * Copyright (c) 2006 Robert N. M. Watson
34f29da19SRobert Watson  * All rights reserved.
44f29da19SRobert Watson  *
54f29da19SRobert Watson  * Redistribution and use in source and binary forms, with or without
64f29da19SRobert Watson  * modification, are permitted provided that the following conditions
74f29da19SRobert Watson  * are met:
84f29da19SRobert Watson  * 1. Redistributions of source code must retain the above copyright
94f29da19SRobert Watson  *    notice, this list of conditions and the following disclaimer.
104f29da19SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
114f29da19SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
124f29da19SRobert Watson  *    documentation and/or other materials provided with the distribution.
134f29da19SRobert Watson  *
144f29da19SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
154f29da19SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
164f29da19SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
174f29da19SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184f29da19SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194f29da19SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204f29da19SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214f29da19SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
224f29da19SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
234f29da19SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
244f29da19SRobert Watson  * SUCH DAMAGE.
254f29da19SRobert Watson  */
264f29da19SRobert Watson 
274f29da19SRobert Watson /*
284f29da19SRobert Watson  * TCP regression test which opens a loopback TCP session, and closes it
29*fc19db6cSRobert Watson  * before the remote endpoint (server) can accept it.  Run the test twice,
30*fc19db6cSRobert Watson  * once using an explicit close() from the client, a second using a tcp drop.
314f29da19SRobert Watson  */
324f29da19SRobert Watson 
334f29da19SRobert Watson #include <sys/types.h>
344f29da19SRobert Watson #include <sys/socket.h>
35*fc19db6cSRobert Watson #include <sys/sysctl.h>
364f29da19SRobert Watson 
374f29da19SRobert Watson #include <netinet/in.h>
384f29da19SRobert Watson 
394f29da19SRobert Watson #include <err.h>
404f29da19SRobert Watson #include <errno.h>
414f29da19SRobert Watson #include <signal.h>
424f29da19SRobert Watson #include <stdio.h>
434f29da19SRobert Watson #include <stdlib.h>
444f29da19SRobert Watson #include <string.h>
454f29da19SRobert Watson #include <unistd.h>
464f29da19SRobert Watson 
47*fc19db6cSRobert Watson #define	TCP_PORT	9005
48*fc19db6cSRobert Watson 
49*fc19db6cSRobert Watson static int
tcp_drop(struct sockaddr_in * sin_local,struct sockaddr_in * sin_remote)50*fc19db6cSRobert Watson tcp_drop(struct sockaddr_in *sin_local, struct sockaddr_in *sin_remote)
51*fc19db6cSRobert Watson {
52*fc19db6cSRobert Watson 	struct sockaddr_storage addrs[2];
53*fc19db6cSRobert Watson 
54*fc19db6cSRobert Watson 	/*
55*fc19db6cSRobert Watson 	 * Sysctl accepts an array of two sockaddr's, the first being the
56*fc19db6cSRobert Watson 	 * 'foreign' sockaddr, the second being the 'local' sockaddr.
57*fc19db6cSRobert Watson 	 */
58*fc19db6cSRobert Watson 
59*fc19db6cSRobert Watson 	bcopy(sin_remote, &addrs[0], sizeof(*sin_remote));
60*fc19db6cSRobert Watson 	bcopy(sin_local, &addrs[1], sizeof(*sin_local));
61*fc19db6cSRobert Watson 
62*fc19db6cSRobert Watson 	return (sysctlbyname("net.inet.tcp.drop", NULL, 0, addrs,
63*fc19db6cSRobert Watson 	    sizeof(addrs)));
64*fc19db6cSRobert Watson }
65*fc19db6cSRobert Watson 
664f29da19SRobert Watson 
674f29da19SRobert Watson static void
tcp_server(pid_t partner)684f29da19SRobert Watson tcp_server(pid_t partner)
694f29da19SRobert Watson {
704f29da19SRobert Watson 	int error, listen_fd, accept_fd;
714f29da19SRobert Watson 	struct sockaddr_in sin;
724f29da19SRobert Watson 
734f29da19SRobert Watson 	listen_fd = socket(PF_INET, SOCK_STREAM, 0);
744f29da19SRobert Watson 	if (listen_fd < 0) {
754f29da19SRobert Watson 		error = errno;
764f29da19SRobert Watson 		(void)kill(partner, SIGKILL);
774f29da19SRobert Watson 		errno = error;
784f29da19SRobert Watson 		err(-1, "tcp_server: socket");
794f29da19SRobert Watson 	}
804f29da19SRobert Watson 
814f29da19SRobert Watson 	bzero(&sin, sizeof(sin));
824f29da19SRobert Watson 	sin.sin_family = AF_INET;
834f29da19SRobert Watson 	sin.sin_len = sizeof(sin);
844f29da19SRobert Watson 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
854f29da19SRobert Watson 	sin.sin_port = htons(TCP_PORT);
864f29da19SRobert Watson 
874f29da19SRobert Watson 	if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
884f29da19SRobert Watson 		error = errno;
894f29da19SRobert Watson 		(void)kill(partner, SIGKILL);
904f29da19SRobert Watson 		errno = error;
914f29da19SRobert Watson 		err(-1, "tcp_server: bind");
924f29da19SRobert Watson 	}
934f29da19SRobert Watson 
944f29da19SRobert Watson 	if (listen(listen_fd, -1) < 0) {
954f29da19SRobert Watson 		error = errno;
964f29da19SRobert Watson 		(void)kill(partner, SIGKILL);
974f29da19SRobert Watson 		errno = error;
984f29da19SRobert Watson 		err(-1, "tcp_server: listen");
994f29da19SRobert Watson 	}
1004f29da19SRobert Watson 
1014f29da19SRobert Watson 	sleep(10);
1024f29da19SRobert Watson 
1034f29da19SRobert Watson 	accept_fd = accept(listen_fd, NULL, NULL);
1044f29da19SRobert Watson 	if (accept_fd < 0) {
1054f29da19SRobert Watson 		error = errno;
1064f29da19SRobert Watson 		(void)kill(partner, SIGKILL);
1074f29da19SRobert Watson 		errno = error;
1084f29da19SRobert Watson 		err(-1, "tcp_server: accept");
1094f29da19SRobert Watson 	}
1104f29da19SRobert Watson 	close(accept_fd);
1114f29da19SRobert Watson 	close(listen_fd);
1124f29da19SRobert Watson }
1134f29da19SRobert Watson 
1144f29da19SRobert Watson static void
tcp_client(pid_t partner,int dropflag)115*fc19db6cSRobert Watson tcp_client(pid_t partner, int dropflag)
1164f29da19SRobert Watson {
117*fc19db6cSRobert Watson 	struct sockaddr_in sin, sin_local;
1184f29da19SRobert Watson 	int error, sock;
119*fc19db6cSRobert Watson 	socklen_t slen;
1204f29da19SRobert Watson 
1214f29da19SRobert Watson 	sleep(1);
1224f29da19SRobert Watson 
1234f29da19SRobert Watson 	sock = socket(PF_INET, SOCK_STREAM, 0);
1244f29da19SRobert Watson 	if (sock < 0) {
1254f29da19SRobert Watson 		error = errno;
1264f29da19SRobert Watson 		(void)kill(partner, SIGKILL);
1274f29da19SRobert Watson 		errno = error;
1284f29da19SRobert Watson 		err(-1, "socket");
1294f29da19SRobert Watson 	}
1304f29da19SRobert Watson 
1314f29da19SRobert Watson 	bzero(&sin, sizeof(sin));
1324f29da19SRobert Watson 	sin.sin_family = AF_INET;
1334f29da19SRobert Watson 	sin.sin_len = sizeof(sin);
1344f29da19SRobert Watson 	sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
1354f29da19SRobert Watson 	sin.sin_port = htons(TCP_PORT);
1364f29da19SRobert Watson 
1374f29da19SRobert Watson 	if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
1384f29da19SRobert Watson 		error = errno;
1394f29da19SRobert Watson 		(void)kill(partner, SIGKILL);
1404f29da19SRobert Watson 		errno = error;
1414f29da19SRobert Watson 		err(-1, "connect");
1424f29da19SRobert Watson 	}
1434f29da19SRobert Watson 
144*fc19db6cSRobert Watson 	slen = sizeof(sin_local);
145*fc19db6cSRobert Watson 	if (getsockname(sock, (struct sockaddr *)&sin_local, &slen) < 0) {
146*fc19db6cSRobert Watson 		error = errno;
147*fc19db6cSRobert Watson 		(void)kill(partner, SIGKILL);
148*fc19db6cSRobert Watson 		errno = error;
149*fc19db6cSRobert Watson 		err(-1, "getsockname");
150*fc19db6cSRobert Watson 	}
151*fc19db6cSRobert Watson 
152*fc19db6cSRobert Watson 	if (dropflag) {
153*fc19db6cSRobert Watson 		if (tcp_drop(&sin_local, &sin) < 0) {
154*fc19db6cSRobert Watson 			error = errno;
155*fc19db6cSRobert Watson 			(void)kill(partner, SIGKILL);
156*fc19db6cSRobert Watson 			errno = error;
157*fc19db6cSRobert Watson 			err(-1, "tcp_drop");
158*fc19db6cSRobert Watson 		}
159*fc19db6cSRobert Watson 		sleep(2);
160*fc19db6cSRobert Watson 	}
1614f29da19SRobert Watson 	close(sock);
1624f29da19SRobert Watson }
1634f29da19SRobert Watson 
1644f29da19SRobert Watson int
main(int argc,char * argv[])1654f29da19SRobert Watson main(int argc, char *argv[])
1664f29da19SRobert Watson {
1674f29da19SRobert Watson 	pid_t child_pid, parent_pid;
1684f29da19SRobert Watson 
1694f29da19SRobert Watson 	if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
1704f29da19SRobert Watson 		err(-1, "signal");
1714f29da19SRobert Watson 
1724f29da19SRobert Watson 	parent_pid = getpid();
1734f29da19SRobert Watson 	child_pid = fork();
1744f29da19SRobert Watson 	if (child_pid < 0)
1754f29da19SRobert Watson 		err(-1, "fork");
1764f29da19SRobert Watson 	if (child_pid == 0) {
1774f29da19SRobert Watson 		child_pid = getpid();
1784f29da19SRobert Watson 		tcp_server(parent_pid);
179*fc19db6cSRobert Watson 		return (0);
1804f29da19SRobert Watson 	} else
181*fc19db6cSRobert Watson 		tcp_client(child_pid, 0);
182*fc19db6cSRobert Watson 	(void)kill(child_pid, SIGTERM);
183*fc19db6cSRobert Watson 
184*fc19db6cSRobert Watson 	sleep(5);
185*fc19db6cSRobert Watson 
186*fc19db6cSRobert Watson 	parent_pid = getpid();
187*fc19db6cSRobert Watson 	child_pid = fork();
188*fc19db6cSRobert Watson 	if (child_pid < 0)
189*fc19db6cSRobert Watson 		err(-1, "fork");
190*fc19db6cSRobert Watson 	if (child_pid == 0) {
191*fc19db6cSRobert Watson 		child_pid = getpid();
192*fc19db6cSRobert Watson 		tcp_server(parent_pid);
193*fc19db6cSRobert Watson 		return (0);
194*fc19db6cSRobert Watson 	} else
195*fc19db6cSRobert Watson 		tcp_client(child_pid, 1);
196*fc19db6cSRobert Watson 	(void)kill(child_pid, SIGTERM);
1974f29da19SRobert Watson 
1984f29da19SRobert Watson 	return (0);
1994f29da19SRobert Watson }
200