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
tcp_socketpair(int * sv)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
87*ac52fa1fSMark Johnston 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 *
receiver(void * arg)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
1240c0146c3SGleb Smirnoff static void
usage(void)1250c0146c3SGleb Smirnoff usage(void)
1260c0146c3SGleb Smirnoff {
1270c0146c3SGleb Smirnoff errx(1, "usage: %s [-u] <file> <start> <len> <flags>", getprogname());
1280c0146c3SGleb Smirnoff }
1290c0146c3SGleb Smirnoff
1303b41d99dSChuck Silvers int
main(int argc,char ** argv)1313b41d99dSChuck Silvers main(int argc, char **argv)
1323b41d99dSChuck Silvers {
1333b41d99dSChuck Silvers pthread_t pt;
134c368d3f2SGleb Smirnoff off_t start;
1350c0146c3SGleb Smirnoff int ch, fd, ss[2], flags, error;
1360c0146c3SGleb Smirnoff bool pf_unix = false;
1373b41d99dSChuck Silvers
1380c0146c3SGleb Smirnoff while ((ch = getopt(argc, argv, "u")) != -1)
1390c0146c3SGleb Smirnoff switch (ch) {
1400c0146c3SGleb Smirnoff case 'u':
1410c0146c3SGleb Smirnoff pf_unix = true;
1420c0146c3SGleb Smirnoff break;
1430c0146c3SGleb Smirnoff default:
1440c0146c3SGleb Smirnoff usage();
1450c0146c3SGleb Smirnoff }
1460c0146c3SGleb Smirnoff argc -= optind;
1470c0146c3SGleb Smirnoff argv += optind;
1483b41d99dSChuck Silvers
1490c0146c3SGleb Smirnoff if (argc != 4)
1500c0146c3SGleb Smirnoff usage();
1513b41d99dSChuck Silvers
1520c0146c3SGleb Smirnoff start = strtoull(argv[1], NULL, 0);
1530c0146c3SGleb Smirnoff readlen = strtoull(argv[2], NULL, 0);
1540c0146c3SGleb Smirnoff flags = strtoul(argv[3], NULL, 0);
1550c0146c3SGleb Smirnoff
1560c0146c3SGleb Smirnoff fd = open(argv[0], O_RDONLY);
1573b41d99dSChuck Silvers if (fd < 0)
1583b41d99dSChuck Silvers err(1, "open");
1593b41d99dSChuck Silvers
1600c0146c3SGleb Smirnoff if (pf_unix) {
1610c0146c3SGleb Smirnoff if (socketpair(PF_LOCAL, SOCK_STREAM, 0, ss) != 0)
1620c0146c3SGleb Smirnoff err(1, "socketpair");
1630c0146c3SGleb 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