Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/regression/netinet/tcpsocktimewait/tcpsocktimewait.c
39491 views
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
31
/*
32
* TCP regression test that opens a loopback TCP session, then closes one end
33
* while shutting down the other. This triggers an unusual TCP stack case in
34
* which an open file descriptor / socket is associated with a closed TCP
35
* connection.
36
*/
37
38
#include <sys/types.h>
39
#include <sys/socket.h>
40
41
#include <netinet/in.h>
42
43
#include <err.h>
44
#include <errno.h>
45
#include <signal.h>
46
#include <stdio.h>
47
#include <stdlib.h>
48
#include <string.h>
49
#include <unistd.h>
50
51
static void
52
tcp_server(pid_t partner, int listen_fd)
53
{
54
int error, accept_fd;
55
56
accept_fd = accept(listen_fd, NULL, NULL);
57
if (accept_fd < 0) {
58
error = errno;
59
(void)kill(partner, SIGTERM);
60
errno = error;
61
err(-1, "tcp_server: accept");
62
}
63
close(accept_fd);
64
close(listen_fd);
65
}
66
67
static void
68
tcp_client(pid_t partner, u_short port, int secs)
69
{
70
struct sockaddr_in sin;
71
int error, sock;
72
73
sleep(1);
74
75
sock = socket(PF_INET, SOCK_STREAM, 0);
76
if (sock < 0) {
77
error = errno;
78
(void)kill(partner, SIGTERM);
79
errno = error;
80
err(-1, "socket");
81
}
82
83
bzero(&sin, sizeof(sin));
84
sin.sin_family = AF_INET;
85
sin.sin_len = sizeof(sin);
86
sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
87
sin.sin_port = port;
88
89
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
90
error = errno;
91
(void)kill(partner, SIGTERM);
92
errno = error;
93
err(-1, "connect");
94
}
95
96
if (shutdown(sock, SHUT_RDWR) < 0) {
97
error = errno;
98
(void)kill(partner, SIGTERM);
99
errno = error;
100
err(-1, "shutdown");
101
}
102
103
sleep(secs);
104
close(sock);
105
}
106
107
int
108
main(int argc, char *argv[])
109
{
110
struct sockaddr_in sin;
111
pid_t child_pid, parent_pid;
112
int listen_fd;
113
socklen_t len;
114
u_short port;
115
116
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
117
err(-1, "signal");
118
119
/*
120
* Run the whole thing twice: once, with a short sleep in the client,
121
* so that we close before time wait runs out, and once with a long
122
* sleep so that the time wait terminates while the socket is open.
123
* We don't reuse listen sockets between runs.
124
*/
125
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
126
if (listen_fd < 0)
127
err(-1, "socket");
128
129
/*
130
* We use the loopback, but let the kernel select a port for the
131
* server socket.
132
*/
133
bzero(&sin, sizeof(sin));
134
sin.sin_family = AF_INET;
135
sin.sin_len = sizeof(sin);
136
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
137
138
if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
139
err(-1, "bind");
140
141
if (listen(listen_fd, -1) < 0)
142
err(-1, "listen");
143
144
/*
145
* Query the port so that the client can use it.
146
*/
147
bzero(&sin, sizeof(sin));
148
sin.sin_family = AF_INET;
149
sin.sin_len = sizeof(sin);
150
len = sizeof(sin);
151
if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
152
err(-1, "getsockname");
153
port = sin.sin_port;
154
printf("Using port %d\n", ntohs(port));
155
156
parent_pid = getpid();
157
child_pid = fork();
158
if (child_pid < 0)
159
err(-1, "fork");
160
if (child_pid == 0) {
161
child_pid = getpid();
162
tcp_server(child_pid, listen_fd);
163
exit(0);
164
} else
165
tcp_client(parent_pid, port, 1);
166
(void)kill(child_pid, SIGTERM);
167
close(listen_fd);
168
sleep(5);
169
170
/*
171
* Start again, this time long sleep.
172
*/
173
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
174
if (listen_fd < 0)
175
err(-1, "socket");
176
177
/*
178
* We use the loopback, but let the kernel select a port for the
179
* server socket.
180
*/
181
bzero(&sin, sizeof(sin));
182
sin.sin_family = AF_INET;
183
sin.sin_len = sizeof(sin);
184
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
185
186
if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
187
err(-1, "bind");
188
189
if (listen(listen_fd, -1) < 0)
190
err(-1, "listen");
191
192
/*
193
* Query the port so that the client can use it.
194
*/
195
bzero(&sin, sizeof(sin));
196
sin.sin_family = AF_INET;
197
sin.sin_len = sizeof(sin);
198
len = sizeof(sin);
199
if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
200
err(-1, "getsockname");
201
port = sin.sin_port;
202
printf("Using port %d\n", ntohs(port));
203
204
parent_pid = getpid();
205
child_pid = fork();
206
if (child_pid < 0)
207
err(-1, "fork");
208
if (child_pid == 0) {
209
child_pid = getpid();
210
tcp_server(parent_pid, listen_fd);
211
} else
212
tcp_client(child_pid, port, 800);
213
214
return (0);
215
}
216
217