]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/regression/netinet/tcpsocktimewait/tcpsocktimewait.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / regression / netinet / tcpsocktimewait / tcpsocktimewait.c
1 /*-
2  * Copyright (c) 2006 Robert N. M. Watson
3  * Copyright (c) 2011 Juniper Networks, Inc.
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Robert N. M. Watson under
7  * contract to Juniper Networks, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
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.
17  *
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
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32
33 /*
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
37  * connection.
38  */
39
40 #include <sys/types.h>
41 #include <sys/socket.h>
42
43 #include <netinet/in.h>
44
45 #include <err.h>
46 #include <errno.h>
47 #include <signal.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52
53 static void
54 tcp_server(pid_t partner, int listen_fd)
55 {
56         int error, accept_fd;
57
58         accept_fd = accept(listen_fd, NULL, NULL);
59         if (accept_fd < 0) {
60                 error = errno;
61                 (void)kill(partner, SIGTERM);
62                 errno = error;
63                 err(-1, "tcp_server: accept");
64         }
65         close(accept_fd);
66         close(listen_fd);
67 }
68
69 static void
70 tcp_client(pid_t partner, u_short port, int secs)
71 {
72         struct sockaddr_in sin;
73         int error, sock;
74
75         sleep(1);
76
77         sock = socket(PF_INET, SOCK_STREAM, 0);
78         if (sock < 0) {
79                 error = errno;
80                 (void)kill(partner, SIGTERM);
81                 errno = error;
82                 err(-1, "socket");
83         }
84
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);
89         sin.sin_port = port;
90
91         if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
92                 error = errno;
93                 (void)kill(partner, SIGTERM);
94                 errno = error;
95                 err(-1, "connect");
96         }
97
98         if (shutdown(sock, SHUT_RDWR) < 0) {
99                 error = errno;
100                 (void)kill(partner, SIGTERM);
101                 errno = error;
102                 err(-1, "shutdown");
103         }
104
105         sleep(secs);
106         close(sock);
107 }
108
109 int
110 main(int argc, char *argv[])
111 {
112         struct sockaddr_in sin;
113         pid_t child_pid, parent_pid;
114         int listen_fd;
115         socklen_t len;
116         u_short port;
117
118         if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
119                 err(-1, "signal");
120
121         /*
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.
126          */
127         listen_fd = socket(PF_INET, SOCK_STREAM, 0);
128         if (listen_fd < 0)
129                 err(-1, "socket");
130
131         /*
132          * We use the loopback, but let the kernel select a port for the
133          * server socket.
134          */
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);
139
140         if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
141                 err(-1, "bind");
142
143         if (listen(listen_fd, -1) < 0)
144                 err(-1, "listen");
145
146         /*
147          * Query the port so that the client can use it.
148          */
149         bzero(&sin, sizeof(sin));
150         sin.sin_family = AF_INET;
151         sin.sin_len = sizeof(sin);
152         len = sizeof(sin);
153         if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
154                 err(-1, "getsockname");
155         port = sin.sin_port;
156         printf("Using port %d\n", ntohs(port));
157
158         parent_pid = getpid();
159         child_pid = fork();
160         if (child_pid < 0)
161                 err(-1, "fork");
162         if (child_pid == 0) {
163                 child_pid = getpid();
164                 tcp_server(child_pid, listen_fd);
165                 exit(0);
166         } else
167                 tcp_client(parent_pid, port, 1);
168         (void)kill(child_pid, SIGTERM);
169         close(listen_fd);
170         sleep(5);
171
172         /*
173          * Start again, this time long sleep.
174          */
175         listen_fd = socket(PF_INET, SOCK_STREAM, 0);
176         if (listen_fd < 0)
177                 err(-1, "socket");
178
179         /*
180          * We use the loopback, but let the kernel select a port for the
181          * server socket.
182          */
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);
187
188         if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
189                 err(-1, "bind");
190
191         if (listen(listen_fd, -1) < 0)
192                 err(-1, "listen");
193
194         /*
195          * Query the port so that the client can use it.
196          */
197         bzero(&sin, sizeof(sin));
198         sin.sin_family = AF_INET;
199         sin.sin_len = sizeof(sin);
200         len = sizeof(sin);
201         if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
202                 err(-1, "getsockname");
203         port = sin.sin_port;
204         printf("Using port %d\n", ntohs(port));
205
206         parent_pid = getpid();
207         child_pid = fork();
208         if (child_pid < 0)
209                 err(-1, "fork");
210         if (child_pid == 0) {
211                 child_pid = getpid();
212                 tcp_server(parent_pid, listen_fd);
213         } else
214                 tcp_client(child_pid, port, 800);
215
216         return (0);
217 }