Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/regression/netinet/tcpdrop/tcpdrop.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 for the tcpdrop sysctl; build a loopback TCP
33
* connection, drop it, and make sure both endpoints return that the
34
* connection has been reset.
35
*/
36
37
#include <sys/types.h>
38
#include <sys/socket.h>
39
#include <sys/sysctl.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 int
52
tcp_drop(struct sockaddr_in *sin_local, struct sockaddr_in *sin_remote)
53
{
54
struct sockaddr_storage addrs[2];
55
56
/*
57
* Sysctl accepts an array of two sockaddr's, the first being the
58
* 'foreign' sockaddr, the second being the 'local' sockaddr.
59
*/
60
61
bcopy(sin_remote, &addrs[0], sizeof(*sin_remote));
62
bcopy(sin_local, &addrs[1], sizeof(*sin_local));
63
64
return (sysctlbyname("net.inet.tcp.drop", NULL, 0, addrs,
65
sizeof(addrs)));
66
}
67
68
static void
69
tcp_server(pid_t partner, int listen_fd)
70
{
71
int error, accept_fd;
72
ssize_t len;
73
char ch;
74
75
accept_fd = accept(listen_fd, NULL, NULL);
76
if (accept_fd < 0) {
77
error = errno;
78
(void)kill(partner, SIGTERM);
79
errno = error;
80
err(-1, "tcp_server: accept");
81
}
82
83
/*
84
* Send one byte, make sure that worked, wait for the drop, and try
85
* sending another. By sending small amounts, we avoid blocking
86
* waiting on the remote buffer to be drained.
87
*/
88
ch = 'A';
89
len = send(accept_fd, &ch, sizeof(ch), MSG_NOSIGNAL);
90
if (len < 0) {
91
error = errno;
92
(void)kill(partner, SIGTERM);
93
errno = error;
94
err(-1, "tcp_server: send (1)");
95
}
96
if (len != sizeof(ch)) {
97
(void)kill(partner, SIGTERM);
98
errx(-1, "tcp_server: send (1) len");
99
}
100
101
sleep (10);
102
103
ch = 'A';
104
len = send(accept_fd, &ch, sizeof(ch), MSG_NOSIGNAL);
105
if (len >= 0) {
106
(void)kill(partner, SIGTERM);
107
errx(-1, "tcp_server: send (2): success");
108
} else if (errno != EPIPE) {
109
error = errno;
110
(void)kill(partner, SIGTERM);
111
errno = error;
112
err(-1, "tcp_server: send (2)");
113
}
114
115
close(accept_fd);
116
close(listen_fd);
117
}
118
119
static void
120
tcp_client(pid_t partner, u_short port)
121
{
122
struct sockaddr_in sin, sin_local;
123
int error, sock;
124
socklen_t slen;
125
ssize_t len;
126
char ch;
127
128
sleep(1);
129
130
sock = socket(PF_INET, SOCK_STREAM, 0);
131
if (sock < 0) {
132
error = errno;
133
(void)kill(partner, SIGTERM);
134
errno = error;
135
err(-1, "socket");
136
}
137
138
bzero(&sin, sizeof(sin));
139
sin.sin_family = AF_INET;
140
sin.sin_len = sizeof(sin);
141
sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
142
sin.sin_port = port;
143
144
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
145
error = errno;
146
(void)kill(partner, SIGTERM);
147
errno = error;
148
err(-1, "connect");
149
}
150
151
slen = sizeof(sin_local);
152
if (getsockname(sock, (struct sockaddr *)&sin_local, &slen) < 0) {
153
error = errno;
154
(void)kill(partner, SIGTERM);
155
errno = error;
156
err(-1, "getsockname");
157
}
158
159
/*
160
* Send one byte, make sure that worked, wait for the drop, and try
161
* sending another. By sending small amounts, we avoid blocking
162
* waiting on the remote buffer to be drained.
163
*/
164
ch = 'A';
165
len = send(sock, &ch, sizeof(ch), MSG_NOSIGNAL);
166
if (len < 0) {
167
error = errno;
168
(void)kill(partner, SIGTERM);
169
errno = error;
170
err(-1, "tcp_client: send (1)");
171
}
172
if (len != sizeof(ch)) {
173
(void)kill(partner, SIGTERM);
174
errx(-1, "tcp_client: send (1) len");
175
}
176
177
sleep(5);
178
if (tcp_drop(&sin_local, &sin) < 0) {
179
error = errno;
180
(void)kill(partner, SIGTERM);
181
errno = error;
182
err(-1, "tcp_client: tcp_drop");
183
}
184
sleep(5);
185
186
ch = 'A';
187
len = send(sock, &ch, sizeof(ch), MSG_NOSIGNAL);
188
if (len >= 0) {
189
(void)kill(partner, SIGTERM);
190
errx(-1, "tcp_client: send (2): success");
191
} else if (errno != EPIPE) {
192
error = errno;
193
(void)kill(partner, SIGTERM);
194
errno = error;
195
err(-1, "tcp_client: send (2)");
196
}
197
close(sock);
198
}
199
200
int
201
main(int argc, char *argv[])
202
{
203
pid_t child_pid, parent_pid;
204
struct sockaddr_in sin;
205
int listen_fd;
206
u_short port;
207
socklen_t len;
208
209
listen_fd = socket(PF_INET, SOCK_STREAM, 0);
210
if (listen_fd < 0)
211
err(-1, "socket");
212
213
/*
214
* We use the loopback, but let the kernel select a port for the
215
* server socket.
216
*/
217
bzero(&sin, sizeof(sin));
218
sin.sin_family = AF_INET;
219
sin.sin_len = sizeof(sin);
220
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
221
222
if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
223
err(-1, "bind");
224
225
if (listen(listen_fd, -1) < 0)
226
err(-1, "listen");
227
228
/*
229
* Query the port so that the client can use it.
230
*/
231
bzero(&sin, sizeof(sin));
232
sin.sin_family = AF_INET;
233
sin.sin_len = sizeof(sin);
234
len = sizeof(sin);
235
if (getsockname(listen_fd, (struct sockaddr *)&sin, &len) < 0)
236
err(-1, "getsockname");
237
port = sin.sin_port;
238
printf("Using port %d\n", ntohs(port));
239
240
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
241
err(-1, "signal");
242
243
parent_pid = getpid();
244
child_pid = fork();
245
if (child_pid < 0)
246
err(-1, "fork");
247
if (child_pid == 0) {
248
child_pid = getpid();
249
tcp_server(parent_pid, listen_fd);
250
} else
251
tcp_client(child_pid, port);
252
253
return (0);
254
}
255
256