zerosend.c revision 165982
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 * $FreeBSD: head/tools/regression/sockets/zerosend/zerosend.c 165982 2007-01-12 21:49:36Z rwatson $
27 */
28
29#include <sys/socket.h>
30#include <sys/stat.h>
31
32#include <netinet/in.h>
33
34#include <arpa/inet.h>
35
36#include <err.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
46static void
47try_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 %d", test, len);
58}
59
60static void
61try_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 %d", test, len);
72}
73
74static void
75setup_udp(const char *test, int *fdp)
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: bind(%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: bind(%s, %d)", test,
106		    inet_ntoa(sin.sin_addr), PORT1);
107
108	fdp[0] = sock1;
109	fdp[1] = sock2;
110}
111
112static void
113setup_tcp(const char *test, int *fdp)
114{
115	struct sockaddr_in sin;
116	int sock1, sock2, sock3;
117
118	bzero(&sin, sizeof(sin));
119	sin.sin_len = sizeof(sin);
120	sin.sin_family = AF_INET;
121	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
122
123	/*
124	 * First set up the listen socket.
125	 */
126	sin.sin_port = htons(PORT1);
127	sock1 = socket(PF_INET, SOCK_STREAM, 0);
128	if (sock1 < 0)
129		err(-1, "%s: setup_tcp: socket", test);
130	if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)
131		err(-1, "%s: bind(%s, %d)", test, inet_ntoa(sin.sin_addr),
132		    PORT1);
133	if (listen(sock1, -1) < 0)
134		err(-1, "%s: listen", test);
135
136	/*
137	 * Now connect to it, non-blocking so that we don't deadlock against
138	 * ourselves.
139	 */
140	sock2 = socket(PF_INET, SOCK_STREAM, 0);
141	if (sock2 < 0)
142		err(-1, "%s: setup_tcp: socket", test);
143	if (fcntl(sock2, F_SETFL, O_NONBLOCK) < 0)
144		err(-1, "%s: setup_tcp: fcntl(O_NONBLOCK)", test);
145	if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0)
146		err(-1, "%s: setup_tcp: connect(%s, %d)", test,
147		    inet_ntoa(sin.sin_addr), PORT1);
148
149	/*
150	 * Now pick up the connection after sleeping a moment to make sure
151	 * there's been time for some packets to go back and forth.
152	 */
153	if (sleep(1) < 0)
154		err(-1, "%s: sleep(1)", test);
155	sock3 = accept(sock1, NULL, NULL);
156	if (sock3 < 0)
157		err(-1, "%s: accept", test);
158	if (sleep(1) < 0)
159		err(-1, "%s: sleep(1)", test);
160
161	close(sock1);
162	fdp[0] = sock2;
163	fdp[1] = sock3;
164}
165
166static void
167setup_udsstream(const char *test, int *fdp)
168{
169
170	if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fdp) < 0)
171		err(-1, "%s: setup_udsstream: socketpair", test);
172}
173
174static void
175setup_udsdgram(const char *test, int *fdp)
176{
177
178	if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fdp) < 0)
179		err(-1, "%s: setup_udsdgram: socketpair", test);
180}
181
182static void
183setup_pipe(const char *test, int *fdp)
184{
185
186	if (pipe(fdp) < 0)
187		err(-1, "%s: setup_pipe: pipe", test);
188}
189
190static void
191setup_fifo(const char *test, int *fdp)
192{
193	char path[PATH_MAX];
194	int fd1, fd2;
195
196	strcpy(path, "/tmp/0send_fifo.XXXXXXX");
197	if (mktemp(path) == NULL)
198		err(-1, "%s: setup_fifo: mktemp", test);
199
200	if (mkfifo(path, 0600) < 0)
201		err(-1, "%s: setup_fifo: mkfifo(%s)", test, path);
202
203	fd1 = open(path, O_RDONLY | O_NONBLOCK);
204	if (fd1 < 0)
205		err(-1, "%s: setup_fifo: open(%s, O_RDONLY)", test, path);
206
207	fd2 = open(path, O_WRONLY | O_NONBLOCK);
208	if (fd2 < 0)
209		err(-1, "%s: setup_fifo: open(%s, O_WRONLY)", test, path);
210
211	fdp[0] = fd2;
212	fdp[1] = fd1;
213}
214
215static void
216close_both(int *fdp)
217{
218
219	close(fdp[0]);
220	fdp[0] = -1;
221	close(fdp[1]);
222	fdp[1] = -1;
223}
224
225int
226main(int argc, char *argv[])
227{
228	int fd[2];
229
230	setup_udp("udp_0send", fd);
231	try_0send("udp_0send", fd[0]);
232	close_both(fd);
233
234	setup_udp("udp_0write", fd);
235	try_0write("udp_0write", fd[0]);
236	close_both(fd);
237
238	setup_tcp("tcp_0send", fd);
239	try_0send("tcp_0send", fd[0]);
240	close_both(fd);
241
242	setup_tcp("tcp_0write", fd);
243	try_0write("tcp_0write", fd[0]);
244	close_both(fd);
245
246	setup_udsstream("udsstream_0send", fd);
247	try_0send("udsstream_0send", fd[0]);
248	close_both(fd);
249
250	setup_udsstream("udsstream_0write", fd);
251	try_0write("udsstream_0write", fd[0]);
252	close_both(fd);
253
254	setup_udsdgram("udsdgram_0send", fd);
255	try_0send("udsdgram_0send", fd[0]);
256	close_both(fd);
257
258	setup_udsdgram("udsdgram_0write", fd);
259	try_0write("udsdgram_0write", fd[0]);
260	close_both(fd);
261
262	setup_pipe("pipe_0write", fd);
263	try_0write("pipd_0write", fd[0]);
264	close_both(fd);
265
266	setup_fifo("fifo_0write", fd);
267	try_0write("fifo_0write", fd[0]);
268	close_both(fd);
269
270	return (0);
271}
272