1165982Srwatson/*- 2165982Srwatson * Copyright (c) 2007 Robert N. M. Watson 3165982Srwatson * All rights reserved. 4165982Srwatson * 5165982Srwatson * Redistribution and use in source and binary forms, with or without 6165982Srwatson * modification, are permitted provided that the following conditions 7165982Srwatson * are met: 8165982Srwatson * 1. Redistributions of source code must retain the above copyright 9165982Srwatson * notice, this list of conditions and the following disclaimer. 10165982Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11165982Srwatson * notice, this list of conditions and the following disclaimer in the 12165982Srwatson * documentation and/or other materials provided with the distribution. 13165982Srwatson * 14165982Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15165982Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16165982Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17165982Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18165982Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19165982Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20165982Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21165982Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22165982Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23165982Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24165982Srwatson * SUCH DAMAGE. 25165982Srwatson * 26165982Srwatson * $FreeBSD$ 27165982Srwatson */ 28165982Srwatson 29165984Srwatson#include <sys/select.h> 30165982Srwatson#include <sys/socket.h> 31165982Srwatson#include <sys/stat.h> 32165982Srwatson 33165982Srwatson#include <netinet/in.h> 34165982Srwatson 35165982Srwatson#include <arpa/inet.h> 36165982Srwatson 37165982Srwatson#include <err.h> 38165984Srwatson#include <errno.h> 39165982Srwatson#include <fcntl.h> 40165982Srwatson#include <limits.h> 41165982Srwatson#include <stdio.h> 42165982Srwatson#include <string.h> 43165982Srwatson#include <unistd.h> 44165982Srwatson 45165982Srwatson#define PORT1 10001 46165982Srwatson#define PORT2 10002 47165982Srwatson 48165982Srwatsonstatic void 49165982Srwatsontry_0send(const char *test, int fd) 50165982Srwatson{ 51165982Srwatson ssize_t len; 52165982Srwatson char ch; 53165982Srwatson 54165982Srwatson ch = 0; 55165982Srwatson len = send(fd, &ch, 0, 0); 56165982Srwatson if (len < 0) 57165982Srwatson err(-1, "%s: try_0send", test); 58165982Srwatson if (len != 0) 59165982Srwatson errx(-1, "%s: try_0send: returned %d", test, len); 60165982Srwatson} 61165982Srwatson 62165982Srwatsonstatic void 63165982Srwatsontry_0write(const char *test, int fd) 64165982Srwatson{ 65165982Srwatson ssize_t len; 66165982Srwatson char ch; 67165982Srwatson 68165982Srwatson ch = 0; 69165982Srwatson len = write(fd, &ch, 0); 70165982Srwatson if (len < 0) 71165982Srwatson err(-1, "%s: try_0write", test); 72165982Srwatson if (len != 0) 73165982Srwatson errx(-1, "%s: try_0write: returned %d", test, len); 74165982Srwatson} 75165982Srwatson 76165982Srwatsonstatic void 77165982Srwatsonsetup_udp(const char *test, int *fdp) 78165982Srwatson{ 79165982Srwatson struct sockaddr_in sin; 80165982Srwatson int sock1, sock2; 81165982Srwatson 82165982Srwatson bzero(&sin, sizeof(sin)); 83165982Srwatson sin.sin_len = sizeof(sin); 84165982Srwatson sin.sin_family = AF_INET; 85165982Srwatson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 86165982Srwatson 87165982Srwatson sin.sin_port = htons(PORT1); 88165982Srwatson sock1 = socket(PF_INET, SOCK_DGRAM, 0); 89165982Srwatson if (sock1 < 0) 90165982Srwatson err(-1, "%s: setup_udp: socket", test); 91165982Srwatson if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) 92165982Srwatson err(-1, "%s: setup_udp: bind(%s, %d)", test, 93165982Srwatson inet_ntoa(sin.sin_addr), PORT1); 94165982Srwatson sin.sin_port = htons(PORT2); 95165982Srwatson if (connect(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) 96165984Srwatson err(-1, "%s: setup_udp: connect(%s, %d)", test, 97165982Srwatson inet_ntoa(sin.sin_addr), PORT2); 98165982Srwatson 99165982Srwatson sock2 = socket(PF_INET, SOCK_DGRAM, 0); 100165982Srwatson if (sock2 < 0) 101165982Srwatson err(-1, "%s: setup_udp: socket", test); 102165982Srwatson if (bind(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0) 103165982Srwatson err(-1, "%s: setup_udp: bind(%s, %d)", test, 104165982Srwatson inet_ntoa(sin.sin_addr), PORT2); 105165982Srwatson sin.sin_port = htons(PORT1); 106165982Srwatson if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0) 107165984Srwatson err(-1, "%s: setup_udp: connect(%s, %d)", test, 108165982Srwatson inet_ntoa(sin.sin_addr), PORT1); 109165982Srwatson 110165982Srwatson fdp[0] = sock1; 111165982Srwatson fdp[1] = sock2; 112165982Srwatson} 113165982Srwatson 114165982Srwatsonstatic void 115165982Srwatsonsetup_tcp(const char *test, int *fdp) 116165982Srwatson{ 117165984Srwatson fd_set writefds, exceptfds; 118165982Srwatson struct sockaddr_in sin; 119165984Srwatson int ret, sock1, sock2, sock3; 120165984Srwatson struct timeval tv; 121165982Srwatson 122165982Srwatson bzero(&sin, sizeof(sin)); 123165982Srwatson sin.sin_len = sizeof(sin); 124165982Srwatson sin.sin_family = AF_INET; 125165982Srwatson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 126165982Srwatson 127165982Srwatson /* 128165982Srwatson * First set up the listen socket. 129165982Srwatson */ 130165982Srwatson sin.sin_port = htons(PORT1); 131165982Srwatson sock1 = socket(PF_INET, SOCK_STREAM, 0); 132165982Srwatson if (sock1 < 0) 133165982Srwatson err(-1, "%s: setup_tcp: socket", test); 134165982Srwatson if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) 135165982Srwatson err(-1, "%s: bind(%s, %d)", test, inet_ntoa(sin.sin_addr), 136165982Srwatson PORT1); 137165982Srwatson if (listen(sock1, -1) < 0) 138165982Srwatson err(-1, "%s: listen", test); 139165982Srwatson 140165982Srwatson /* 141165982Srwatson * Now connect to it, non-blocking so that we don't deadlock against 142165982Srwatson * ourselves. 143165982Srwatson */ 144165982Srwatson sock2 = socket(PF_INET, SOCK_STREAM, 0); 145165982Srwatson if (sock2 < 0) 146165982Srwatson err(-1, "%s: setup_tcp: socket", test); 147165982Srwatson if (fcntl(sock2, F_SETFL, O_NONBLOCK) < 0) 148165982Srwatson err(-1, "%s: setup_tcp: fcntl(O_NONBLOCK)", test); 149165984Srwatson if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0 && 150165984Srwatson errno != EINPROGRESS) 151165982Srwatson err(-1, "%s: setup_tcp: connect(%s, %d)", test, 152165982Srwatson inet_ntoa(sin.sin_addr), PORT1); 153165982Srwatson 154165982Srwatson /* 155165982Srwatson * Now pick up the connection after sleeping a moment to make sure 156165982Srwatson * there's been time for some packets to go back and forth. 157165982Srwatson */ 158165982Srwatson if (sleep(1) < 0) 159165982Srwatson err(-1, "%s: sleep(1)", test); 160165982Srwatson sock3 = accept(sock1, NULL, NULL); 161165982Srwatson if (sock3 < 0) 162165982Srwatson err(-1, "%s: accept", test); 163165982Srwatson if (sleep(1) < 0) 164165982Srwatson err(-1, "%s: sleep(1)", test); 165165982Srwatson 166165984Srwatson FD_ZERO(&writefds); 167165984Srwatson FD_SET(sock2, &writefds); 168165984Srwatson FD_ZERO(&exceptfds); 169165984Srwatson FD_SET(sock2, &exceptfds); 170165984Srwatson tv.tv_sec = 1; 171165984Srwatson tv.tv_usec = 0; 172165984Srwatson ret = select(sock2 + 1, NULL, &writefds, &exceptfds, &tv); 173165984Srwatson if (ret < 0) 174165984Srwatson err(-1, "%s: setup_tcp: select", test); 175165984Srwatson if (FD_ISSET(sock2, &exceptfds)) 176165984Srwatson errx(-1, "%s: setup_tcp: select: exception", test); 177165984Srwatson if (!FD_ISSET(sock2, &writefds)) 178165984Srwatson errx(-1, "%s: setup_tcp: select: not writable", test); 179165984Srwatson 180165982Srwatson close(sock1); 181165982Srwatson fdp[0] = sock2; 182165982Srwatson fdp[1] = sock3; 183165982Srwatson} 184165982Srwatson 185165982Srwatsonstatic void 186165982Srwatsonsetup_udsstream(const char *test, int *fdp) 187165982Srwatson{ 188165982Srwatson 189165982Srwatson if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fdp) < 0) 190165982Srwatson err(-1, "%s: setup_udsstream: socketpair", test); 191165982Srwatson} 192165982Srwatson 193165982Srwatsonstatic void 194165982Srwatsonsetup_udsdgram(const char *test, int *fdp) 195165982Srwatson{ 196165982Srwatson 197165982Srwatson if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fdp) < 0) 198165982Srwatson err(-1, "%s: setup_udsdgram: socketpair", test); 199165982Srwatson} 200165982Srwatson 201165982Srwatsonstatic void 202165982Srwatsonsetup_pipe(const char *test, int *fdp) 203165982Srwatson{ 204165982Srwatson 205165982Srwatson if (pipe(fdp) < 0) 206165982Srwatson err(-1, "%s: setup_pipe: pipe", test); 207165982Srwatson} 208165982Srwatson 209165982Srwatsonstatic void 210165982Srwatsonsetup_fifo(const char *test, int *fdp) 211165982Srwatson{ 212165982Srwatson char path[PATH_MAX]; 213165982Srwatson int fd1, fd2; 214165982Srwatson 215165982Srwatson strcpy(path, "/tmp/0send_fifo.XXXXXXX"); 216165982Srwatson if (mktemp(path) == NULL) 217165982Srwatson err(-1, "%s: setup_fifo: mktemp", test); 218165982Srwatson 219165982Srwatson if (mkfifo(path, 0600) < 0) 220165982Srwatson err(-1, "%s: setup_fifo: mkfifo(%s)", test, path); 221165982Srwatson 222165982Srwatson fd1 = open(path, O_RDONLY | O_NONBLOCK); 223165982Srwatson if (fd1 < 0) 224165982Srwatson err(-1, "%s: setup_fifo: open(%s, O_RDONLY)", test, path); 225165982Srwatson 226165982Srwatson fd2 = open(path, O_WRONLY | O_NONBLOCK); 227165982Srwatson if (fd2 < 0) 228165982Srwatson err(-1, "%s: setup_fifo: open(%s, O_WRONLY)", test, path); 229165982Srwatson 230165982Srwatson fdp[0] = fd2; 231165982Srwatson fdp[1] = fd1; 232165982Srwatson} 233165982Srwatson 234165982Srwatsonstatic void 235165982Srwatsonclose_both(int *fdp) 236165982Srwatson{ 237165982Srwatson 238165982Srwatson close(fdp[0]); 239165982Srwatson fdp[0] = -1; 240165982Srwatson close(fdp[1]); 241165982Srwatson fdp[1] = -1; 242165982Srwatson} 243165982Srwatson 244165982Srwatsonint 245165982Srwatsonmain(int argc, char *argv[]) 246165982Srwatson{ 247165982Srwatson int fd[2]; 248165982Srwatson 249165982Srwatson setup_udp("udp_0send", fd); 250165982Srwatson try_0send("udp_0send", fd[0]); 251165982Srwatson close_both(fd); 252165982Srwatson 253165982Srwatson setup_udp("udp_0write", fd); 254165982Srwatson try_0write("udp_0write", fd[0]); 255165982Srwatson close_both(fd); 256165982Srwatson 257165982Srwatson setup_tcp("tcp_0send", fd); 258165982Srwatson try_0send("tcp_0send", fd[0]); 259165982Srwatson close_both(fd); 260165982Srwatson 261165982Srwatson setup_tcp("tcp_0write", fd); 262165982Srwatson try_0write("tcp_0write", fd[0]); 263165982Srwatson close_both(fd); 264165982Srwatson 265165982Srwatson setup_udsstream("udsstream_0send", fd); 266165982Srwatson try_0send("udsstream_0send", fd[0]); 267165982Srwatson close_both(fd); 268165982Srwatson 269165982Srwatson setup_udsstream("udsstream_0write", fd); 270165982Srwatson try_0write("udsstream_0write", fd[0]); 271165982Srwatson close_both(fd); 272165982Srwatson 273165982Srwatson setup_udsdgram("udsdgram_0send", fd); 274165982Srwatson try_0send("udsdgram_0send", fd[0]); 275165982Srwatson close_both(fd); 276165982Srwatson 277165982Srwatson setup_udsdgram("udsdgram_0write", fd); 278165982Srwatson try_0write("udsdgram_0write", fd[0]); 279165982Srwatson close_both(fd); 280165982Srwatson 281165982Srwatson setup_pipe("pipe_0write", fd); 282165982Srwatson try_0write("pipd_0write", fd[0]); 283165982Srwatson close_both(fd); 284165982Srwatson 285165982Srwatson setup_fifo("fifo_0write", fd); 286165982Srwatson try_0write("fifo_0write", fd[0]); 287165982Srwatson close_both(fd); 288165982Srwatson 289165982Srwatson return (0); 290165982Srwatson} 291