xref: /freebsd/tools/regression/sockets/sendfile/sendfile.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
10fb57f87SRobert Watson /*-
20fb57f87SRobert Watson  * Copyright (c) 2006 Robert N. M. Watson
30fb57f87SRobert Watson  * All rights reserved.
40fb57f87SRobert Watson  *
50fb57f87SRobert Watson  * Redistribution and use in source and binary forms, with or without
60fb57f87SRobert Watson  * modification, are permitted provided that the following conditions
70fb57f87SRobert Watson  * are met:
80fb57f87SRobert Watson  * 1. Redistributions of source code must retain the above copyright
90fb57f87SRobert Watson  *    notice, this list of conditions and the following disclaimer.
100fb57f87SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
110fb57f87SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
120fb57f87SRobert Watson  *    documentation and/or other materials provided with the distribution.
130fb57f87SRobert Watson  *
140fb57f87SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
150fb57f87SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
160fb57f87SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
170fb57f87SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
180fb57f87SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
190fb57f87SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
200fb57f87SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
210fb57f87SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
220fb57f87SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
230fb57f87SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
240fb57f87SRobert Watson  * SUCH DAMAGE.
250fb57f87SRobert Watson  */
260fb57f87SRobert Watson 
270fb57f87SRobert Watson #include <sys/types.h>
280fb57f87SRobert Watson #include <sys/socket.h>
29ed3d9b6eSPawel Jakub Dawidek #include <sys/stat.h>
308dd83f1eSRebecca Cran #include <sys/wait.h>
310fb57f87SRobert Watson 
320fb57f87SRobert Watson #include <netinet/in.h>
330fb57f87SRobert Watson 
340fb57f87SRobert Watson #include <err.h>
358dd83f1eSRebecca Cran #include <errno.h>
3676423e6eSPawel Jakub Dawidek #include <fcntl.h>
370fb57f87SRobert Watson #include <limits.h>
388dd83f1eSRebecca Cran #include <md5.h>
390fb57f87SRobert Watson #include <signal.h>
40f7754b09SDag-Erling Smørgrav #include <stdint.h>
410fb57f87SRobert Watson #include <stdio.h>
420fb57f87SRobert Watson #include <stdlib.h>
430fb57f87SRobert Watson #include <string.h>
440fb57f87SRobert Watson #include <unistd.h>
450fb57f87SRobert Watson 
460fb57f87SRobert Watson /*
474225b7d6SMaxim Konovalov  * Simple regression test for sendfile.  Creates a file sized at four pages
480fb57f87SRobert Watson  * and then proceeds to send it over a series of sockets, exercising a number
490fb57f87SRobert Watson  * of cases and performing limited validation.
500fb57f87SRobert Watson  */
510fb57f87SRobert Watson 
528dd83f1eSRebecca Cran #define FAIL(msg)	{printf("# %s\n", msg); \
538dd83f1eSRebecca Cran 			return (-1);}
548dd83f1eSRebecca Cran 
558dd83f1eSRebecca Cran #define FAIL_ERR(msg)	{printf("# %s: %s\n", msg, strerror(errno)); \
568dd83f1eSRebecca Cran 			return (-1);}
578dd83f1eSRebecca Cran 
580fb57f87SRobert Watson #define	TEST_PORT	5678
590fb57f87SRobert Watson #define	TEST_MAGIC	0x4440f7bb
60ed3d9b6eSPawel Jakub Dawidek #define	TEST_PAGES	4
610fb57f87SRobert Watson #define	TEST_SECONDS	30
620fb57f87SRobert Watson 
630fb57f87SRobert Watson struct test_header {
648dd83f1eSRebecca Cran 	uint32_t	th_magic;
658dd83f1eSRebecca Cran 	uint32_t	th_header_length;
668dd83f1eSRebecca Cran 	uint32_t	th_offset;
678dd83f1eSRebecca Cran 	uint32_t	th_length;
688dd83f1eSRebecca Cran 	char		th_md5[33];
690fb57f87SRobert Watson };
700fb57f87SRobert Watson 
718dd83f1eSRebecca Cran struct sendfile_test {
728dd83f1eSRebecca Cran 	uint32_t	hdr_length;
738dd83f1eSRebecca Cran 	uint32_t	offset;
748dd83f1eSRebecca Cran 	uint32_t	length;
7550185946SEd Maste 	uint32_t	file_size;
768dd83f1eSRebecca Cran };
778dd83f1eSRebecca Cran 
7850185946SEd Maste static int	file_fd;
7950185946SEd Maste static char	path[PATH_MAX];
8050185946SEd Maste static int	listen_socket;
8150185946SEd Maste static int	accept_socket;
828dd83f1eSRebecca Cran 
838dd83f1eSRebecca Cran static int test_th(struct test_header *th, uint32_t *header_length,
848dd83f1eSRebecca Cran 		uint32_t *offset, uint32_t *length);
858dd83f1eSRebecca Cran static void signal_alarm(int signum);
868dd83f1eSRebecca Cran static void setup_alarm(int seconds);
878dd83f1eSRebecca Cran static void cancel_alarm(void);
888dd83f1eSRebecca Cran static int receive_test(void);
898dd83f1eSRebecca Cran static void run_child(void);
908dd83f1eSRebecca Cran static int new_test_socket(int *connect_socket);
918dd83f1eSRebecca Cran static void init_th(struct test_header *th, uint32_t header_length,
928dd83f1eSRebecca Cran 		uint32_t offset, uint32_t length);
938dd83f1eSRebecca Cran static int send_test(int connect_socket, struct sendfile_test);
9450185946SEd Maste static int write_test_file(size_t file_size);
958dd83f1eSRebecca Cran static void run_parent(void);
968dd83f1eSRebecca Cran static void cleanup(void);
978dd83f1eSRebecca Cran 
980fb57f87SRobert Watson 
990fb57f87SRobert Watson static int
test_th(struct test_header * th,uint32_t * header_length,uint32_t * offset,uint32_t * length)1008dd83f1eSRebecca Cran test_th(struct test_header *th, uint32_t *header_length, uint32_t *offset,
1018dd83f1eSRebecca Cran 		uint32_t *length)
1020fb57f87SRobert Watson {
1030fb57f87SRobert Watson 
1040fb57f87SRobert Watson 	if (th->th_magic != htonl(TEST_MAGIC))
1058dd83f1eSRebecca Cran 		FAIL("magic number not found in header")
1060fb57f87SRobert Watson 	*header_length = ntohl(th->th_header_length);
1070fb57f87SRobert Watson 	*offset = ntohl(th->th_offset);
1080fb57f87SRobert Watson 	*length = ntohl(th->th_length);
1098dd83f1eSRebecca Cran 	return (0);
1100fb57f87SRobert Watson }
1110fb57f87SRobert Watson 
1120fb57f87SRobert Watson static void
signal_alarm(int signum)1130fb57f87SRobert Watson signal_alarm(int signum)
1140fb57f87SRobert Watson {
115f7754b09SDag-Erling Smørgrav 	(void)signum;
1168dd83f1eSRebecca Cran 
1178dd83f1eSRebecca Cran 	printf("# test timeout\n");
1188dd83f1eSRebecca Cran 
1198dd83f1eSRebecca Cran 	if (accept_socket > 0)
1208dd83f1eSRebecca Cran 		close(accept_socket);
1218dd83f1eSRebecca Cran 	if (listen_socket > 0)
1228dd83f1eSRebecca Cran 		close(listen_socket);
1238dd83f1eSRebecca Cran 
1248dd83f1eSRebecca Cran 	_exit(-1);
1250fb57f87SRobert Watson }
1260fb57f87SRobert Watson 
1270fb57f87SRobert Watson static void
setup_alarm(int seconds)1280fb57f87SRobert Watson setup_alarm(int seconds)
1290fb57f87SRobert Watson {
1308dd83f1eSRebecca Cran 	struct itimerval itv;
1318dd83f1eSRebecca Cran 	bzero(&itv, sizeof(itv));
1328dd83f1eSRebecca Cran 	(void)seconds;
1338dd83f1eSRebecca Cran 	itv.it_value.tv_sec = seconds;
1340fb57f87SRobert Watson 
1350fb57f87SRobert Watson 	signal(SIGALRM, signal_alarm);
1368dd83f1eSRebecca Cran 	setitimer(ITIMER_REAL, &itv, NULL);
1370fb57f87SRobert Watson }
1380fb57f87SRobert Watson 
1390fb57f87SRobert Watson static void
cancel_alarm(void)1400fb57f87SRobert Watson cancel_alarm(void)
1410fb57f87SRobert Watson {
1428dd83f1eSRebecca Cran 	struct itimerval itv;
1438dd83f1eSRebecca Cran 	bzero(&itv, sizeof(itv));
1448dd83f1eSRebecca Cran 	setitimer(ITIMER_REAL, &itv, NULL);
1450fb57f87SRobert Watson }
1460fb57f87SRobert Watson 
1478dd83f1eSRebecca Cran static int
receive_test(void)1488dd83f1eSRebecca Cran receive_test(void)
1490fb57f87SRobert Watson {
1508dd83f1eSRebecca Cran 	uint32_t header_length, offset, length, counter;
1510fb57f87SRobert Watson 	struct test_header th;
1520fb57f87SRobert Watson 	ssize_t len;
1538dd83f1eSRebecca Cran 	char buf[10240];
1548dd83f1eSRebecca Cran 	MD5_CTX md5ctx;
1558dd83f1eSRebecca Cran 	char *rxmd5;
1560fb57f87SRobert Watson 
1570fb57f87SRobert Watson 	len = read(accept_socket, &th, sizeof(th));
1588dd83f1eSRebecca Cran 	if (len < 0 || (size_t)len < sizeof(th))
1598dd83f1eSRebecca Cran 		FAIL_ERR("read")
1600fb57f87SRobert Watson 
1618dd83f1eSRebecca Cran 	if (test_th(&th, &header_length, &offset, &length) != 0)
1628dd83f1eSRebecca Cran 		return (-1);
1638dd83f1eSRebecca Cran 
1648dd83f1eSRebecca Cran 	MD5Init(&md5ctx);
1650fb57f87SRobert Watson 
1660fb57f87SRobert Watson 	counter = 0;
1670fb57f87SRobert Watson 	while (1) {
1688dd83f1eSRebecca Cran 		len = read(accept_socket, buf, sizeof(buf));
1698dd83f1eSRebecca Cran 		if (len < 0 || len == 0)
1700fb57f87SRobert Watson 			break;
1718dd83f1eSRebecca Cran 		counter += len;
1728dd83f1eSRebecca Cran 		MD5Update(&md5ctx, buf, len);
1730fb57f87SRobert Watson 	}
1748dd83f1eSRebecca Cran 
1758dd83f1eSRebecca Cran 	rxmd5 = MD5End(&md5ctx, NULL);
1768dd83f1eSRebecca Cran 
1778dd83f1eSRebecca Cran 	if ((counter != header_length+length) ||
1788dd83f1eSRebecca Cran 			memcmp(th.th_md5, rxmd5, 33) != 0)
1798dd83f1eSRebecca Cran 		FAIL("receive length mismatch")
1808dd83f1eSRebecca Cran 
1818dd83f1eSRebecca Cran 	free(rxmd5);
1828dd83f1eSRebecca Cran 	return (0);
1830fb57f87SRobert Watson }
1840fb57f87SRobert Watson 
1850fb57f87SRobert Watson static void
run_child(void)1860fb57f87SRobert Watson run_child(void)
1870fb57f87SRobert Watson {
1888dd83f1eSRebecca Cran 	struct sockaddr_in sin;
1898dd83f1eSRebecca Cran 	int rc = 0;
1900fb57f87SRobert Watson 
1918dd83f1eSRebecca Cran 	listen_socket = socket(PF_INET, SOCK_STREAM, 0);
1928dd83f1eSRebecca Cran 	if (listen_socket < 0) {
1938dd83f1eSRebecca Cran 		printf("# socket: %s\n", strerror(errno));
1948dd83f1eSRebecca Cran 		rc = -1;
1958dd83f1eSRebecca Cran 	}
1968dd83f1eSRebecca Cran 
1978dd83f1eSRebecca Cran 	if (!rc) {
1988dd83f1eSRebecca Cran 		bzero(&sin, sizeof(sin));
1998dd83f1eSRebecca Cran 		sin.sin_len = sizeof(sin);
2008dd83f1eSRebecca Cran 		sin.sin_family = AF_INET;
2018dd83f1eSRebecca Cran 		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2028dd83f1eSRebecca Cran 		sin.sin_port = htons(TEST_PORT);
2038dd83f1eSRebecca Cran 
2048dd83f1eSRebecca Cran 		if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
2058dd83f1eSRebecca Cran 			printf("# bind: %s\n", strerror(errno));
2068dd83f1eSRebecca Cran 			rc = -1;
2078dd83f1eSRebecca Cran 		}
2088dd83f1eSRebecca Cran 	}
2098dd83f1eSRebecca Cran 
2108dd83f1eSRebecca Cran 	if (!rc && listen(listen_socket, -1) < 0) {
2118dd83f1eSRebecca Cran 		printf("# listen: %s\n", strerror(errno));
2128dd83f1eSRebecca Cran 		rc = -1;
2138dd83f1eSRebecca Cran 	}
2148dd83f1eSRebecca Cran 
2158dd83f1eSRebecca Cran 	if (!rc) {
2160fb57f87SRobert Watson 		accept_socket = accept(listen_socket, NULL, NULL);
2170fb57f87SRobert Watson 		setup_alarm(TEST_SECONDS);
2188dd83f1eSRebecca Cran 		if (receive_test() != 0)
2198dd83f1eSRebecca Cran 			rc = -1;
2200fb57f87SRobert Watson 	}
2218dd83f1eSRebecca Cran 
2228dd83f1eSRebecca Cran 	cancel_alarm();
2238dd83f1eSRebecca Cran 	if (accept_socket > 0)
2248dd83f1eSRebecca Cran 		close(accept_socket);
2258dd83f1eSRebecca Cran 	if (listen_socket > 0)
2268dd83f1eSRebecca Cran 		close(listen_socket);
2278dd83f1eSRebecca Cran 
2288dd83f1eSRebecca Cran 	_exit(rc);
2290fb57f87SRobert Watson }
2300fb57f87SRobert Watson 
2310fb57f87SRobert Watson static int
new_test_socket(int * connect_socket)2328dd83f1eSRebecca Cran new_test_socket(int *connect_socket)
2330fb57f87SRobert Watson {
2340fb57f87SRobert Watson 	struct sockaddr_in sin;
2358dd83f1eSRebecca Cran 	int rc = 0;
2360fb57f87SRobert Watson 
2378dd83f1eSRebecca Cran 	*connect_socket = socket(PF_INET, SOCK_STREAM, 0);
2388dd83f1eSRebecca Cran 	if (*connect_socket < 0)
2398dd83f1eSRebecca Cran 		FAIL_ERR("socket")
2400fb57f87SRobert Watson 
2410fb57f87SRobert Watson 	bzero(&sin, sizeof(sin));
2420fb57f87SRobert Watson 	sin.sin_len = sizeof(sin);
2430fb57f87SRobert Watson 	sin.sin_family = AF_INET;
2440fb57f87SRobert Watson 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2450fb57f87SRobert Watson 	sin.sin_port = htons(TEST_PORT);
2460fb57f87SRobert Watson 
2478dd83f1eSRebecca Cran 	if (connect(*connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0)
2488dd83f1eSRebecca Cran 		FAIL_ERR("connect")
2490fb57f87SRobert Watson 
2508dd83f1eSRebecca Cran 	return (rc);
2510fb57f87SRobert Watson }
2520fb57f87SRobert Watson 
2530fb57f87SRobert Watson static void
init_th(struct test_header * th,uint32_t header_length,uint32_t offset,uint32_t length)2548dd83f1eSRebecca Cran init_th(struct test_header *th, uint32_t header_length, uint32_t offset,
2558dd83f1eSRebecca Cran 		uint32_t length)
2560fb57f87SRobert Watson {
2570fb57f87SRobert Watson 	bzero(th, sizeof(*th));
2580fb57f87SRobert Watson 	th->th_magic = htonl(TEST_MAGIC);
2590fb57f87SRobert Watson 	th->th_header_length = htonl(header_length);
2600fb57f87SRobert Watson 	th->th_offset = htonl(offset);
2610fb57f87SRobert Watson 	th->th_length = htonl(length);
2628dd83f1eSRebecca Cran 
2638dd83f1eSRebecca Cran 	MD5FileChunk(path, th->th_md5, offset, length);
2640fb57f87SRobert Watson }
2650fb57f87SRobert Watson 
2668dd83f1eSRebecca Cran static int
send_test(int connect_socket,struct sendfile_test test)2678dd83f1eSRebecca Cran send_test(int connect_socket, struct sendfile_test test)
2680fb57f87SRobert Watson {
2690fb57f87SRobert Watson 	struct test_header th;
2700fb57f87SRobert Watson 	struct sf_hdtr hdtr, *hdtrp;
2710fb57f87SRobert Watson 	struct iovec headers;
2720fb57f87SRobert Watson 	char *header;
2730fb57f87SRobert Watson 	ssize_t len;
2748dd83f1eSRebecca Cran 	int length;
2750fb57f87SRobert Watson 	off_t off;
2760fb57f87SRobert Watson 
2770fb57f87SRobert Watson 	len = lseek(file_fd, 0, SEEK_SET);
2780fb57f87SRobert Watson 	if (len != 0)
2798dd83f1eSRebecca Cran 		FAIL_ERR("lseek")
2800fb57f87SRobert Watson 
2818dd83f1eSRebecca Cran 	struct stat st;
2828dd83f1eSRebecca Cran 	if (fstat(file_fd, &st) < 0)
2838dd83f1eSRebecca Cran 		FAIL_ERR("fstat")
2848dd83f1eSRebecca Cran 	length = st.st_size - test.offset;
28550185946SEd Maste 	if (test.length > 0 && test.length < (uint32_t)length)
2868dd83f1eSRebecca Cran 		length = test.length;
2878dd83f1eSRebecca Cran 
2888dd83f1eSRebecca Cran 	init_th(&th, test.hdr_length, test.offset, length);
2890fb57f87SRobert Watson 
2900fb57f87SRobert Watson 	len = write(connect_socket, &th, sizeof(th));
2910fb57f87SRobert Watson 	if (len != sizeof(th))
2928dd83f1eSRebecca Cran 		return (-1);
2930fb57f87SRobert Watson 
2948dd83f1eSRebecca Cran 	if (test.hdr_length != 0) {
2958dd83f1eSRebecca Cran 		header = malloc(test.hdr_length);
2960fb57f87SRobert Watson 		if (header == NULL)
2978dd83f1eSRebecca Cran 			FAIL_ERR("malloc")
2988dd83f1eSRebecca Cran 
2990fb57f87SRobert Watson 		hdtrp = &hdtr;
3000fb57f87SRobert Watson 		bzero(&headers, sizeof(headers));
3010fb57f87SRobert Watson 		headers.iov_base = header;
3028dd83f1eSRebecca Cran 		headers.iov_len = test.hdr_length;
3030fb57f87SRobert Watson 		bzero(&hdtr, sizeof(hdtr));
3040fb57f87SRobert Watson 		hdtr.headers = &headers;
3050fb57f87SRobert Watson 		hdtr.hdr_cnt = 1;
3060fb57f87SRobert Watson 		hdtr.trailers = NULL;
3070fb57f87SRobert Watson 		hdtr.trl_cnt = 0;
3080fb57f87SRobert Watson 	} else {
3090fb57f87SRobert Watson 		hdtrp = NULL;
3100fb57f87SRobert Watson 		header = NULL;
3110fb57f87SRobert Watson 	}
3120fb57f87SRobert Watson 
3138dd83f1eSRebecca Cran 	if (sendfile(file_fd, connect_socket, test.offset, test.length,
3148dd83f1eSRebecca Cran 				hdtrp, &off, 0) < 0) {
3158dd83f1eSRebecca Cran 		if (header != NULL)
3168dd83f1eSRebecca Cran 			free(header);
3178dd83f1eSRebecca Cran 		FAIL_ERR("sendfile")
3188dd83f1eSRebecca Cran 	}
3190fb57f87SRobert Watson 
320ed3d9b6eSPawel Jakub Dawidek 	if (length == 0) {
321ed3d9b6eSPawel Jakub Dawidek 		struct stat sb;
322ed3d9b6eSPawel Jakub Dawidek 
3238dd83f1eSRebecca Cran 		if (fstat(file_fd, &sb) == 0)
3248dd83f1eSRebecca Cran 			length = sb.st_size - test.offset;
325ed3d9b6eSPawel Jakub Dawidek 	}
3260fb57f87SRobert Watson 
3270fb57f87SRobert Watson 	if (header != NULL)
3280fb57f87SRobert Watson 		free(header);
3298dd83f1eSRebecca Cran 
3308dd83f1eSRebecca Cran 	if (off != length)
3318dd83f1eSRebecca Cran 		FAIL("offset != length")
3328dd83f1eSRebecca Cran 
3338dd83f1eSRebecca Cran 	return (0);
3340fb57f87SRobert Watson }
3350fb57f87SRobert Watson 
33650185946SEd Maste static int
write_test_file(size_t file_size)33750185946SEd Maste write_test_file(size_t file_size)
33850185946SEd Maste {
33950185946SEd Maste 	char *page_buffer;
34050185946SEd Maste 	ssize_t len;
34150185946SEd Maste 	static size_t current_file_size = 0;
34250185946SEd Maste 
34350185946SEd Maste 	if (file_size == current_file_size)
34450185946SEd Maste 		return (0);
34550185946SEd Maste 	else if (file_size < current_file_size) {
34650185946SEd Maste 		if (ftruncate(file_fd, file_size) != 0)
34750185946SEd Maste 			FAIL_ERR("ftruncate");
34850185946SEd Maste 		current_file_size = file_size;
34950185946SEd Maste 		return (0);
35050185946SEd Maste 	}
35150185946SEd Maste 
35250185946SEd Maste 	page_buffer = malloc(file_size);
35350185946SEd Maste 	if (page_buffer == NULL)
35450185946SEd Maste 		FAIL_ERR("malloc")
35550185946SEd Maste 	bzero(page_buffer, file_size);
35650185946SEd Maste 
35750185946SEd Maste 	len = write(file_fd, page_buffer, file_size);
35850185946SEd Maste 	if (len < 0)
35950185946SEd Maste 		FAIL_ERR("write")
36050185946SEd Maste 
36150185946SEd Maste 	len = lseek(file_fd, 0, SEEK_SET);
36250185946SEd Maste 	if (len < 0)
36350185946SEd Maste 		FAIL_ERR("lseek")
36450185946SEd Maste 	if (len != 0)
36550185946SEd Maste 		FAIL("len != 0")
36650185946SEd Maste 
36750185946SEd Maste 	free(page_buffer);
36850185946SEd Maste 	current_file_size = file_size;
36950185946SEd Maste 	return (0);
37050185946SEd Maste }
37150185946SEd Maste 
3720fb57f87SRobert Watson static void
run_parent(void)3730fb57f87SRobert Watson run_parent(void)
3740fb57f87SRobert Watson {
3750fb57f87SRobert Watson 	int connect_socket;
3768dd83f1eSRebecca Cran 	int status;
3778dd83f1eSRebecca Cran 	int test_num;
37850185946SEd Maste 	int test_count;
3798dd83f1eSRebecca Cran 	int pid;
38050185946SEd Maste 	size_t desired_file_size = 0;
3810fb57f87SRobert Watson 
3828dd83f1eSRebecca Cran 	const int pagesize = getpagesize();
3838dd83f1eSRebecca Cran 
38450185946SEd Maste 	struct sendfile_test tests[] = {
3858dd83f1eSRebecca Cran  		{ .hdr_length = 0, .offset = 0, .length = 1 },
3868dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 0, .length = pagesize },
3878dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 1, .length = 1 },
3888dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 1, .length = pagesize },
3898dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = pagesize, .length = pagesize },
3908dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 0, .length = 2*pagesize },
3918dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 0, .length = 0 },
3928dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = pagesize, .length = 0 },
3938dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 2*pagesize, .length = 0 },
39450185946SEd Maste 		{ .hdr_length = 0, .offset = TEST_PAGES*pagesize, .length = 0 },
39550185946SEd Maste 		{ .hdr_length = 0, .offset = 0, .length = pagesize,
39650185946SEd Maste 		    .file_size = 1 }
3978dd83f1eSRebecca Cran 	};
3988dd83f1eSRebecca Cran 
39950185946SEd Maste 	test_count = sizeof(tests) / sizeof(tests[0]);
40050185946SEd Maste 	printf("1..%d\n", test_count);
4018dd83f1eSRebecca Cran 
40250185946SEd Maste 	for (test_num = 1; test_num <= test_count; test_num++) {
40350185946SEd Maste 
40450185946SEd Maste 		desired_file_size = tests[test_num - 1].file_size;
40550185946SEd Maste 		if (desired_file_size == 0)
40650185946SEd Maste 			desired_file_size = TEST_PAGES * pagesize;
40750185946SEd Maste 		if (write_test_file(desired_file_size) != 0) {
40850185946SEd Maste 			printf("not ok %d\n", test_num);
40950185946SEd Maste 			continue;
41050185946SEd Maste 		}
4118dd83f1eSRebecca Cran 
4128dd83f1eSRebecca Cran 		pid = fork();
4138dd83f1eSRebecca Cran 		if (pid == -1) {
4148dd83f1eSRebecca Cran 			printf("not ok %d\n", test_num);
4158dd83f1eSRebecca Cran 			continue;
4168dd83f1eSRebecca Cran 		}
4178dd83f1eSRebecca Cran 
4188dd83f1eSRebecca Cran 		if (pid == 0)
4198dd83f1eSRebecca Cran 			run_child();
4208dd83f1eSRebecca Cran 
4218dd83f1eSRebecca Cran 		usleep(250000);
4228dd83f1eSRebecca Cran 
4238dd83f1eSRebecca Cran 		if (new_test_socket(&connect_socket) != 0) {
4248dd83f1eSRebecca Cran 			printf("not ok %d\n", test_num);
4258dd83f1eSRebecca Cran 			kill(pid, SIGALRM);
4260fb57f87SRobert Watson 			close(connect_socket);
4278dd83f1eSRebecca Cran 			continue;
4288dd83f1eSRebecca Cran 		}
4290fb57f87SRobert Watson 
4308dd83f1eSRebecca Cran 		if (send_test(connect_socket, tests[test_num-1]) != 0) {
4318dd83f1eSRebecca Cran 			printf("not ok %d\n", test_num);
4328dd83f1eSRebecca Cran 			kill(pid, SIGALRM);
4330fb57f87SRobert Watson 			close(connect_socket);
4348dd83f1eSRebecca Cran 			continue;
4358dd83f1eSRebecca Cran 		}
4360fb57f87SRobert Watson 
4370fb57f87SRobert Watson 		close(connect_socket);
4388dd83f1eSRebecca Cran 		if (waitpid(pid, &status, 0) == pid) {
4398dd83f1eSRebecca Cran 			if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
4408dd83f1eSRebecca Cran 				printf("%s %d\n", "ok", test_num);
4418dd83f1eSRebecca Cran 			else
4428dd83f1eSRebecca Cran 				printf("%s %d\n", "not ok", test_num);
4438dd83f1eSRebecca Cran 		}
4448dd83f1eSRebecca Cran 		else {
4458dd83f1eSRebecca Cran 			printf("not ok %d\n", test_num);
4468dd83f1eSRebecca Cran 		}
4478dd83f1eSRebecca Cran 	}
4488dd83f1eSRebecca Cran }
4490fb57f87SRobert Watson 
4508dd83f1eSRebecca Cran static void
cleanup(void)4518dd83f1eSRebecca Cran cleanup(void)
4528dd83f1eSRebecca Cran {
453*b74bcac4SEnji Cooper 
4548dd83f1eSRebecca Cran 	unlink(path);
4550fb57f87SRobert Watson }
4560fb57f87SRobert Watson 
4570fb57f87SRobert Watson int
main(int argc,char * argv[])45876423e6eSPawel Jakub Dawidek main(int argc, char *argv[])
4590fb57f87SRobert Watson {
4600fb57f87SRobert Watson 
461*b74bcac4SEnji Cooper 	path[0] = '\0';
4628dd83f1eSRebecca Cran 
46376423e6eSPawel Jakub Dawidek 	if (argc == 1) {
464*b74bcac4SEnji Cooper 		snprintf(path, sizeof(path), "sendfile.XXXXXXXXXXXX");
4650fb57f87SRobert Watson 		file_fd = mkstemp(path);
46676423e6eSPawel Jakub Dawidek 		if (file_fd == -1)
46776423e6eSPawel Jakub Dawidek 			FAIL_ERR("mkstemp");
46876423e6eSPawel Jakub Dawidek 	} else if (argc == 2) {
46976423e6eSPawel Jakub Dawidek 		(void)strlcpy(path, argv[1], sizeof(path));
47076423e6eSPawel Jakub Dawidek 		file_fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
47176423e6eSPawel Jakub Dawidek 		if (file_fd == -1)
47276423e6eSPawel Jakub Dawidek 			FAIL_ERR("open");
47376423e6eSPawel Jakub Dawidek 	} else {
47476423e6eSPawel Jakub Dawidek 		FAIL("usage: sendfile [path]");
47576423e6eSPawel Jakub Dawidek 	}
47676423e6eSPawel Jakub Dawidek 
4778dd83f1eSRebecca Cran 	atexit(cleanup);
4780fb57f87SRobert Watson 
4790fb57f87SRobert Watson 	run_parent();
4800fb57f87SRobert Watson 	return (0);
4810fb57f87SRobert Watson }
482