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