1197781Srwatson/*- 2197781Srwatson * Copyright (c) 2009 Robert N. M. Watson 3197781Srwatson * All rights reserved. 4197781Srwatson * 5197781Srwatson * This software was developed at the University of Cambridge Computer 6197781Srwatson * Laboratory with support from a grant from Google, Inc. 7197781Srwatson * 8197781Srwatson * Redistribution and use in source and binary forms, with or without 9197781Srwatson * modification, are permitted provided that the following conditions 10197781Srwatson * are met: 11197781Srwatson * 1. Redistributions of source code must retain the above copyright 12197781Srwatson * notice, this list of conditions and the following disclaimer. 13197781Srwatson * 2. Redistributions in binary form must reproduce the above copyright 14197781Srwatson * notice, this list of conditions and the following disclaimer in the 15197781Srwatson * documentation and/or other materials provided with the distribution. 16197781Srwatson * 17197781Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18197781Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19197781Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20197781Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21197781Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22197781Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23197781Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24197781Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25197781Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26197781Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27197781Srwatson * SUCH DAMAGE. 28197781Srwatson */ 29197781Srwatson 30197781Srwatson#include <sys/cdefs.h> 31197781Srwatson__FBSDID("$FreeBSD$"); 32197781Srwatson 33197781Srwatson#include <sys/socket.h> 34197781Srwatson#include <sys/wait.h> 35197781Srwatson#include <sys/un.h> 36197781Srwatson 37197781Srwatson#include <err.h> 38197781Srwatson#include <errno.h> 39197781Srwatson#include <limits.h> 40197781Srwatson#include <stdio.h> 41197781Srwatson#include <signal.h> 42197781Srwatson#include <string.h> 43197781Srwatson#include <unistd.h> 44197781Srwatson 45197781Srwatson#define min(x, y) (x < y ? x : y) 46197781Srwatson 47197781Srwatson#define BUFLEN 32768 48197781Srwatson 49197781Srwatson#define SEQPACKET_RCVBUF (131072-16) 50197781Srwatson#define SEQPACKET_SNDBUF (131072-16) 51197781Srwatson 52197781Srwatson#define FAILERR(str) err(-1, "%s: %s", __func__, str) 53197781Srwatson#define FAILNERR(str, n) err(-1, "%s %d: %s", __func__, n, str) 54197781Srwatson#define FAILNMERR(str, n, m) err(-1, "%s %d %d: %s", __func__, n, m, str) 55197781Srwatson#define FAILERRX(str) errx(-1, "%s: %s", __func__, str) 56197781Srwatson#define FAILNERRX(str, n) errx(-1, "%s %d: %s", __func__, n, str) 57197781Srwatson#define FAILNMERRX(str, n, m) errx(-1, "%s %d %d: %s", __func__, n, m, str) 58197781Srwatson 59197781Srwatsonstatic int ann = 0; 60197781Srwatson 61197781Srwatson#define ANN() (ann ? warnx("%s: start", __func__) : 0) 62197781Srwatson#define ANNN(n) (ann ? warnx("%s %d: start", __func__, (n)) : 0) 63197781Srwatson#define ANNNM(n, m) (ann ? warnx("%s %d %d: start", __func__, (n), (m)) : 0) 64197781Srwatson 65197781Srwatson#define OK() warnx("%s: ok", __func__) 66197781Srwatson#define OKN(n) warnx("%s %d: ok", __func__, (n)) 67197781Srwatson#define OKNM(n, m) warnx("%s %d %d: ok", __func__, (n), (m)) 68197781Srwatson 69197781Srwatson#ifdef SO_NOSIGPIPE 70197781Srwatson#define NEW_SOCKET(s) do { \ 71197781Srwatson int i; \ 72197781Srwatson \ 73197781Srwatson (s) = socket(PF_LOCAL, SOCK_SEQPACKET, 0); \ 74197781Srwatson if ((s) < 0) \ 75197781Srwatson FAILERR("socket"); \ 76197781Srwatson \ 77197781Srwatson i = 1; \ 78197781Srwatson if (setsockopt((s), SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0) \ 79197781Srwatson FAILERR("setsockopt SO_NOSIGPIPE"); \ 80197781Srwatson \ 81197781Srwatson i = SEQPACKET_RCVBUF; \ 82197781Srwatson if (setsockopt((s), SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) \ 83197781Srwatson FAILERR("setsockopt SO_RCVBUF"); \ 84197781Srwatson \ 85197781Srwatson i = SEQPACKET_SNDBUF; \ 86197781Srwatson if (setsockopt((s), SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) \ 87197781Srwatson FAILERR("setsockopt SO_SNDBUF"); \ 88197781Srwatson} while (0) 89197781Srwatson#else 90197781Srwatson#define NEW_SOCKET(s) do { \ 91197781Srwatson int i; \ 92197781Srwatson \ 93197781Srwatson (s) = socket(PF_LOCAL, SOCK_SEQPACKET, 0); \ 94197781Srwatson if ((s) < 0) \ 95197781Srwatson FAILERR("socket"); \ 96197781Srwatson \ 97197781Srwatson i = SEQPACKET_RCVBUF; \ 98197781Srwatson if (setsockopt((s), SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) \ 99197781Srwatson FAILERR("setsockopt SO_RCVBUF"); \ 100197781Srwatson \ 101197781Srwatson i = SEQPACKET_SNDBUF; \ 102197781Srwatson if (setsockopt((s), SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) \ 103197781Srwatson FAILERR("setsockopt SO_SNDBUF"); \ 104197781Srwatson} while (0) 105197781Srwatson#endif 106197781Srwatson 107197781Srwatsonstatic void 108197781Srwatsonserver(int s_listen) 109197781Srwatson{ 110197781Srwatson char buffer[BUFLEN]; 111197781Srwatson ssize_t ssize_recv, ssize_send; 112197781Srwatson socklen_t socklen; 113197781Srwatson int i, s_accept; 114197781Srwatson 115197781Srwatson while (1) { 116197781Srwatson s_accept = accept(s_listen, NULL, 0); 117197781Srwatson if (s_accept >= 0) { 118197781Srwatson i = SEQPACKET_RCVBUF; 119197781Srwatson if (setsockopt(s_accept, SOL_SOCKET, SO_RCVBUF, &i, 120197781Srwatson sizeof(i)) < 0) { 121197781Srwatson warn("server: setsockopt SO_RCVBUF"); 122197781Srwatson close(s_accept); 123197781Srwatson continue; 124197781Srwatson } 125197781Srwatson 126197781Srwatson if (getsockopt(s_accept, SOL_SOCKET, SO_RCVBUF, &i, 127197781Srwatson &socklen) < 0) { 128197781Srwatson warn("server: getsockopt SO_RCVBUF"); 129197781Srwatson close(s_accept); 130197781Srwatson continue; 131197781Srwatson } 132197781Srwatson if (i != SEQPACKET_RCVBUF) { 133197781Srwatson warnx("server: getsockopt SO_RCVBUF wrong %d", 134197781Srwatson i); 135197781Srwatson close(s_accept); 136197781Srwatson continue; 137197781Srwatson } 138197781Srwatson 139197781Srwatson socklen = sizeof(i); 140197781Srwatson if (getsockopt(s_accept, SOL_SOCKET, SO_SNDBUF, &i, 141197781Srwatson &socklen) < 0) { 142197781Srwatson warn("server: getsockopt SO_SNDBUF"); 143197781Srwatson close(s_accept); 144197781Srwatson continue; 145197781Srwatson } 146197781Srwatson if (i != SEQPACKET_SNDBUF) { 147197781Srwatson warnx("server: getsockopt SO_SNDBUF wrong %d", 148197781Srwatson i); 149197781Srwatson close(s_accept); 150197781Srwatson continue; 151197781Srwatson } 152197781Srwatson 153197781Srwatson do { 154197781Srwatson ssize_recv = recv(s_accept, buffer, 155197781Srwatson sizeof(buffer), 0); 156197781Srwatson if (ssize_recv == 0) 157197781Srwatson break; 158197781Srwatson if (ssize_recv < 0) { 159197781Srwatson warn("server: recv"); 160197781Srwatson break; 161197781Srwatson } 162197781Srwatson ssize_send = send(s_accept, buffer, 163197781Srwatson ssize_recv, 0); 164197781Srwatson if (ssize_send == 0) 165197781Srwatson break; 166197781Srwatson if (ssize_send < 0) { 167197781Srwatson warn("server: send"); 168197781Srwatson break; 169197781Srwatson } 170197781Srwatson if (ssize_send != ssize_recv) 171197781Srwatson warnx("server: recv %d sent %d", 172197781Srwatson ssize_recv, ssize_send); 173197781Srwatson } while (1); 174197781Srwatson close(s_accept); 175197781Srwatson } else 176197781Srwatson warn("server: accept"); 177197781Srwatson } 178197781Srwatson} 179197781Srwatson 180197781Srwatsonstatic void 181197781Srwatsontest_connect(struct sockaddr_un *sun) 182197781Srwatson{ 183197781Srwatson int s; 184197781Srwatson 185197781Srwatson ANN(); 186197781Srwatson NEW_SOCKET(s); 187197781Srwatson if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) 188197781Srwatson FAILERR("connect"); 189197781Srwatson (void)close(s); 190197781Srwatson OK(); 191197781Srwatson} 192197781Srwatson 193197781Srwatsonstatic void 194197781Srwatsontest_connect_send(struct sockaddr_un *sun) 195197781Srwatson{ 196197781Srwatson ssize_t ssize; 197197781Srwatson char ch; 198197781Srwatson int s; 199197781Srwatson 200197781Srwatson ANN(); 201197781Srwatson NEW_SOCKET(s); 202197781Srwatson if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) 203197781Srwatson FAILERR("connect"); 204197781Srwatson ssize = send(s, &ch, sizeof(ch), 0); 205197781Srwatson if (ssize < 0) 206197781Srwatson FAILERR("send"); 207197781Srwatson if (ssize != sizeof(ch)) 208197781Srwatson FAILERRX("send wrong size"); 209197781Srwatson (void)close(s); 210197781Srwatson OK(); 211197781Srwatson} 212197781Srwatson 213197781Srwatsonstatic void 214197781Srwatsontest_connect_shutdown_send(struct sockaddr_un *sun) 215197781Srwatson{ 216197781Srwatson ssize_t ssize; 217197781Srwatson char ch; 218197781Srwatson int s; 219197781Srwatson 220197781Srwatson ANN(); 221197781Srwatson NEW_SOCKET(s); 222197781Srwatson if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) 223197781Srwatson FAILERR("connect"); 224197781Srwatson if (shutdown(s, SHUT_RDWR) < 0) 225197781Srwatson FAILERR("shutdown SHUT_RDWR"); 226197781Srwatson ssize = send(s, &ch, sizeof(ch), 0); 227197781Srwatson if (ssize >= 0) 228197781Srwatson FAILERRX("send"); 229197781Srwatson if (errno != EPIPE) 230197781Srwatson FAILERR("send unexpected error"); 231197781Srwatson (void)close(s); 232197781Srwatson OK(); 233197781Srwatson} 234197781Srwatson 235197781Srwatsonstatic void 236197781Srwatsontest_connect_send_recv(struct sockaddr_un *sun, size_t size) 237197781Srwatson{ 238197781Srwatson char buf[size + 4]; /* Detect extra bytes. */ 239197781Srwatson size_t truncsize; 240197781Srwatson ssize_t ssize; 241197781Srwatson int s; 242197781Srwatson 243197781Srwatson ANNN(size); 244197781Srwatson NEW_SOCKET(s); 245197781Srwatson if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) 246197781Srwatson FAILNERR("connect", size); 247197781Srwatson ssize = send(s, buf, size, 0); 248197781Srwatson if (ssize < 0 && size >= SEQPACKET_RCVBUF) 249197781Srwatson goto out; 250197781Srwatson if (ssize < 0) 251197781Srwatson FAILNERR("send", size); 252197781Srwatson if (ssize == 0) 253197781Srwatson FAILNERR("send eof", size); 254197781Srwatson if (ssize != size) 255197781Srwatson FAILNERRX("send size", size); 256197781Srwatson 257197781Srwatson truncsize = min(size, BUFLEN); 258197781Srwatson ssize = recv(s, buf, sizeof(buf), 0); 259197781Srwatson if (ssize < 0) 260197781Srwatson FAILNERR("recv", size); 261197781Srwatson if (ssize == 0) 262197781Srwatson FAILNERRX("recv eof", size); 263197781Srwatson if (ssize < truncsize) 264197781Srwatson FAILNERRX("recv too few bytes", size); 265197781Srwatson if (ssize > truncsize) 266197781Srwatson FAILNERRX("recv too many bytes", size); 267197781Srwatsonout: 268197781Srwatson (void)close(s); 269197781Srwatson OKN(size); 270197781Srwatson} 271197781Srwatson 272197781Srwatsonstatic void 273197781Srwatsontest_connect_send_recv_count(struct sockaddr_un *sun, int count, size_t size) 274197781Srwatson{ 275197781Srwatson char buf[size + 4]; /* Detect extra bytes and coalescing. */ 276197781Srwatson size_t truncsize; 277197781Srwatson ssize_t ssize; 278197781Srwatson int i, s; 279197781Srwatson 280197781Srwatson ANNNM(size, count); 281197781Srwatson NEW_SOCKET(s); 282197781Srwatson if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) 283197781Srwatson FAILNMERR("connect", size, count); 284197781Srwatson for (i = 0; i < count; i++) { 285197781Srwatson usleep(5000); 286197781Srwatson ssize = send(s, buf, size, 0); 287197781Srwatson if (ssize < 0 && size >= SEQPACKET_RCVBUF) 288197781Srwatson goto out; 289197781Srwatson if (ssize < 0) 290197781Srwatson FAILNMERR("send", size, count); 291197781Srwatson if (ssize == 0) 292197781Srwatson FAILNMERRX("send eof", size, count); 293197781Srwatson if (ssize != size) 294197781Srwatson FAILNMERRX("send size", size, count); 295197781Srwatson } 296197781Srwatson 297197781Srwatson truncsize = min(size, BUFLEN); 298197781Srwatson for (i = 0; i < count; i++) { 299197781Srwatson ssize = recv(s, buf, sizeof(buf), 0); 300197781Srwatson if (ssize < 0) 301197781Srwatson FAILNMERR("recv", size, count); 302197781Srwatson if (ssize == 0) 303197781Srwatson FAILNMERRX("recv eof", size, count); 304197781Srwatson if (ssize < truncsize) 305197781Srwatson FAILNMERRX("recv too few bytes", size, count); 306197781Srwatson if (ssize > truncsize) 307197781Srwatson FAILNMERRX("recv too many bytes", size, count); 308197781Srwatson } 309197781Srwatsonout: 310197781Srwatson (void)close(s); 311197781Srwatson OKNM(size, count); 312197781Srwatson} 313197781Srwatson 314197781Srwatsonstatic void 315197781Srwatsontest_sendto(struct sockaddr_un *sun) 316197781Srwatson{ 317197781Srwatson ssize_t ssize; 318197781Srwatson char ch; 319197781Srwatson int s; 320197781Srwatson 321197781Srwatson ANN(); 322197781Srwatson NEW_SOCKET(s); 323197781Srwatson ssize = sendto(s, &ch, sizeof(ch), 0, (struct sockaddr *)sun, 324197781Srwatson sizeof(*sun)); 325197781Srwatson if (ssize < 0) 326197781Srwatson FAILERR("sendto"); 327197781Srwatson (void)close(s); 328197781Srwatson OK(); 329197781Srwatson} 330197781Srwatson 331197781Srwatsonstatic void 332197781Srwatsonclient(struct sockaddr_un *sun) 333197781Srwatson{ 334197781Srwatson size_t sizes[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 335197781Srwatson 4096, 8192, 16384, 32768, 65536 /*, 131072 */}; 336197781Srwatson int c, i; 337197781Srwatson 338197781Srwatson test_connect(sun); 339197781Srwatson test_connect_send(sun); 340197781Srwatson test_connect_shutdown_send(sun); 341197781Srwatson 342197781Srwatson /* 343197781Srwatson * Try a range of sizes and packet counts. 344197781Srwatson */ 345197781Srwatson for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) 346197781Srwatson test_connect_send_recv(sun, sizes[i]); 347197781Srwatson for (c = 1; c <= 8; c++) { 348197781Srwatson for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) 349197781Srwatson test_connect_send_recv_count(sun, c, sizes[i]); 350197781Srwatson } 351197781Srwatson test_sendto(sun); 352197781Srwatson printf("client done\n"); 353197781Srwatson} 354197781Srwatson 355197781Srwatsonint 356197781Srwatsonmain(int argc, char *argv[]) 357197781Srwatson{ 358197781Srwatson struct sockaddr_un sun; 359197781Srwatson char path[PATH_MAX]; 360197781Srwatson pid_t pid_client, pid_server; 361197781Srwatson int i, s_listen; 362197781Srwatson 363197781Srwatson snprintf(path, sizeof(path), "/tmp/lds_exercise.XXXXXXXXX"); 364197781Srwatson if (mktemp(path) == NULL) 365197781Srwatson FAILERR("mktemp"); 366197781Srwatson 367197781Srwatson s_listen = socket(PF_LOCAL, SOCK_SEQPACKET, 0); 368197781Srwatson if (s_listen < 0) { 369197781Srwatson (void)unlink(path); 370197781Srwatson FAILERR("socket"); 371197781Srwatson } 372197781Srwatson 373197781Srwatson i = SEQPACKET_RCVBUF; 374197781Srwatson if (setsockopt(s_listen, SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) { 375197781Srwatson (void)unlink(path); 376197781Srwatson FAILERR("setsockopt SO_RCVBUF"); 377197781Srwatson } 378197781Srwatson 379197781Srwatson i = SEQPACKET_SNDBUF; 380197781Srwatson if (setsockopt(s_listen, SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) { 381197781Srwatson (void)unlink(path); 382197781Srwatson FAILERR("setsockopt SO_SNDBUF"); 383197781Srwatson } 384197781Srwatson 385197781Srwatson i = 1; 386197781Srwatson if (setsockopt(s_listen, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) 387197781Srwatson < 0) { 388197781Srwatson (void)unlink(path); 389197781Srwatson FAILERR("setsockopt SO_NOSIGPIPE"); 390197781Srwatson } 391197781Srwatson 392197781Srwatson bzero(&sun, sizeof(sun)); 393197781Srwatson sun.sun_len = sizeof(sun); 394197781Srwatson sun.sun_family = AF_LOCAL; 395197781Srwatson strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 396197781Srwatson 397197781Srwatson if (bind(s_listen, (struct sockaddr *)&sun, sizeof(sun)) < 0) { 398197781Srwatson (void)unlink(path); 399197781Srwatson FAILERR("bind"); 400197781Srwatson } 401197781Srwatson 402197781Srwatson if (listen(s_listen, -1) < 0) { 403197781Srwatson (void)unlink(path); 404197781Srwatson FAILERR("listen"); 405197781Srwatson } 406197781Srwatson 407197781Srwatson pid_server = fork(); 408197781Srwatson if (pid_server < 0) { 409197781Srwatson (void)unlink(path); 410197781Srwatson FAILERR("fork"); 411197781Srwatson } 412197781Srwatson if (pid_server == 0) { 413197781Srwatson server(s_listen); 414197781Srwatson return (0); 415197781Srwatson } 416197781Srwatson 417197781Srwatson pid_client = fork(); 418197781Srwatson if (pid_client < 0) { 419197781Srwatson (void)kill(pid_server, SIGKILL); 420197781Srwatson (void)unlink(path); 421197781Srwatson FAILERR("fork"); 422197781Srwatson } 423197781Srwatson if (pid_client == 0) { 424197781Srwatson client(&sun); 425197781Srwatson return (0); 426197781Srwatson } 427197781Srwatson 428197781Srwatson /* 429197781Srwatson * When the client is done, kill the server and clean up. 430197781Srwatson */ 431197781Srwatson (void)waitpid(pid_client, NULL, 0); 432197781Srwatson (void)kill(pid_server, SIGKILL); 433197781Srwatson (void)unlink(path); 434197781Srwatson return (0); 435197781Srwatson} 436