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