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