xref: /freebsd/tests/sys/kern/sendfile_helper.c (revision ac52fa1f1b9768d281b9deed6d1158f43a8564ca)
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