Path: blob/main/tools/regression/sockets/zerosend/zerosend.c
48249 views
/*-1* Copyright (c) 2007 Robert N. M. Watson2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/select.h>27#include <sys/socket.h>28#include <sys/stat.h>2930#include <netinet/in.h>3132#include <arpa/inet.h>3334#include <err.h>35#include <errno.h>36#include <fcntl.h>37#include <limits.h>38#include <stdio.h>39#include <string.h>40#include <unistd.h>4142#define PORT1 1000143#define PORT2 100024445static void46try_0send(const char *test, int fd)47{48ssize_t len;49char ch;5051ch = 0;52len = send(fd, &ch, 0, 0);53if (len < 0)54err(1, "%s: try_0send", test);55if (len != 0)56errx(1, "%s: try_0send: returned %zd", test, len);57}5859static void60try_0write(const char *test, int fd)61{62ssize_t len;63char ch;6465ch = 0;66len = write(fd, &ch, 0);67if (len < 0)68err(1, "%s: try_0write", test);69if (len != 0)70errx(1, "%s: try_0write: returned %zd", test, len);71}7273static void74setup_udp(const char *test, int *fdp, int port1, int port2)75{76struct sockaddr_in sin;77int sock1, sock2;7879bzero(&sin, sizeof(sin));80sin.sin_len = sizeof(sin);81sin.sin_family = AF_INET;82sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);8384sin.sin_port = htons(port1);85sock1 = socket(PF_INET, SOCK_DGRAM, 0);86if (sock1 < 0)87err(1, "%s: setup_udp: socket", test);88if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)89err(1, "%s: setup_udp: bind(%s, %d)", test,90inet_ntoa(sin.sin_addr), PORT1);91sin.sin_port = htons(port2);92if (connect(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)93err(1, "%s: setup_udp: connect(%s, %d)", test,94inet_ntoa(sin.sin_addr), PORT2);9596sock2 = socket(PF_INET, SOCK_DGRAM, 0);97if (sock2 < 0)98err(1, "%s: setup_udp: socket", test);99if (bind(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0)100err(1, "%s: setup_udp: bind(%s, %d)", test,101inet_ntoa(sin.sin_addr), PORT2);102sin.sin_port = htons(port1);103if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0)104err(1, "%s: setup_udp: connect(%s, %d)", test,105inet_ntoa(sin.sin_addr), PORT1);106107fdp[0] = sock1;108fdp[1] = sock2;109}110111static void112setup_tcp(const char *test, int *fdp, int port)113{114fd_set writefds, exceptfds;115struct sockaddr_in sin;116int ret, sock1, sock2, sock3;117struct timeval tv;118119bzero(&sin, sizeof(sin));120sin.sin_len = sizeof(sin);121sin.sin_family = AF_INET;122sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);123124/*125* First set up the listen socket.126*/127sin.sin_port = htons(port);128sock1 = socket(PF_INET, SOCK_STREAM, 0);129if (sock1 < 0)130err(1, "%s: setup_tcp: socket", test);131if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0)132err(1, "%s: bind(%s, %d)", test, inet_ntoa(sin.sin_addr),133PORT1);134if (listen(sock1, -1) < 0)135err(1, "%s: listen", test);136137/*138* Now connect to it, non-blocking so that we don't deadlock against139* ourselves.140*/141sock2 = socket(PF_INET, SOCK_STREAM, 0);142if (sock2 < 0)143err(1, "%s: setup_tcp: socket", test);144if (fcntl(sock2, F_SETFL, O_NONBLOCK) < 0)145err(1, "%s: setup_tcp: fcntl(O_NONBLOCK)", test);146if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0 &&147errno != EINPROGRESS)148err(1, "%s: setup_tcp: connect(%s, %d)", test,149inet_ntoa(sin.sin_addr), PORT1);150151/*152* Now pick up the connection after sleeping a moment to make sure153* there's been time for some packets to go back and forth.154*/155if (sleep(1) != 0)156err(1, "%s: sleep(1)", test);157sock3 = accept(sock1, NULL, NULL);158if (sock3 < 0)159err(1, "%s: accept", test);160if (sleep(1) != 0)161err(1, "%s: sleep(1)", test);162163FD_ZERO(&writefds);164FD_SET(sock2, &writefds);165FD_ZERO(&exceptfds);166FD_SET(sock2, &exceptfds);167tv.tv_sec = 1;168tv.tv_usec = 0;169ret = select(sock2 + 1, NULL, &writefds, &exceptfds, &tv);170if (ret < 0)171err(1, "%s: setup_tcp: select", test);172if (FD_ISSET(sock2, &exceptfds))173errx(1, "%s: setup_tcp: select: exception", test);174if (!FD_ISSET(sock2, &writefds))175errx(1, "%s: setup_tcp: select: not writable", test);176177close(sock1);178fdp[0] = sock2;179fdp[1] = sock3;180}181182static void183setup_udsstream(const char *test, int *fdp)184{185186if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fdp) < 0)187err(1, "%s: setup_udsstream: socketpair", test);188}189190static void191setup_udsdgram(const char *test, int *fdp)192{193194if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fdp) < 0)195err(1, "%s: setup_udsdgram: socketpair", test);196}197198static void199setup_pipe(const char *test, int *fdp)200{201202if (pipe(fdp) < 0)203err(1, "%s: setup_pipe: pipe", test);204}205206static void207setup_fifo(const char *test, int *fdp)208{209char path[] = "0send_fifo.XXXXXXX";210int fd1, fd2;211212if (mkstemp(path) == -1)213err(1, "%s: setup_fifo: mktemp", test);214unlink(path);215216if (mkfifo(path, 0600) < 0)217err(1, "%s: setup_fifo: mkfifo(%s)", test, path);218219fd1 = open(path, O_RDONLY | O_NONBLOCK);220if (fd1 < 0)221err(1, "%s: setup_fifo: open(%s, O_RDONLY)", test, path);222223fd2 = open(path, O_WRONLY | O_NONBLOCK);224if (fd2 < 0)225err(1, "%s: setup_fifo: open(%s, O_WRONLY)", test, path);226227fdp[0] = fd2;228fdp[1] = fd1;229}230231static void232close_both(int *fdp)233{234235close(fdp[0]);236fdp[0] = -1;237close(fdp[1]);238fdp[1] = -1;239}240241int242main(void)243{244int fd[2];245246setup_udp("udp_0send", fd, PORT1, PORT2);247try_0send("udp_0send", fd[0]);248close_both(fd);249250setup_udp("udp_0write", fd, PORT1 + 10, PORT2 + 10);251try_0write("udp_0write", fd[0]);252close_both(fd);253254setup_tcp("tcp_0send", fd, PORT1);255try_0send("tcp_0send", fd[0]);256close_both(fd);257258setup_tcp("tcp_0write", fd, PORT1 + 10);259try_0write("tcp_0write", fd[0]);260close_both(fd);261262setup_udsstream("udsstream_0send", fd);263try_0send("udsstream_0send", fd[0]);264close_both(fd);265266setup_udsstream("udsstream_0write", fd);267try_0write("udsstream_0write", fd[0]);268close_both(fd);269270setup_udsdgram("udsdgram_0send", fd);271try_0send("udsdgram_0send", fd[0]);272close_both(fd);273274setup_udsdgram("udsdgram_0write", fd);275try_0write("udsdgram_0write", fd[0]);276close_both(fd);277278setup_pipe("pipe_0write", fd);279try_0write("pipd_0write", fd[0]);280close_both(fd);281282setup_fifo("fifo_0write", fd);283try_0write("fifo_0write", fd[0]);284close_both(fd);285286return (0);287}288289290