xref: /freebsd/tools/regression/sockets/sendfile/sendfile.c (revision 76423e6e3c020f320fa0b1610c5521f95d44eec0)
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  * $FreeBSD$
270fb57f87SRobert Watson  */
280fb57f87SRobert Watson 
290fb57f87SRobert Watson #include <sys/types.h>
300fb57f87SRobert Watson #include <sys/socket.h>
31ed3d9b6eSPawel Jakub Dawidek #include <sys/stat.h>
328dd83f1eSRebecca Cran #include <sys/wait.h>
330fb57f87SRobert Watson 
340fb57f87SRobert Watson #include <netinet/in.h>
350fb57f87SRobert Watson 
360fb57f87SRobert Watson #include <err.h>
378dd83f1eSRebecca Cran #include <errno.h>
38*76423e6eSPawel Jakub Dawidek #include <fcntl.h>
390fb57f87SRobert Watson #include <limits.h>
408dd83f1eSRebecca Cran #include <md5.h>
410fb57f87SRobert Watson #include <signal.h>
42f7754b09SDag-Erling Smørgrav #include <stdint.h>
430fb57f87SRobert Watson #include <stdio.h>
440fb57f87SRobert Watson #include <stdlib.h>
450fb57f87SRobert Watson #include <string.h>
460fb57f87SRobert Watson #include <unistd.h>
470fb57f87SRobert Watson 
480fb57f87SRobert Watson /*
494225b7d6SMaxim Konovalov  * Simple regression test for sendfile.  Creates a file sized at four pages
500fb57f87SRobert Watson  * and then proceeds to send it over a series of sockets, exercising a number
510fb57f87SRobert Watson  * of cases and performing limited validation.
520fb57f87SRobert Watson  */
530fb57f87SRobert Watson 
548dd83f1eSRebecca Cran #define FAIL(msg)	{printf("# %s\n", msg); \
558dd83f1eSRebecca Cran 			return (-1);}
568dd83f1eSRebecca Cran 
578dd83f1eSRebecca Cran #define FAIL_ERR(msg)	{printf("# %s: %s\n", msg, strerror(errno)); \
588dd83f1eSRebecca Cran 			return (-1);}
598dd83f1eSRebecca Cran 
600fb57f87SRobert Watson #define	TEST_PORT	5678
610fb57f87SRobert Watson #define	TEST_MAGIC	0x4440f7bb
62ed3d9b6eSPawel Jakub Dawidek #define	TEST_PAGES	4
630fb57f87SRobert Watson #define	TEST_SECONDS	30
640fb57f87SRobert Watson 
650fb57f87SRobert Watson struct test_header {
668dd83f1eSRebecca Cran 	uint32_t	th_magic;
678dd83f1eSRebecca Cran 	uint32_t	th_header_length;
688dd83f1eSRebecca Cran 	uint32_t	th_offset;
698dd83f1eSRebecca Cran 	uint32_t	th_length;
708dd83f1eSRebecca Cran 	char		th_md5[33];
710fb57f87SRobert Watson };
720fb57f87SRobert Watson 
738dd83f1eSRebecca Cran struct sendfile_test {
748dd83f1eSRebecca Cran 	uint32_t	hdr_length;
758dd83f1eSRebecca Cran 	uint32_t	offset;
768dd83f1eSRebecca Cran 	uint32_t	length;
778dd83f1eSRebecca Cran };
788dd83f1eSRebecca Cran 
790fb57f87SRobert Watson int	file_fd;
808dd83f1eSRebecca Cran char	path[PATH_MAX];
818dd83f1eSRebecca Cran int	listen_socket;
828dd83f1eSRebecca Cran int	accept_socket;
838dd83f1eSRebecca Cran 
848dd83f1eSRebecca Cran static int test_th(struct test_header *th, uint32_t *header_length,
858dd83f1eSRebecca Cran 		uint32_t *offset, uint32_t *length);
868dd83f1eSRebecca Cran static void signal_alarm(int signum);
878dd83f1eSRebecca Cran static void setup_alarm(int seconds);
888dd83f1eSRebecca Cran static void cancel_alarm(void);
898dd83f1eSRebecca Cran static int receive_test(void);
908dd83f1eSRebecca Cran static void run_child(void);
918dd83f1eSRebecca Cran static int new_test_socket(int *connect_socket);
928dd83f1eSRebecca Cran static void init_th(struct test_header *th, uint32_t header_length,
938dd83f1eSRebecca Cran 		uint32_t offset, uint32_t length);
948dd83f1eSRebecca Cran static int send_test(int connect_socket, struct sendfile_test);
958dd83f1eSRebecca Cran static void run_parent(void);
968dd83f1eSRebecca Cran static void cleanup(void);
978dd83f1eSRebecca Cran 
980fb57f87SRobert Watson 
990fb57f87SRobert Watson static int
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
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
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
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
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
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
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
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
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 	if (test.length == 0) {
2828dd83f1eSRebecca Cran 		struct stat st;
2838dd83f1eSRebecca Cran 		if (fstat(file_fd, &st) < 0)
2848dd83f1eSRebecca Cran 			FAIL_ERR("fstat")
2858dd83f1eSRebecca Cran 		length = st.st_size - test.offset;
2868dd83f1eSRebecca Cran 	}
2878dd83f1eSRebecca Cran 	else {
2888dd83f1eSRebecca Cran 		length = test.length;
2898dd83f1eSRebecca Cran 	}
2908dd83f1eSRebecca Cran 
2918dd83f1eSRebecca Cran 	init_th(&th, test.hdr_length, test.offset, length);
2920fb57f87SRobert Watson 
2930fb57f87SRobert Watson 	len = write(connect_socket, &th, sizeof(th));
2940fb57f87SRobert Watson 	if (len != sizeof(th))
2958dd83f1eSRebecca Cran 		return (-1);
2960fb57f87SRobert Watson 
2978dd83f1eSRebecca Cran 	if (test.hdr_length != 0) {
2988dd83f1eSRebecca Cran 		header = malloc(test.hdr_length);
2990fb57f87SRobert Watson 		if (header == NULL)
3008dd83f1eSRebecca Cran 			FAIL_ERR("malloc")
3018dd83f1eSRebecca Cran 
3020fb57f87SRobert Watson 		hdtrp = &hdtr;
3030fb57f87SRobert Watson 		bzero(&headers, sizeof(headers));
3040fb57f87SRobert Watson 		headers.iov_base = header;
3058dd83f1eSRebecca Cran 		headers.iov_len = test.hdr_length;
3060fb57f87SRobert Watson 		bzero(&hdtr, sizeof(hdtr));
3070fb57f87SRobert Watson 		hdtr.headers = &headers;
3080fb57f87SRobert Watson 		hdtr.hdr_cnt = 1;
3090fb57f87SRobert Watson 		hdtr.trailers = NULL;
3100fb57f87SRobert Watson 		hdtr.trl_cnt = 0;
3110fb57f87SRobert Watson 	} else {
3120fb57f87SRobert Watson 		hdtrp = NULL;
3130fb57f87SRobert Watson 		header = NULL;
3140fb57f87SRobert Watson 	}
3150fb57f87SRobert Watson 
3168dd83f1eSRebecca Cran 	if (sendfile(file_fd, connect_socket, test.offset, test.length,
3178dd83f1eSRebecca Cran 				hdtrp, &off, 0) < 0) {
3188dd83f1eSRebecca Cran 		if (header != NULL)
3198dd83f1eSRebecca Cran 			free(header);
3208dd83f1eSRebecca Cran 		FAIL_ERR("sendfile")
3218dd83f1eSRebecca Cran 	}
3220fb57f87SRobert Watson 
323ed3d9b6eSPawel Jakub Dawidek 	if (length == 0) {
324ed3d9b6eSPawel Jakub Dawidek 		struct stat sb;
325ed3d9b6eSPawel Jakub Dawidek 
3268dd83f1eSRebecca Cran 		if (fstat(file_fd, &sb) == 0)
3278dd83f1eSRebecca Cran 			length = sb.st_size - test.offset;
328ed3d9b6eSPawel Jakub Dawidek 	}
3290fb57f87SRobert Watson 
3300fb57f87SRobert Watson 	if (header != NULL)
3310fb57f87SRobert Watson 		free(header);
3328dd83f1eSRebecca Cran 
3338dd83f1eSRebecca Cran 	if (off != length)
3348dd83f1eSRebecca Cran 		FAIL("offset != length")
3358dd83f1eSRebecca Cran 
3368dd83f1eSRebecca Cran 	return (0);
3370fb57f87SRobert Watson }
3380fb57f87SRobert Watson 
3390fb57f87SRobert Watson static void
3400fb57f87SRobert Watson run_parent(void)
3410fb57f87SRobert Watson {
3420fb57f87SRobert Watson 	int connect_socket;
3438dd83f1eSRebecca Cran 	int status;
3448dd83f1eSRebecca Cran 	int test_num;
3458dd83f1eSRebecca Cran 	int pid;
3460fb57f87SRobert Watson 
3478dd83f1eSRebecca Cran 	const int pagesize = getpagesize();
3488dd83f1eSRebecca Cran 
3498dd83f1eSRebecca Cran 	struct sendfile_test tests[10] = {
3508dd83f1eSRebecca Cran  		{ .hdr_length = 0, .offset = 0, .length = 1 },
3518dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 0, .length = pagesize },
3528dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 1, .length = 1 },
3538dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 1, .length = pagesize },
3548dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = pagesize, .length = pagesize },
3558dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 0, .length = 2*pagesize },
3568dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 0, .length = 0 },
3578dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = pagesize, .length = 0 },
3588dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = 2*pagesize, .length = 0 },
3598dd83f1eSRebecca Cran 		{ .hdr_length = 0, .offset = TEST_PAGES*pagesize, .length = 0 }
3608dd83f1eSRebecca Cran 	};
3618dd83f1eSRebecca Cran 
3628dd83f1eSRebecca Cran 	printf("1..10\n");
3638dd83f1eSRebecca Cran 
3648dd83f1eSRebecca Cran 	for (test_num = 1; test_num <= 10; test_num++) {
3658dd83f1eSRebecca Cran 
3668dd83f1eSRebecca Cran 		pid = fork();
3678dd83f1eSRebecca Cran 		if (pid == -1) {
3688dd83f1eSRebecca Cran 			printf("not ok %d\n", test_num);
3698dd83f1eSRebecca Cran 			continue;
3708dd83f1eSRebecca Cran 		}
3718dd83f1eSRebecca Cran 
3728dd83f1eSRebecca Cran 		if (pid == 0)
3738dd83f1eSRebecca Cran 			run_child();
3748dd83f1eSRebecca Cran 
3758dd83f1eSRebecca Cran 		usleep(250000);
3768dd83f1eSRebecca Cran 
3778dd83f1eSRebecca Cran 		if (new_test_socket(&connect_socket) != 0) {
3788dd83f1eSRebecca Cran 			printf("not ok %d\n", test_num);
3798dd83f1eSRebecca Cran 			kill(pid, SIGALRM);
3800fb57f87SRobert Watson 			close(connect_socket);
3818dd83f1eSRebecca Cran 			continue;
3828dd83f1eSRebecca Cran 		}
3830fb57f87SRobert Watson 
3848dd83f1eSRebecca Cran 		if (send_test(connect_socket, tests[test_num-1]) != 0) {
3858dd83f1eSRebecca Cran 			printf("not ok %d\n", test_num);
3868dd83f1eSRebecca Cran 			kill(pid, SIGALRM);
3870fb57f87SRobert Watson 			close(connect_socket);
3888dd83f1eSRebecca Cran 			continue;
3898dd83f1eSRebecca Cran 		}
3900fb57f87SRobert Watson 
3910fb57f87SRobert Watson 		close(connect_socket);
3928dd83f1eSRebecca Cran 		if (waitpid(pid, &status, 0) == pid) {
3938dd83f1eSRebecca Cran 			if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
3948dd83f1eSRebecca Cran 				printf("%s %d\n", "ok", test_num);
3958dd83f1eSRebecca Cran 			else
3968dd83f1eSRebecca Cran 				printf("%s %d\n", "not ok", test_num);
3978dd83f1eSRebecca Cran 		}
3988dd83f1eSRebecca Cran 		else {
3998dd83f1eSRebecca Cran 			printf("not ok %d\n", test_num);
4008dd83f1eSRebecca Cran 		}
4018dd83f1eSRebecca Cran 	}
4028dd83f1eSRebecca Cran }
4030fb57f87SRobert Watson 
4048dd83f1eSRebecca Cran static void
4058dd83f1eSRebecca Cran cleanup(void)
4068dd83f1eSRebecca Cran {
4078dd83f1eSRebecca Cran 	if (*path != '\0')
4088dd83f1eSRebecca Cran 		unlink(path);
4090fb57f87SRobert Watson }
4100fb57f87SRobert Watson 
4110fb57f87SRobert Watson int
412*76423e6eSPawel Jakub Dawidek main(int argc, char *argv[])
4130fb57f87SRobert Watson {
4148dd83f1eSRebecca Cran 	char *page_buffer;
4150fb57f87SRobert Watson 	int pagesize;
4160fb57f87SRobert Watson 	ssize_t len;
4170fb57f87SRobert Watson 
4188dd83f1eSRebecca Cran 	*path = '\0';
4198dd83f1eSRebecca Cran 
4200fb57f87SRobert Watson 	pagesize = getpagesize();
4210fb57f87SRobert Watson 	page_buffer = malloc(TEST_PAGES * pagesize);
4220fb57f87SRobert Watson 	if (page_buffer == NULL)
4238dd83f1eSRebecca Cran 		FAIL_ERR("malloc")
4240fb57f87SRobert Watson 	bzero(page_buffer, TEST_PAGES * pagesize);
4250fb57f87SRobert Watson 
426*76423e6eSPawel Jakub Dawidek 	if (argc == 1) {
4270fb57f87SRobert Watson 		snprintf(path, PATH_MAX, "/tmp/sendfile.XXXXXXXXXXXX");
4280fb57f87SRobert Watson 		file_fd = mkstemp(path);
429*76423e6eSPawel Jakub Dawidek 		if (file_fd == -1)
430*76423e6eSPawel Jakub Dawidek 			FAIL_ERR("mkstemp");
431*76423e6eSPawel Jakub Dawidek 	} else if (argc == 2) {
432*76423e6eSPawel Jakub Dawidek 		(void)strlcpy(path, argv[1], sizeof(path));
433*76423e6eSPawel Jakub Dawidek 		file_fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
434*76423e6eSPawel Jakub Dawidek 		if (file_fd == -1)
435*76423e6eSPawel Jakub Dawidek 			FAIL_ERR("open");
436*76423e6eSPawel Jakub Dawidek 	} else {
437*76423e6eSPawel Jakub Dawidek 		FAIL("usage: sendfile [path]");
438*76423e6eSPawel Jakub Dawidek 	}
439*76423e6eSPawel Jakub Dawidek 
4408dd83f1eSRebecca Cran 	atexit(cleanup);
4410fb57f87SRobert Watson 
4420fb57f87SRobert Watson 	len = write(file_fd, page_buffer, TEST_PAGES * pagesize);
4430fb57f87SRobert Watson 	if (len < 0)
4448dd83f1eSRebecca Cran 		FAIL_ERR("write")
4450fb57f87SRobert Watson 
4460fb57f87SRobert Watson 	len = lseek(file_fd, 0, SEEK_SET);
4470fb57f87SRobert Watson 	if (len < 0)
4488dd83f1eSRebecca Cran 		FAIL_ERR("lseek")
4490fb57f87SRobert Watson 	if (len != 0)
4508dd83f1eSRebecca Cran 		FAIL("len != 0")
4510fb57f87SRobert Watson 
4520fb57f87SRobert Watson 	run_parent();
4530fb57f87SRobert Watson 	return (0);
4540fb57f87SRobert Watson }
455