Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/regression/sockets/zerosend/zerosend.c
48249 views
1
/*-
2
* Copyright (c) 2007 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
27
#include <sys/select.h>
28
#include <sys/socket.h>
29
#include <sys/stat.h>
30
31
#include <netinet/in.h>
32
33
#include <arpa/inet.h>
34
35
#include <err.h>
36
#include <errno.h>
37
#include <fcntl.h>
38
#include <limits.h>
39
#include <stdio.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
#define PORT1 10001
44
#define PORT2 10002
45
46
static void
47
try_0send(const char *test, int fd)
48
{
49
ssize_t len;
50
char ch;
51
52
ch = 0;
53
len = send(fd, &ch, 0, 0);
54
if (len < 0)
55
err(1, "%s: try_0send", test);
56
if (len != 0)
57
errx(1, "%s: try_0send: returned %zd", test, len);
58
}
59
60
static void
61
try_0write(const char *test, int fd)
62
{
63
ssize_t len;
64
char ch;
65
66
ch = 0;
67
len = write(fd, &ch, 0);
68
if (len < 0)
69
err(1, "%s: try_0write", test);
70
if (len != 0)
71
errx(1, "%s: try_0write: returned %zd", test, len);
72
}
73
74
static void
75
setup_udp(const char *test, int *fdp, int port1, int port2)
76
{
77
struct sockaddr_in sin;
78
int sock1, sock2;
79
80
bzero(&sin, sizeof(sin));
81
sin.sin_len = sizeof(sin);
82
sin.sin_family = AF_INET;
83
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
84
85
sin.sin_port = htons(port1);
86
sock1 = socket(PF_INET, SOCK_DGRAM, 0);
87
if (sock1 < 0)
88
err(1, "%s: setup_udp: socket", test);
89
if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)
90
err(1, "%s: setup_udp: bind(%s, %d)", test,
91
inet_ntoa(sin.sin_addr), PORT1);
92
sin.sin_port = htons(port2);
93
if (connect(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)
94
err(1, "%s: setup_udp: connect(%s, %d)", test,
95
inet_ntoa(sin.sin_addr), PORT2);
96
97
sock2 = socket(PF_INET, SOCK_DGRAM, 0);
98
if (sock2 < 0)
99
err(1, "%s: setup_udp: socket", test);
100
if (bind(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0)
101
err(1, "%s: setup_udp: bind(%s, %d)", test,
102
inet_ntoa(sin.sin_addr), PORT2);
103
sin.sin_port = htons(port1);
104
if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0)
105
err(1, "%s: setup_udp: connect(%s, %d)", test,
106
inet_ntoa(sin.sin_addr), PORT1);
107
108
fdp[0] = sock1;
109
fdp[1] = sock2;
110
}
111
112
static void
113
setup_tcp(const char *test, int *fdp, int port)
114
{
115
fd_set writefds, exceptfds;
116
struct sockaddr_in sin;
117
int ret, sock1, sock2, sock3;
118
struct timeval tv;
119
120
bzero(&sin, sizeof(sin));
121
sin.sin_len = sizeof(sin);
122
sin.sin_family = AF_INET;
123
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
124
125
/*
126
* First set up the listen socket.
127
*/
128
sin.sin_port = htons(port);
129
sock1 = socket(PF_INET, SOCK_STREAM, 0);
130
if (sock1 < 0)
131
err(1, "%s: setup_tcp: socket", test);
132
if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)
133
err(1, "%s: bind(%s, %d)", test, inet_ntoa(sin.sin_addr),
134
PORT1);
135
if (listen(sock1, -1) < 0)
136
err(1, "%s: listen", test);
137
138
/*
139
* Now connect to it, non-blocking so that we don't deadlock against
140
* ourselves.
141
*/
142
sock2 = socket(PF_INET, SOCK_STREAM, 0);
143
if (sock2 < 0)
144
err(1, "%s: setup_tcp: socket", test);
145
if (fcntl(sock2, F_SETFL, O_NONBLOCK) < 0)
146
err(1, "%s: setup_tcp: fcntl(O_NONBLOCK)", test);
147
if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0 &&
148
errno != EINPROGRESS)
149
err(1, "%s: setup_tcp: connect(%s, %d)", test,
150
inet_ntoa(sin.sin_addr), PORT1);
151
152
/*
153
* Now pick up the connection after sleeping a moment to make sure
154
* there's been time for some packets to go back and forth.
155
*/
156
if (sleep(1) != 0)
157
err(1, "%s: sleep(1)", test);
158
sock3 = accept(sock1, NULL, NULL);
159
if (sock3 < 0)
160
err(1, "%s: accept", test);
161
if (sleep(1) != 0)
162
err(1, "%s: sleep(1)", test);
163
164
FD_ZERO(&writefds);
165
FD_SET(sock2, &writefds);
166
FD_ZERO(&exceptfds);
167
FD_SET(sock2, &exceptfds);
168
tv.tv_sec = 1;
169
tv.tv_usec = 0;
170
ret = select(sock2 + 1, NULL, &writefds, &exceptfds, &tv);
171
if (ret < 0)
172
err(1, "%s: setup_tcp: select", test);
173
if (FD_ISSET(sock2, &exceptfds))
174
errx(1, "%s: setup_tcp: select: exception", test);
175
if (!FD_ISSET(sock2, &writefds))
176
errx(1, "%s: setup_tcp: select: not writable", test);
177
178
close(sock1);
179
fdp[0] = sock2;
180
fdp[1] = sock3;
181
}
182
183
static void
184
setup_udsstream(const char *test, int *fdp)
185
{
186
187
if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fdp) < 0)
188
err(1, "%s: setup_udsstream: socketpair", test);
189
}
190
191
static void
192
setup_udsdgram(const char *test, int *fdp)
193
{
194
195
if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fdp) < 0)
196
err(1, "%s: setup_udsdgram: socketpair", test);
197
}
198
199
static void
200
setup_pipe(const char *test, int *fdp)
201
{
202
203
if (pipe(fdp) < 0)
204
err(1, "%s: setup_pipe: pipe", test);
205
}
206
207
static void
208
setup_fifo(const char *test, int *fdp)
209
{
210
char path[] = "0send_fifo.XXXXXXX";
211
int fd1, fd2;
212
213
if (mkstemp(path) == -1)
214
err(1, "%s: setup_fifo: mktemp", test);
215
unlink(path);
216
217
if (mkfifo(path, 0600) < 0)
218
err(1, "%s: setup_fifo: mkfifo(%s)", test, path);
219
220
fd1 = open(path, O_RDONLY | O_NONBLOCK);
221
if (fd1 < 0)
222
err(1, "%s: setup_fifo: open(%s, O_RDONLY)", test, path);
223
224
fd2 = open(path, O_WRONLY | O_NONBLOCK);
225
if (fd2 < 0)
226
err(1, "%s: setup_fifo: open(%s, O_WRONLY)", test, path);
227
228
fdp[0] = fd2;
229
fdp[1] = fd1;
230
}
231
232
static void
233
close_both(int *fdp)
234
{
235
236
close(fdp[0]);
237
fdp[0] = -1;
238
close(fdp[1]);
239
fdp[1] = -1;
240
}
241
242
int
243
main(void)
244
{
245
int fd[2];
246
247
setup_udp("udp_0send", fd, PORT1, PORT2);
248
try_0send("udp_0send", fd[0]);
249
close_both(fd);
250
251
setup_udp("udp_0write", fd, PORT1 + 10, PORT2 + 10);
252
try_0write("udp_0write", fd[0]);
253
close_both(fd);
254
255
setup_tcp("tcp_0send", fd, PORT1);
256
try_0send("tcp_0send", fd[0]);
257
close_both(fd);
258
259
setup_tcp("tcp_0write", fd, PORT1 + 10);
260
try_0write("tcp_0write", fd[0]);
261
close_both(fd);
262
263
setup_udsstream("udsstream_0send", fd);
264
try_0send("udsstream_0send", fd[0]);
265
close_both(fd);
266
267
setup_udsstream("udsstream_0write", fd);
268
try_0write("udsstream_0write", fd[0]);
269
close_both(fd);
270
271
setup_udsdgram("udsdgram_0send", fd);
272
try_0send("udsdgram_0send", fd[0]);
273
close_both(fd);
274
275
setup_udsdgram("udsdgram_0write", fd);
276
try_0write("udsdgram_0write", fd[0]);
277
close_both(fd);
278
279
setup_pipe("pipe_0write", fd);
280
try_0write("pipd_0write", fd[0]);
281
close_both(fd);
282
283
setup_fifo("fifo_0write", fd);
284
try_0write("fifo_0write", fd[0]);
285
close_both(fd);
286
287
return (0);
288
}
289
290