]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - tools/regression/netinet/tcpsocktimewait/tcpsocktimewait.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / tools / regression / netinet / tcpsocktimewait / tcpsocktimewait.c
1 /*-
2  * Copyright (c) 2006 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 /*
30  * TCP regression test that opens a loopback TCP session, then closes one end
31  * while shutting down the other.  This triggers an unusual TCP stack case in
32  * which an open file descriptor / socket is associated with a closed TCP
33  * connection.
34  */
35
36 #include <sys/types.h>
37 #include <sys/socket.h>
38
39 #include <netinet/in.h>
40
41 #include <err.h>
42 #include <errno.h>
43 #include <signal.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #define TCP_PORT        9001
49
50 static void
51 tcp_server(pid_t partner)
52 {
53         int error, listen_fd, accept_fd;
54         struct sockaddr_in sin;
55
56         listen_fd = socket(PF_INET, SOCK_STREAM, 0);
57         if (listen_fd < 0) {
58                 error = errno;
59                 (void)kill(partner, SIGTERM);
60                 errno = error;
61                 err(-1, "tcp_server: socket");
62         }
63
64         bzero(&sin, sizeof(sin));
65         sin.sin_family = AF_INET;
66         sin.sin_len = sizeof(sin);
67         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
68         sin.sin_port = htons(TCP_PORT);
69
70         if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
71                 error = errno;
72                 (void)kill(partner, SIGTERM);
73                 errno = error;
74                 err(-1, "tcp_server: bind");
75         }
76
77         if (listen(listen_fd, -1) < 0) {
78                 error = errno;
79                 (void)kill(partner, SIGTERM);
80                 errno = error;
81                 err(-1, "tcp_server: listen");
82         }
83
84         accept_fd = accept(listen_fd, NULL, NULL);
85         if (accept_fd < 0) {
86                 error = errno;
87                 (void)kill(partner, SIGTERM);
88                 errno = error;
89                 err(-1, "tcp_server: accept");
90         }
91         close(accept_fd);
92         close(listen_fd);
93 }
94
95 static void
96 tcp_client(pid_t partner, int secs)
97 {
98         struct sockaddr_in sin;
99         int error, sock;
100
101         sleep(1);
102
103         sock = socket(PF_INET, SOCK_STREAM, 0);
104         if (sock < 0) {
105                 error = errno;
106                 (void)kill(partner, SIGTERM);
107                 errno = error;
108                 err(-1, "socket");
109         }
110
111         bzero(&sin, sizeof(sin));
112         sin.sin_family = AF_INET;
113         sin.sin_len = sizeof(sin);
114         sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
115         sin.sin_port = htons(TCP_PORT);
116
117         if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
118                 error = errno;
119                 (void)kill(partner, SIGTERM);
120                 errno = error;
121                 err(-1, "connect");
122         }
123
124         if (shutdown(sock, SHUT_RDWR) < 0) {
125                 error = errno;
126                 (void)kill(partner, SIGTERM);
127                 errno = error;
128                 err(-1, "shutdown");
129         }
130
131         sleep(secs);
132         close(sock);
133 }
134
135 int
136 main(int argc, char *argv[])
137 {
138         pid_t child_pid, parent_pid;
139
140         if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
141                 err(-1, "signal");
142
143         /*
144          * Run the whole thing twice: once, with a short sleep in the client,
145          * so that we close before time wait runs out, and once with a long
146          * sleep so that the time wait terminates while the socket is open.
147          */
148         parent_pid = getpid();
149         child_pid = fork();
150         if (child_pid < 0)
151                 err(-1, "fork");
152         if (child_pid == 0) {
153                 child_pid = getpid();
154                 tcp_server(child_pid);
155                 exit(0);
156         } else
157                 tcp_client(parent_pid, 1);
158         (void)kill(child_pid, SIGTERM);
159         sleep(5);
160
161         parent_pid = getpid();
162         child_pid = fork();
163         if (child_pid < 0)
164                 err(-1, "fork");
165         if (child_pid == 0) {
166                 child_pid = getpid();
167                 tcp_server(parent_pid);
168         } else
169                 tcp_client(child_pid, 800);
170
171         return (0);
172 }