2 * Copyright (c) 2009 Robert N. M. Watson
5 * This software was developed at the University of Cambridge Computer
6 * Laboratory with support from a grant from Google, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/socket.h>
45 #define min(x, y) (x < y ? x : y)
49 #define SEQPACKET_RCVBUF (131072-16)
50 #define SEQPACKET_SNDBUF (131072-16)
52 #define FAILERR(str) err(-1, "%s: %s", __func__, str)
53 #define FAILNERR(str, n) err(-1, "%s %d: %s", __func__, n, str)
54 #define FAILNMERR(str, n, m) err(-1, "%s %d %d: %s", __func__, n, m, str)
55 #define FAILERRX(str) errx(-1, "%s: %s", __func__, str)
56 #define FAILNERRX(str, n) errx(-1, "%s %d: %s", __func__, n, str)
57 #define FAILNMERRX(str, n, m) errx(-1, "%s %d %d: %s", __func__, n, m, str)
61 #define ANN() (ann ? warnx("%s: start", __func__) : 0)
62 #define ANNN(n) (ann ? warnx("%s %d: start", __func__, (n)) : 0)
63 #define ANNNM(n, m) (ann ? warnx("%s %d %d: start", __func__, (n), (m)) : 0)
65 #define OK() warnx("%s: ok", __func__)
66 #define OKN(n) warnx("%s %d: ok", __func__, (n))
67 #define OKNM(n, m) warnx("%s %d %d: ok", __func__, (n), (m))
70 #define NEW_SOCKET(s) do { \
73 (s) = socket(PF_LOCAL, SOCK_SEQPACKET, 0); \
78 if (setsockopt((s), SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0) \
79 FAILERR("setsockopt SO_NOSIGPIPE"); \
81 i = SEQPACKET_RCVBUF; \
82 if (setsockopt((s), SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) \
83 FAILERR("setsockopt SO_RCVBUF"); \
85 i = SEQPACKET_SNDBUF; \
86 if (setsockopt((s), SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) \
87 FAILERR("setsockopt SO_SNDBUF"); \
90 #define NEW_SOCKET(s) do { \
93 (s) = socket(PF_LOCAL, SOCK_SEQPACKET, 0); \
97 i = SEQPACKET_RCVBUF; \
98 if (setsockopt((s), SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) \
99 FAILERR("setsockopt SO_RCVBUF"); \
101 i = SEQPACKET_SNDBUF; \
102 if (setsockopt((s), SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) \
103 FAILERR("setsockopt SO_SNDBUF"); \
111 ssize_t ssize_recv, ssize_send;
116 s_accept = accept(s_listen, NULL, 0);
118 i = SEQPACKET_RCVBUF;
119 if (setsockopt(s_accept, SOL_SOCKET, SO_RCVBUF, &i,
121 warn("server: setsockopt SO_RCVBUF");
126 if (getsockopt(s_accept, SOL_SOCKET, SO_RCVBUF, &i,
128 warn("server: getsockopt SO_RCVBUF");
132 if (i != SEQPACKET_RCVBUF) {
133 warnx("server: getsockopt SO_RCVBUF wrong %d",
140 if (getsockopt(s_accept, SOL_SOCKET, SO_SNDBUF, &i,
142 warn("server: getsockopt SO_SNDBUF");
146 if (i != SEQPACKET_SNDBUF) {
147 warnx("server: getsockopt SO_SNDBUF wrong %d",
154 ssize_recv = recv(s_accept, buffer,
158 if (ssize_recv < 0) {
159 warn("server: recv");
162 ssize_send = send(s_accept, buffer,
166 if (ssize_send < 0) {
167 warn("server: send");
170 if (ssize_send != ssize_recv)
171 warnx("server: recv %d sent %d",
172 ssize_recv, ssize_send);
176 warn("server: accept");
181 test_connect(struct sockaddr_un *sun)
187 if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0)
194 test_connect_send(struct sockaddr_un *sun)
202 if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0)
204 ssize = send(s, &ch, sizeof(ch), 0);
207 if (ssize != sizeof(ch))
208 FAILERRX("send wrong size");
214 test_connect_shutdown_send(struct sockaddr_un *sun)
222 if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0)
224 if (shutdown(s, SHUT_RDWR) < 0)
225 FAILERR("shutdown SHUT_RDWR");
226 ssize = send(s, &ch, sizeof(ch), 0);
230 FAILERR("send unexpected error");
236 test_connect_send_recv(struct sockaddr_un *sun, size_t size)
238 char buf[size + 4]; /* Detect extra bytes. */
245 if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0)
246 FAILNERR("connect", size);
247 ssize = send(s, buf, size, 0);
248 if (ssize < 0 && size >= SEQPACKET_RCVBUF)
251 FAILNERR("send", size);
253 FAILNERR("send eof", size);
255 FAILNERRX("send size", size);
257 truncsize = min(size, BUFLEN);
258 ssize = recv(s, buf, sizeof(buf), 0);
260 FAILNERR("recv", size);
262 FAILNERRX("recv eof", size);
263 if (ssize < truncsize)
264 FAILNERRX("recv too few bytes", size);
265 if (ssize > truncsize)
266 FAILNERRX("recv too many bytes", size);
273 test_connect_send_recv_count(struct sockaddr_un *sun, int count, size_t size)
275 char buf[size + 4]; /* Detect extra bytes and coalescing. */
282 if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0)
283 FAILNMERR("connect", size, count);
284 for (i = 0; i < count; i++) {
286 ssize = send(s, buf, size, 0);
287 if (ssize < 0 && size >= SEQPACKET_RCVBUF)
290 FAILNMERR("send", size, count);
292 FAILNMERRX("send eof", size, count);
294 FAILNMERRX("send size", size, count);
297 truncsize = min(size, BUFLEN);
298 for (i = 0; i < count; i++) {
299 ssize = recv(s, buf, sizeof(buf), 0);
301 FAILNMERR("recv", size, count);
303 FAILNMERRX("recv eof", size, count);
304 if (ssize < truncsize)
305 FAILNMERRX("recv too few bytes", size, count);
306 if (ssize > truncsize)
307 FAILNMERRX("recv too many bytes", size, count);
315 test_sendto(struct sockaddr_un *sun)
323 ssize = sendto(s, &ch, sizeof(ch), 0, (struct sockaddr *)sun,
332 client(struct sockaddr_un *sun)
334 size_t sizes[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
335 4096, 8192, 16384, 32768, 65536 /*, 131072 */};
339 test_connect_send(sun);
340 test_connect_shutdown_send(sun);
343 * Try a range of sizes and packet counts.
345 for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++)
346 test_connect_send_recv(sun, sizes[i]);
347 for (c = 1; c <= 8; c++) {
348 for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++)
349 test_connect_send_recv_count(sun, c, sizes[i]);
352 printf("client done\n");
356 main(int argc, char *argv[])
358 struct sockaddr_un sun;
360 pid_t pid_client, pid_server;
363 snprintf(path, sizeof(path), "/tmp/lds_exercise.XXXXXXXXX");
364 if (mktemp(path) == NULL)
367 s_listen = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
373 i = SEQPACKET_RCVBUF;
374 if (setsockopt(s_listen, SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) {
376 FAILERR("setsockopt SO_RCVBUF");
379 i = SEQPACKET_SNDBUF;
380 if (setsockopt(s_listen, SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) {
382 FAILERR("setsockopt SO_SNDBUF");
386 if (setsockopt(s_listen, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i))
389 FAILERR("setsockopt SO_NOSIGPIPE");
392 bzero(&sun, sizeof(sun));
393 sun.sun_len = sizeof(sun);
394 sun.sun_family = AF_LOCAL;
395 strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
397 if (bind(s_listen, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
402 if (listen(s_listen, -1) < 0) {
408 if (pid_server < 0) {
412 if (pid_server == 0) {
418 if (pid_client < 0) {
419 (void)kill(pid_server, SIGKILL);
423 if (pid_client == 0) {
429 * When the client is done, kill the server and clean up.
431 (void)waitpid(pid_client, NULL, 0);
432 (void)kill(pid_server, SIGKILL);