16a5ba658SKUROSAWA Takahiro /*-
26a5ba658SKUROSAWA Takahiro * SPDX-License-Identifier: BSD-2-Clause
36a5ba658SKUROSAWA Takahiro *
46a5ba658SKUROSAWA Takahiro * Copyright (c) 2020 Netflix, Inc.
56a5ba658SKUROSAWA Takahiro *
66a5ba658SKUROSAWA Takahiro * Redistribution and use in source and binary forms, with or without
76a5ba658SKUROSAWA Takahiro * modification, are permitted provided that the following conditions
86a5ba658SKUROSAWA Takahiro * are met:
96a5ba658SKUROSAWA Takahiro * 1. Redistributions of source code must retain the above copyright
106a5ba658SKUROSAWA Takahiro * notice, this list of conditions and the following disclaimer.
116a5ba658SKUROSAWA Takahiro * 2. Redistributions in binary form must reproduce the above copyright
126a5ba658SKUROSAWA Takahiro * notice, this list of conditions and the following disclaimer in the
136a5ba658SKUROSAWA Takahiro * documentation and/or other materials provided with the distribution.
146a5ba658SKUROSAWA Takahiro *
156a5ba658SKUROSAWA Takahiro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
166a5ba658SKUROSAWA Takahiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
176a5ba658SKUROSAWA Takahiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
186a5ba658SKUROSAWA Takahiro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
196a5ba658SKUROSAWA Takahiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
206a5ba658SKUROSAWA Takahiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
216a5ba658SKUROSAWA Takahiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
226a5ba658SKUROSAWA Takahiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
236a5ba658SKUROSAWA Takahiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246a5ba658SKUROSAWA Takahiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256a5ba658SKUROSAWA Takahiro * SUCH DAMAGE.
266a5ba658SKUROSAWA Takahiro */
276a5ba658SKUROSAWA Takahiro
286a5ba658SKUROSAWA Takahiro #include <sys/types.h>
296a5ba658SKUROSAWA Takahiro #include <sys/socket.h>
306a5ba658SKUROSAWA Takahiro #include <sys/sysctl.h>
316a5ba658SKUROSAWA Takahiro #include <sys/uio.h>
326a5ba658SKUROSAWA Takahiro
336a5ba658SKUROSAWA Takahiro #include <netinet/in.h>
34*2039fe8eSKUROSAWA Takahiro #include <netdb.h>
356a5ba658SKUROSAWA Takahiro
366a5ba658SKUROSAWA Takahiro #include <err.h>
376a5ba658SKUROSAWA Takahiro #include <errno.h>
386a5ba658SKUROSAWA Takahiro #include <fcntl.h>
396a5ba658SKUROSAWA Takahiro #include <pthread.h>
406a5ba658SKUROSAWA Takahiro #include <stdbool.h>
416a5ba658SKUROSAWA Takahiro #include <stdio.h>
426a5ba658SKUROSAWA Takahiro #include <stdlib.h>
436a5ba658SKUROSAWA Takahiro #include <string.h>
446a5ba658SKUROSAWA Takahiro #include <unistd.h>
456a5ba658SKUROSAWA Takahiro
466a5ba658SKUROSAWA Takahiro static char buf[1024*1024];
476a5ba658SKUROSAWA Takahiro static ssize_t readlen;
486a5ba658SKUROSAWA Takahiro static volatile bool read_done = false;
496a5ba658SKUROSAWA Takahiro
506a5ba658SKUROSAWA Takahiro static int
tcp_socketpair(int * sv)516a5ba658SKUROSAWA Takahiro tcp_socketpair(int *sv)
526a5ba658SKUROSAWA Takahiro {
536a5ba658SKUROSAWA Takahiro struct sockaddr_in sin = {
546a5ba658SKUROSAWA Takahiro .sin_len = sizeof(struct sockaddr_in),
556a5ba658SKUROSAWA Takahiro .sin_family = AF_INET,
566a5ba658SKUROSAWA Takahiro .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
576a5ba658SKUROSAWA Takahiro };
586a5ba658SKUROSAWA Takahiro int flags;
596a5ba658SKUROSAWA Takahiro int ls;
606a5ba658SKUROSAWA Takahiro
616a5ba658SKUROSAWA Takahiro ls = socket(PF_INET, SOCK_STREAM, 0);
626a5ba658SKUROSAWA Takahiro if (ls < 0)
636a5ba658SKUROSAWA Takahiro err(1, "socket ls");
646a5ba658SKUROSAWA Takahiro
656a5ba658SKUROSAWA Takahiro if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &(socklen_t){1},
666a5ba658SKUROSAWA Takahiro sizeof(int)) < 0)
676a5ba658SKUROSAWA Takahiro err(1, "SO_REUSEADDR");
686a5ba658SKUROSAWA Takahiro
696a5ba658SKUROSAWA Takahiro if (bind(ls, (struct sockaddr *)&sin, sizeof(sin)) < 0)
706a5ba658SKUROSAWA Takahiro err(1, "bind ls");
716a5ba658SKUROSAWA Takahiro
726a5ba658SKUROSAWA Takahiro if (getsockname(ls, (struct sockaddr *)&sin,
736a5ba658SKUROSAWA Takahiro &(socklen_t){ sizeof(sin) }) < 0)
746a5ba658SKUROSAWA Takahiro err(1, "getsockname");
756a5ba658SKUROSAWA Takahiro
766a5ba658SKUROSAWA Takahiro if (listen(ls, 5) < 0)
776a5ba658SKUROSAWA Takahiro err(1, "listen ls");
786a5ba658SKUROSAWA Takahiro
796a5ba658SKUROSAWA Takahiro sv[0] = socket(PF_INET, SOCK_STREAM, 0);
806a5ba658SKUROSAWA Takahiro if (sv[0] < 0)
816a5ba658SKUROSAWA Takahiro err(1, "socket cs");
826a5ba658SKUROSAWA Takahiro
836a5ba658SKUROSAWA Takahiro flags = fcntl(sv[0], F_GETFL);
846a5ba658SKUROSAWA Takahiro flags |= O_NONBLOCK;
856a5ba658SKUROSAWA Takahiro if (fcntl(sv[0], F_SETFL, flags) == -1)
866a5ba658SKUROSAWA Takahiro err(1, "fcntl +O_NONBLOCK");
876a5ba658SKUROSAWA Takahiro
886a5ba658SKUROSAWA Takahiro if (connect(sv[0], (void *)&sin, sizeof(sin)) == -1 &&
896a5ba658SKUROSAWA Takahiro errno != EINPROGRESS)
906a5ba658SKUROSAWA Takahiro err(1, "connect cs");
916a5ba658SKUROSAWA Takahiro
926a5ba658SKUROSAWA Takahiro sv[1] = accept(ls, NULL, 0);
936a5ba658SKUROSAWA Takahiro if (sv[1] < 0)
946a5ba658SKUROSAWA Takahiro err(1, "accept ls");
956a5ba658SKUROSAWA Takahiro
966a5ba658SKUROSAWA Takahiro flags &= ~O_NONBLOCK;
976a5ba658SKUROSAWA Takahiro if (fcntl(sv[0], F_SETFL, flags) == -1)
986a5ba658SKUROSAWA Takahiro err(1, "fcntl -O_NONBLOCK");
996a5ba658SKUROSAWA Takahiro
1006a5ba658SKUROSAWA Takahiro close(ls);
1016a5ba658SKUROSAWA Takahiro
1026a5ba658SKUROSAWA Takahiro return (0);
1036a5ba658SKUROSAWA Takahiro }
1046a5ba658SKUROSAWA Takahiro
105*2039fe8eSKUROSAWA Takahiro static int
tcp_client_socket(const char * host,const char * port)106*2039fe8eSKUROSAWA Takahiro tcp_client_socket(const char *host, const char *port)
107*2039fe8eSKUROSAWA Takahiro {
108*2039fe8eSKUROSAWA Takahiro struct addrinfo hints, *res, *res0;
109*2039fe8eSKUROSAWA Takahiro int error;
110*2039fe8eSKUROSAWA Takahiro int s;
111*2039fe8eSKUROSAWA Takahiro
112*2039fe8eSKUROSAWA Takahiro memset(&hints, 0, sizeof(hints));
113*2039fe8eSKUROSAWA Takahiro hints.ai_family = AF_UNSPEC;
114*2039fe8eSKUROSAWA Takahiro hints.ai_socktype = SOCK_STREAM;
115*2039fe8eSKUROSAWA Takahiro if ((error = getaddrinfo(host, port, &hints, &res0)) != 0)
116*2039fe8eSKUROSAWA Takahiro errx(1, "host %s port %s: %s.",
117*2039fe8eSKUROSAWA Takahiro host, port, gai_strerror(error));
118*2039fe8eSKUROSAWA Takahiro s = -1;
119*2039fe8eSKUROSAWA Takahiro for (res = res0; res != NULL; res = res->ai_next) {
120*2039fe8eSKUROSAWA Takahiro s = socket(res->ai_family, res->ai_socktype,
121*2039fe8eSKUROSAWA Takahiro res->ai_protocol);
122*2039fe8eSKUROSAWA Takahiro if (s < 0) {
123*2039fe8eSKUROSAWA Takahiro warn("socket(pf:%d, type:%d, proto:%d)",
124*2039fe8eSKUROSAWA Takahiro res->ai_family, res->ai_socktype,
125*2039fe8eSKUROSAWA Takahiro res->ai_protocol);
126*2039fe8eSKUROSAWA Takahiro continue;
127*2039fe8eSKUROSAWA Takahiro }
128*2039fe8eSKUROSAWA Takahiro if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
129*2039fe8eSKUROSAWA Takahiro warn("connect(%s, %s)", host, port);
130*2039fe8eSKUROSAWA Takahiro close(s);
131*2039fe8eSKUROSAWA Takahiro s = -1;
132*2039fe8eSKUROSAWA Takahiro continue;
133*2039fe8eSKUROSAWA Takahiro } else
134*2039fe8eSKUROSAWA Takahiro break;
135*2039fe8eSKUROSAWA Takahiro }
136*2039fe8eSKUROSAWA Takahiro if (s < 0)
137*2039fe8eSKUROSAWA Takahiro exit(1);
138*2039fe8eSKUROSAWA Takahiro freeaddrinfo(res0);
139*2039fe8eSKUROSAWA Takahiro
140*2039fe8eSKUROSAWA Takahiro return s;
141*2039fe8eSKUROSAWA Takahiro }
142*2039fe8eSKUROSAWA Takahiro
1436a5ba658SKUROSAWA Takahiro static void *
receiver(void * arg)1446a5ba658SKUROSAWA Takahiro receiver(void *arg)
1456a5ba658SKUROSAWA Takahiro {
1466a5ba658SKUROSAWA Takahiro int s = *(int *)arg;
1476a5ba658SKUROSAWA Takahiro ssize_t rv;
1486a5ba658SKUROSAWA Takahiro
1496a5ba658SKUROSAWA Takahiro do {
1506a5ba658SKUROSAWA Takahiro rv = read(s, buf, sizeof(buf));
1516a5ba658SKUROSAWA Takahiro if (rv == -1)
1526a5ba658SKUROSAWA Takahiro err(2, "read receiver");
1536a5ba658SKUROSAWA Takahiro if (rv == 0)
1546a5ba658SKUROSAWA Takahiro break;
1556a5ba658SKUROSAWA Takahiro readlen -= rv;
1566a5ba658SKUROSAWA Takahiro } while (readlen != 0);
1576a5ba658SKUROSAWA Takahiro
1586a5ba658SKUROSAWA Takahiro read_done = true;
1596a5ba658SKUROSAWA Takahiro
1606a5ba658SKUROSAWA Takahiro return NULL;
1616a5ba658SKUROSAWA Takahiro }
1626a5ba658SKUROSAWA Takahiro
1636a5ba658SKUROSAWA Takahiro static void
usage(void)1646a5ba658SKUROSAWA Takahiro usage(void)
1656a5ba658SKUROSAWA Takahiro {
166*2039fe8eSKUROSAWA Takahiro errx(1, "usage: %s [-u] [-c host] [-p port] "
167*2039fe8eSKUROSAWA Takahiro "<file> <start> <len> <flags>", getprogname());
1686a5ba658SKUROSAWA Takahiro }
1696a5ba658SKUROSAWA Takahiro
1706a5ba658SKUROSAWA Takahiro int
main(int argc,char ** argv)1716a5ba658SKUROSAWA Takahiro main(int argc, char **argv)
1726a5ba658SKUROSAWA Takahiro {
1736a5ba658SKUROSAWA Takahiro pthread_t pt;
1746a5ba658SKUROSAWA Takahiro off_t start;
1756a5ba658SKUROSAWA Takahiro int ch, fd, ss[2], flags, error;
1766a5ba658SKUROSAWA Takahiro bool pf_unix = false;
177*2039fe8eSKUROSAWA Takahiro bool tcp_client = false;
178*2039fe8eSKUROSAWA Takahiro const char *host, *port;
1796a5ba658SKUROSAWA Takahiro
180*2039fe8eSKUROSAWA Takahiro while ((ch = getopt(argc, argv, "c:p:u")) != -1)
1816a5ba658SKUROSAWA Takahiro switch (ch) {
182*2039fe8eSKUROSAWA Takahiro case 'c':
183*2039fe8eSKUROSAWA Takahiro host = optarg;
184*2039fe8eSKUROSAWA Takahiro tcp_client = true;
185*2039fe8eSKUROSAWA Takahiro break;
186*2039fe8eSKUROSAWA Takahiro case 'p':
187*2039fe8eSKUROSAWA Takahiro port = optarg;
188*2039fe8eSKUROSAWA Takahiro tcp_client = true;
189*2039fe8eSKUROSAWA Takahiro break;
1906a5ba658SKUROSAWA Takahiro case 'u':
1916a5ba658SKUROSAWA Takahiro pf_unix = true;
1926a5ba658SKUROSAWA Takahiro break;
1936a5ba658SKUROSAWA Takahiro default:
1946a5ba658SKUROSAWA Takahiro usage();
1956a5ba658SKUROSAWA Takahiro }
1966a5ba658SKUROSAWA Takahiro argc -= optind;
1976a5ba658SKUROSAWA Takahiro argv += optind;
1986a5ba658SKUROSAWA Takahiro
1996a5ba658SKUROSAWA Takahiro if (argc != 4)
2006a5ba658SKUROSAWA Takahiro usage();
201*2039fe8eSKUROSAWA Takahiro if (tcp_client && (host == NULL || port == NULL))
202*2039fe8eSKUROSAWA Takahiro errx(1, "Need to specify host and port.");
2036a5ba658SKUROSAWA Takahiro
2046a5ba658SKUROSAWA Takahiro start = strtoull(argv[1], NULL, 0);
2056a5ba658SKUROSAWA Takahiro readlen = strtoull(argv[2], NULL, 0);
2066a5ba658SKUROSAWA Takahiro flags = strtoul(argv[3], NULL, 0);
2076a5ba658SKUROSAWA Takahiro
2086a5ba658SKUROSAWA Takahiro fd = open(argv[0], O_RDONLY);
2096a5ba658SKUROSAWA Takahiro if (fd < 0)
2106a5ba658SKUROSAWA Takahiro err(1, "open");
2116a5ba658SKUROSAWA Takahiro
2126a5ba658SKUROSAWA Takahiro if (pf_unix) {
2136a5ba658SKUROSAWA Takahiro if (socketpair(PF_LOCAL, SOCK_STREAM, 0, ss) != 0)
2146a5ba658SKUROSAWA Takahiro err(1, "socketpair");
215*2039fe8eSKUROSAWA Takahiro } else if (tcp_client)
216*2039fe8eSKUROSAWA Takahiro ss[0] = tcp_client_socket(host, port);
217*2039fe8eSKUROSAWA Takahiro else
2186a5ba658SKUROSAWA Takahiro tcp_socketpair(ss);
2196a5ba658SKUROSAWA Takahiro
220*2039fe8eSKUROSAWA Takahiro if (tcp_client)
221*2039fe8eSKUROSAWA Takahiro read_done = true; /* The receiver is another process. */
222*2039fe8eSKUROSAWA Takahiro else {
2236a5ba658SKUROSAWA Takahiro error = pthread_create(&pt, NULL, receiver, &ss[1]);
2246a5ba658SKUROSAWA Takahiro if (error)
2256a5ba658SKUROSAWA Takahiro errc(1, error, "pthread_create");
226*2039fe8eSKUROSAWA Takahiro }
2276a5ba658SKUROSAWA Takahiro
2286a5ba658SKUROSAWA Takahiro if (sendfile(fd, ss[0], start, readlen, NULL, NULL, flags) < 0)
2296a5ba658SKUROSAWA Takahiro err(3, "sendfile");
2306a5ba658SKUROSAWA Takahiro
2316a5ba658SKUROSAWA Takahiro while (!read_done)
2326a5ba658SKUROSAWA Takahiro usleep(1000);
2336a5ba658SKUROSAWA Takahiro
2346a5ba658SKUROSAWA Takahiro exit(0);
2356a5ba658SKUROSAWA Takahiro }
236