13b41d99dSChuck Silvers /*- 23b41d99dSChuck Silvers * SPDX-License-Identifier: BSD-2-Clause 33b41d99dSChuck Silvers * 43b41d99dSChuck Silvers * Copyright (c) 2020 Netflix, Inc. 53b41d99dSChuck Silvers * 63b41d99dSChuck Silvers * Redistribution and use in source and binary forms, with or without 73b41d99dSChuck Silvers * modification, are permitted provided that the following conditions 83b41d99dSChuck Silvers * are met: 93b41d99dSChuck Silvers * 1. Redistributions of source code must retain the above copyright 103b41d99dSChuck Silvers * notice, this list of conditions and the following disclaimer. 113b41d99dSChuck Silvers * 2. Redistributions in binary form must reproduce the above copyright 123b41d99dSChuck Silvers * notice, this list of conditions and the following disclaimer in the 133b41d99dSChuck Silvers * documentation and/or other materials provided with the distribution. 143b41d99dSChuck Silvers * 153b41d99dSChuck Silvers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 163b41d99dSChuck Silvers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 173b41d99dSChuck Silvers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 183b41d99dSChuck Silvers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 193b41d99dSChuck Silvers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 203b41d99dSChuck Silvers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 213b41d99dSChuck Silvers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 223b41d99dSChuck Silvers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 233b41d99dSChuck Silvers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 243b41d99dSChuck Silvers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 253b41d99dSChuck Silvers * SUCH DAMAGE. 263b41d99dSChuck Silvers */ 273b41d99dSChuck Silvers 283b41d99dSChuck Silvers #include <sys/types.h> 293b41d99dSChuck Silvers #include <sys/socket.h> 303b41d99dSChuck Silvers #include <sys/sysctl.h> 313b41d99dSChuck Silvers #include <sys/uio.h> 323b41d99dSChuck Silvers 333b41d99dSChuck Silvers #include <netinet/in.h> 343b41d99dSChuck Silvers 353b41d99dSChuck Silvers #include <err.h> 363b41d99dSChuck Silvers #include <errno.h> 373b41d99dSChuck Silvers #include <fcntl.h> 383b41d99dSChuck Silvers #include <pthread.h> 393b41d99dSChuck Silvers #include <stdbool.h> 403b41d99dSChuck Silvers #include <stdio.h> 413b41d99dSChuck Silvers #include <stdlib.h> 423b41d99dSChuck Silvers #include <string.h> 433b41d99dSChuck Silvers #include <unistd.h> 443b41d99dSChuck Silvers 453b41d99dSChuck Silvers static char buf[1024*1024]; 46c368d3f2SGleb Smirnoff ssize_t readlen; 473b41d99dSChuck Silvers static volatile bool read_done = false; 483b41d99dSChuck Silvers 49c368d3f2SGleb Smirnoff static int 50c368d3f2SGleb Smirnoff tcp_socketpair(int *sv) 513b41d99dSChuck Silvers { 52c368d3f2SGleb Smirnoff struct sockaddr_in sin = { 53c368d3f2SGleb Smirnoff .sin_len = sizeof(struct sockaddr_in), 54c368d3f2SGleb Smirnoff .sin_family = AF_INET, 55c368d3f2SGleb Smirnoff .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 56c368d3f2SGleb Smirnoff }; 57c368d3f2SGleb Smirnoff int flags; 58c368d3f2SGleb Smirnoff int ls; 593b41d99dSChuck Silvers 60c368d3f2SGleb Smirnoff ls = socket(PF_INET, SOCK_STREAM, 0); 61c368d3f2SGleb Smirnoff if (ls < 0) 62c368d3f2SGleb Smirnoff err(1, "socket ls"); 63c368d3f2SGleb Smirnoff 64c368d3f2SGleb Smirnoff if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &(socklen_t){1}, 65c368d3f2SGleb Smirnoff sizeof(int)) < 0) 66c368d3f2SGleb Smirnoff err(1, "SO_REUSEADDR"); 67c368d3f2SGleb Smirnoff 68c368d3f2SGleb Smirnoff if (bind(ls, (struct sockaddr *)&sin, sizeof(sin)) < 0) 69c368d3f2SGleb Smirnoff err(1, "bind ls"); 70c368d3f2SGleb Smirnoff 71c368d3f2SGleb Smirnoff if (getsockname(ls, (struct sockaddr *)&sin, 72c368d3f2SGleb Smirnoff &(socklen_t){ sizeof(sin) }) < 0) 73c368d3f2SGleb Smirnoff err(1, "getsockname"); 74c368d3f2SGleb Smirnoff 75c368d3f2SGleb Smirnoff if (listen(ls, 5) < 0) 76c368d3f2SGleb Smirnoff err(1, "listen ls"); 77c368d3f2SGleb Smirnoff 78c368d3f2SGleb Smirnoff sv[0] = socket(PF_INET, SOCK_STREAM, 0); 79c368d3f2SGleb Smirnoff if (sv[0] < 0) 80c368d3f2SGleb Smirnoff err(1, "socket cs"); 81c368d3f2SGleb Smirnoff 82c368d3f2SGleb Smirnoff flags = fcntl(sv[0], F_GETFL); 83c368d3f2SGleb Smirnoff flags |= O_NONBLOCK; 84c368d3f2SGleb Smirnoff if (fcntl(sv[0], F_SETFL, flags) == -1) 85c368d3f2SGleb Smirnoff err(1, "fcntl +O_NONBLOCK"); 86c368d3f2SGleb Smirnoff 87c368d3f2SGleb Smirnoff if (connect(sv[0], (void *)&sin, sizeof(sin)) != -1 || 88c368d3f2SGleb Smirnoff errno != EINPROGRESS) 89c368d3f2SGleb Smirnoff err(1, "connect cs"); 90c368d3f2SGleb Smirnoff 91c368d3f2SGleb Smirnoff sv[1] = accept(ls, NULL, 0); 92c368d3f2SGleb Smirnoff if (sv[1] < 0) 933b41d99dSChuck Silvers err(1, "accept ls"); 943b41d99dSChuck Silvers 95c368d3f2SGleb Smirnoff flags &= ~O_NONBLOCK; 96c368d3f2SGleb Smirnoff if (fcntl(sv[0], F_SETFL, flags) == -1) 97c368d3f2SGleb Smirnoff err(1, "fcntl -O_NONBLOCK"); 98c368d3f2SGleb Smirnoff 99c368d3f2SGleb Smirnoff close(ls); 100c368d3f2SGleb Smirnoff 101c368d3f2SGleb Smirnoff return (0); 102c368d3f2SGleb Smirnoff } 103c368d3f2SGleb Smirnoff 104c368d3f2SGleb Smirnoff static void * 105c368d3f2SGleb Smirnoff receiver(void *arg) 106c368d3f2SGleb Smirnoff { 107c368d3f2SGleb Smirnoff int s = *(int *)arg; 108c368d3f2SGleb Smirnoff ssize_t rv; 1093b41d99dSChuck Silvers 1103b41d99dSChuck Silvers do { 111c368d3f2SGleb Smirnoff rv = read(s, buf, sizeof(buf)); 1123b41d99dSChuck Silvers if (rv == -1) 1133b41d99dSChuck Silvers err(2, "read receiver"); 1143b41d99dSChuck Silvers if (rv == 0) 1153b41d99dSChuck Silvers break; 1163b41d99dSChuck Silvers readlen -= rv; 1173b41d99dSChuck Silvers } while (readlen != 0); 1183b41d99dSChuck Silvers 1193b41d99dSChuck Silvers read_done = true; 1203b41d99dSChuck Silvers 1213b41d99dSChuck Silvers return NULL; 1223b41d99dSChuck Silvers } 1233b41d99dSChuck Silvers 124*0c0146c3SGleb Smirnoff static void 125*0c0146c3SGleb Smirnoff usage(void) 126*0c0146c3SGleb Smirnoff { 127*0c0146c3SGleb Smirnoff errx(1, "usage: %s [-u] <file> <start> <len> <flags>", getprogname()); 128*0c0146c3SGleb Smirnoff } 129*0c0146c3SGleb Smirnoff 1303b41d99dSChuck Silvers int 1313b41d99dSChuck Silvers main(int argc, char **argv) 1323b41d99dSChuck Silvers { 1333b41d99dSChuck Silvers pthread_t pt; 134c368d3f2SGleb Smirnoff off_t start; 135*0c0146c3SGleb Smirnoff int ch, fd, ss[2], flags, error; 136*0c0146c3SGleb Smirnoff bool pf_unix = false; 1373b41d99dSChuck Silvers 138*0c0146c3SGleb Smirnoff while ((ch = getopt(argc, argv, "u")) != -1) 139*0c0146c3SGleb Smirnoff switch (ch) { 140*0c0146c3SGleb Smirnoff case 'u': 141*0c0146c3SGleb Smirnoff pf_unix = true; 142*0c0146c3SGleb Smirnoff break; 143*0c0146c3SGleb Smirnoff default: 144*0c0146c3SGleb Smirnoff usage(); 145*0c0146c3SGleb Smirnoff } 146*0c0146c3SGleb Smirnoff argc -= optind; 147*0c0146c3SGleb Smirnoff argv += optind; 1483b41d99dSChuck Silvers 149*0c0146c3SGleb Smirnoff if (argc != 4) 150*0c0146c3SGleb Smirnoff usage(); 1513b41d99dSChuck Silvers 152*0c0146c3SGleb Smirnoff start = strtoull(argv[1], NULL, 0); 153*0c0146c3SGleb Smirnoff readlen = strtoull(argv[2], NULL, 0); 154*0c0146c3SGleb Smirnoff flags = strtoul(argv[3], NULL, 0); 155*0c0146c3SGleb Smirnoff 156*0c0146c3SGleb Smirnoff fd = open(argv[0], O_RDONLY); 1573b41d99dSChuck Silvers if (fd < 0) 1583b41d99dSChuck Silvers err(1, "open"); 1593b41d99dSChuck Silvers 160*0c0146c3SGleb Smirnoff if (pf_unix) { 161*0c0146c3SGleb Smirnoff if (socketpair(PF_LOCAL, SOCK_STREAM, 0, ss) != 0) 162*0c0146c3SGleb Smirnoff err(1, "socketpair"); 163*0c0146c3SGleb Smirnoff } else 164c368d3f2SGleb Smirnoff tcp_socketpair(ss); 1653b41d99dSChuck Silvers 166c368d3f2SGleb Smirnoff error = pthread_create(&pt, NULL, receiver, &ss[1]); 1673b41d99dSChuck Silvers if (error) 1683b41d99dSChuck Silvers errc(1, error, "pthread_create"); 1693b41d99dSChuck Silvers 170c368d3f2SGleb Smirnoff if (sendfile(fd, ss[0], start, readlen, NULL, NULL, flags) < 0) 1713b41d99dSChuck Silvers err(3, "sendfile"); 1723b41d99dSChuck Silvers 1733b41d99dSChuck Silvers while (!read_done) 1743b41d99dSChuck Silvers usleep(1000); 1753b41d99dSChuck Silvers 1763b41d99dSChuck Silvers exit(0); 1773b41d99dSChuck Silvers } 178