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> 3876423e6eSPawel 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; 7750185946SEd Maste uint32_t file_size; 788dd83f1eSRebecca Cran }; 798dd83f1eSRebecca Cran 8050185946SEd Maste static int file_fd; 8150185946SEd Maste static char path[PATH_MAX]; 8250185946SEd Maste static int listen_socket; 8350185946SEd Maste static int accept_socket; 848dd83f1eSRebecca Cran 858dd83f1eSRebecca Cran static int test_th(struct test_header *th, uint32_t *header_length, 868dd83f1eSRebecca Cran uint32_t *offset, uint32_t *length); 878dd83f1eSRebecca Cran static void signal_alarm(int signum); 888dd83f1eSRebecca Cran static void setup_alarm(int seconds); 898dd83f1eSRebecca Cran static void cancel_alarm(void); 908dd83f1eSRebecca Cran static int receive_test(void); 918dd83f1eSRebecca Cran static void run_child(void); 928dd83f1eSRebecca Cran static int new_test_socket(int *connect_socket); 938dd83f1eSRebecca Cran static void init_th(struct test_header *th, uint32_t header_length, 948dd83f1eSRebecca Cran uint32_t offset, uint32_t length); 958dd83f1eSRebecca Cran static int send_test(int connect_socket, struct sendfile_test); 9650185946SEd Maste static int write_test_file(size_t file_size); 978dd83f1eSRebecca Cran static void run_parent(void); 988dd83f1eSRebecca Cran static void cleanup(void); 998dd83f1eSRebecca Cran 1000fb57f87SRobert Watson 1010fb57f87SRobert Watson static int 1028dd83f1eSRebecca Cran test_th(struct test_header *th, uint32_t *header_length, uint32_t *offset, 1038dd83f1eSRebecca Cran uint32_t *length) 1040fb57f87SRobert Watson { 1050fb57f87SRobert Watson 1060fb57f87SRobert Watson if (th->th_magic != htonl(TEST_MAGIC)) 1078dd83f1eSRebecca Cran FAIL("magic number not found in header") 1080fb57f87SRobert Watson *header_length = ntohl(th->th_header_length); 1090fb57f87SRobert Watson *offset = ntohl(th->th_offset); 1100fb57f87SRobert Watson *length = ntohl(th->th_length); 1118dd83f1eSRebecca Cran return (0); 1120fb57f87SRobert Watson } 1130fb57f87SRobert Watson 1140fb57f87SRobert Watson static void 1150fb57f87SRobert Watson signal_alarm(int signum) 1160fb57f87SRobert Watson { 117f7754b09SDag-Erling Smørgrav (void)signum; 1188dd83f1eSRebecca Cran 1198dd83f1eSRebecca Cran printf("# test timeout\n"); 1208dd83f1eSRebecca Cran 1218dd83f1eSRebecca Cran if (accept_socket > 0) 1228dd83f1eSRebecca Cran close(accept_socket); 1238dd83f1eSRebecca Cran if (listen_socket > 0) 1248dd83f1eSRebecca Cran close(listen_socket); 1258dd83f1eSRebecca Cran 1268dd83f1eSRebecca Cran _exit(-1); 1270fb57f87SRobert Watson } 1280fb57f87SRobert Watson 1290fb57f87SRobert Watson static void 1300fb57f87SRobert Watson setup_alarm(int seconds) 1310fb57f87SRobert Watson { 1328dd83f1eSRebecca Cran struct itimerval itv; 1338dd83f1eSRebecca Cran bzero(&itv, sizeof(itv)); 1348dd83f1eSRebecca Cran (void)seconds; 1358dd83f1eSRebecca Cran itv.it_value.tv_sec = seconds; 1360fb57f87SRobert Watson 1370fb57f87SRobert Watson signal(SIGALRM, signal_alarm); 1388dd83f1eSRebecca Cran setitimer(ITIMER_REAL, &itv, NULL); 1390fb57f87SRobert Watson } 1400fb57f87SRobert Watson 1410fb57f87SRobert Watson static void 1420fb57f87SRobert Watson cancel_alarm(void) 1430fb57f87SRobert Watson { 1448dd83f1eSRebecca Cran struct itimerval itv; 1458dd83f1eSRebecca Cran bzero(&itv, sizeof(itv)); 1468dd83f1eSRebecca Cran setitimer(ITIMER_REAL, &itv, NULL); 1470fb57f87SRobert Watson } 1480fb57f87SRobert Watson 1498dd83f1eSRebecca Cran static int 1508dd83f1eSRebecca Cran receive_test(void) 1510fb57f87SRobert Watson { 1528dd83f1eSRebecca Cran uint32_t header_length, offset, length, counter; 1530fb57f87SRobert Watson struct test_header th; 1540fb57f87SRobert Watson ssize_t len; 1558dd83f1eSRebecca Cran char buf[10240]; 1568dd83f1eSRebecca Cran MD5_CTX md5ctx; 1578dd83f1eSRebecca Cran char *rxmd5; 1580fb57f87SRobert Watson 1590fb57f87SRobert Watson len = read(accept_socket, &th, sizeof(th)); 1608dd83f1eSRebecca Cran if (len < 0 || (size_t)len < sizeof(th)) 1618dd83f1eSRebecca Cran FAIL_ERR("read") 1620fb57f87SRobert Watson 1638dd83f1eSRebecca Cran if (test_th(&th, &header_length, &offset, &length) != 0) 1648dd83f1eSRebecca Cran return (-1); 1658dd83f1eSRebecca Cran 1668dd83f1eSRebecca Cran MD5Init(&md5ctx); 1670fb57f87SRobert Watson 1680fb57f87SRobert Watson counter = 0; 1690fb57f87SRobert Watson while (1) { 1708dd83f1eSRebecca Cran len = read(accept_socket, buf, sizeof(buf)); 1718dd83f1eSRebecca Cran if (len < 0 || len == 0) 1720fb57f87SRobert Watson break; 1738dd83f1eSRebecca Cran counter += len; 1748dd83f1eSRebecca Cran MD5Update(&md5ctx, buf, len); 1750fb57f87SRobert Watson } 1768dd83f1eSRebecca Cran 1778dd83f1eSRebecca Cran rxmd5 = MD5End(&md5ctx, NULL); 1788dd83f1eSRebecca Cran 1798dd83f1eSRebecca Cran if ((counter != header_length+length) || 1808dd83f1eSRebecca Cran memcmp(th.th_md5, rxmd5, 33) != 0) 1818dd83f1eSRebecca Cran FAIL("receive length mismatch") 1828dd83f1eSRebecca Cran 1838dd83f1eSRebecca Cran free(rxmd5); 1848dd83f1eSRebecca Cran return (0); 1850fb57f87SRobert Watson } 1860fb57f87SRobert Watson 1870fb57f87SRobert Watson static void 1880fb57f87SRobert Watson run_child(void) 1890fb57f87SRobert Watson { 1908dd83f1eSRebecca Cran struct sockaddr_in sin; 1918dd83f1eSRebecca Cran int rc = 0; 1920fb57f87SRobert Watson 1938dd83f1eSRebecca Cran listen_socket = socket(PF_INET, SOCK_STREAM, 0); 1948dd83f1eSRebecca Cran if (listen_socket < 0) { 1958dd83f1eSRebecca Cran printf("# socket: %s\n", strerror(errno)); 1968dd83f1eSRebecca Cran rc = -1; 1978dd83f1eSRebecca Cran } 1988dd83f1eSRebecca Cran 1998dd83f1eSRebecca Cran if (!rc) { 2008dd83f1eSRebecca Cran bzero(&sin, sizeof(sin)); 2018dd83f1eSRebecca Cran sin.sin_len = sizeof(sin); 2028dd83f1eSRebecca Cran sin.sin_family = AF_INET; 2038dd83f1eSRebecca Cran sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 2048dd83f1eSRebecca Cran sin.sin_port = htons(TEST_PORT); 2058dd83f1eSRebecca Cran 2068dd83f1eSRebecca Cran if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 2078dd83f1eSRebecca Cran printf("# bind: %s\n", strerror(errno)); 2088dd83f1eSRebecca Cran rc = -1; 2098dd83f1eSRebecca Cran } 2108dd83f1eSRebecca Cran } 2118dd83f1eSRebecca Cran 2128dd83f1eSRebecca Cran if (!rc && listen(listen_socket, -1) < 0) { 2138dd83f1eSRebecca Cran printf("# listen: %s\n", strerror(errno)); 2148dd83f1eSRebecca Cran rc = -1; 2158dd83f1eSRebecca Cran } 2168dd83f1eSRebecca Cran 2178dd83f1eSRebecca Cran if (!rc) { 2180fb57f87SRobert Watson accept_socket = accept(listen_socket, NULL, NULL); 2190fb57f87SRobert Watson setup_alarm(TEST_SECONDS); 2208dd83f1eSRebecca Cran if (receive_test() != 0) 2218dd83f1eSRebecca Cran rc = -1; 2220fb57f87SRobert Watson } 2238dd83f1eSRebecca Cran 2248dd83f1eSRebecca Cran cancel_alarm(); 2258dd83f1eSRebecca Cran if (accept_socket > 0) 2268dd83f1eSRebecca Cran close(accept_socket); 2278dd83f1eSRebecca Cran if (listen_socket > 0) 2288dd83f1eSRebecca Cran close(listen_socket); 2298dd83f1eSRebecca Cran 2308dd83f1eSRebecca Cran _exit(rc); 2310fb57f87SRobert Watson } 2320fb57f87SRobert Watson 2330fb57f87SRobert Watson static int 2348dd83f1eSRebecca Cran new_test_socket(int *connect_socket) 2350fb57f87SRobert Watson { 2360fb57f87SRobert Watson struct sockaddr_in sin; 2378dd83f1eSRebecca Cran int rc = 0; 2380fb57f87SRobert Watson 2398dd83f1eSRebecca Cran *connect_socket = socket(PF_INET, SOCK_STREAM, 0); 2408dd83f1eSRebecca Cran if (*connect_socket < 0) 2418dd83f1eSRebecca Cran FAIL_ERR("socket") 2420fb57f87SRobert Watson 2430fb57f87SRobert Watson bzero(&sin, sizeof(sin)); 2440fb57f87SRobert Watson sin.sin_len = sizeof(sin); 2450fb57f87SRobert Watson sin.sin_family = AF_INET; 2460fb57f87SRobert Watson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 2470fb57f87SRobert Watson sin.sin_port = htons(TEST_PORT); 2480fb57f87SRobert Watson 2498dd83f1eSRebecca Cran if (connect(*connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) 2508dd83f1eSRebecca Cran FAIL_ERR("connect") 2510fb57f87SRobert Watson 2528dd83f1eSRebecca Cran return (rc); 2530fb57f87SRobert Watson } 2540fb57f87SRobert Watson 2550fb57f87SRobert Watson static void 2568dd83f1eSRebecca Cran init_th(struct test_header *th, uint32_t header_length, uint32_t offset, 2578dd83f1eSRebecca Cran uint32_t length) 2580fb57f87SRobert Watson { 2590fb57f87SRobert Watson bzero(th, sizeof(*th)); 2600fb57f87SRobert Watson th->th_magic = htonl(TEST_MAGIC); 2610fb57f87SRobert Watson th->th_header_length = htonl(header_length); 2620fb57f87SRobert Watson th->th_offset = htonl(offset); 2630fb57f87SRobert Watson th->th_length = htonl(length); 2648dd83f1eSRebecca Cran 2658dd83f1eSRebecca Cran MD5FileChunk(path, th->th_md5, offset, length); 2660fb57f87SRobert Watson } 2670fb57f87SRobert Watson 2688dd83f1eSRebecca Cran static int 2698dd83f1eSRebecca Cran send_test(int connect_socket, struct sendfile_test test) 2700fb57f87SRobert Watson { 2710fb57f87SRobert Watson struct test_header th; 2720fb57f87SRobert Watson struct sf_hdtr hdtr, *hdtrp; 2730fb57f87SRobert Watson struct iovec headers; 2740fb57f87SRobert Watson char *header; 2750fb57f87SRobert Watson ssize_t len; 2768dd83f1eSRebecca Cran int length; 2770fb57f87SRobert Watson off_t off; 2780fb57f87SRobert Watson 2790fb57f87SRobert Watson len = lseek(file_fd, 0, SEEK_SET); 2800fb57f87SRobert Watson if (len != 0) 2818dd83f1eSRebecca Cran FAIL_ERR("lseek") 2820fb57f87SRobert Watson 2838dd83f1eSRebecca Cran struct stat st; 2848dd83f1eSRebecca Cran if (fstat(file_fd, &st) < 0) 2858dd83f1eSRebecca Cran FAIL_ERR("fstat") 2868dd83f1eSRebecca Cran length = st.st_size - test.offset; 28750185946SEd Maste if (test.length > 0 && test.length < (uint32_t)length) 2888dd83f1eSRebecca Cran length = test.length; 2898dd83f1eSRebecca Cran 2908dd83f1eSRebecca Cran init_th(&th, test.hdr_length, test.offset, length); 2910fb57f87SRobert Watson 2920fb57f87SRobert Watson len = write(connect_socket, &th, sizeof(th)); 2930fb57f87SRobert Watson if (len != sizeof(th)) 2948dd83f1eSRebecca Cran return (-1); 2950fb57f87SRobert Watson 2968dd83f1eSRebecca Cran if (test.hdr_length != 0) { 2978dd83f1eSRebecca Cran header = malloc(test.hdr_length); 2980fb57f87SRobert Watson if (header == NULL) 2998dd83f1eSRebecca Cran FAIL_ERR("malloc") 3008dd83f1eSRebecca Cran 3010fb57f87SRobert Watson hdtrp = &hdtr; 3020fb57f87SRobert Watson bzero(&headers, sizeof(headers)); 3030fb57f87SRobert Watson headers.iov_base = header; 3048dd83f1eSRebecca Cran headers.iov_len = test.hdr_length; 3050fb57f87SRobert Watson bzero(&hdtr, sizeof(hdtr)); 3060fb57f87SRobert Watson hdtr.headers = &headers; 3070fb57f87SRobert Watson hdtr.hdr_cnt = 1; 3080fb57f87SRobert Watson hdtr.trailers = NULL; 3090fb57f87SRobert Watson hdtr.trl_cnt = 0; 3100fb57f87SRobert Watson } else { 3110fb57f87SRobert Watson hdtrp = NULL; 3120fb57f87SRobert Watson header = NULL; 3130fb57f87SRobert Watson } 3140fb57f87SRobert Watson 3158dd83f1eSRebecca Cran if (sendfile(file_fd, connect_socket, test.offset, test.length, 3168dd83f1eSRebecca Cran hdtrp, &off, 0) < 0) { 3178dd83f1eSRebecca Cran if (header != NULL) 3188dd83f1eSRebecca Cran free(header); 3198dd83f1eSRebecca Cran FAIL_ERR("sendfile") 3208dd83f1eSRebecca Cran } 3210fb57f87SRobert Watson 322ed3d9b6eSPawel Jakub Dawidek if (length == 0) { 323ed3d9b6eSPawel Jakub Dawidek struct stat sb; 324ed3d9b6eSPawel Jakub Dawidek 3258dd83f1eSRebecca Cran if (fstat(file_fd, &sb) == 0) 3268dd83f1eSRebecca Cran length = sb.st_size - test.offset; 327ed3d9b6eSPawel Jakub Dawidek } 3280fb57f87SRobert Watson 3290fb57f87SRobert Watson if (header != NULL) 3300fb57f87SRobert Watson free(header); 3318dd83f1eSRebecca Cran 3328dd83f1eSRebecca Cran if (off != length) 3338dd83f1eSRebecca Cran FAIL("offset != length") 3348dd83f1eSRebecca Cran 3358dd83f1eSRebecca Cran return (0); 3360fb57f87SRobert Watson } 3370fb57f87SRobert Watson 33850185946SEd Maste static int 33950185946SEd Maste write_test_file(size_t file_size) 34050185946SEd Maste { 34150185946SEd Maste char *page_buffer; 34250185946SEd Maste ssize_t len; 34350185946SEd Maste static size_t current_file_size = 0; 34450185946SEd Maste 34550185946SEd Maste if (file_size == current_file_size) 34650185946SEd Maste return (0); 34750185946SEd Maste else if (file_size < current_file_size) { 34850185946SEd Maste if (ftruncate(file_fd, file_size) != 0) 34950185946SEd Maste FAIL_ERR("ftruncate"); 35050185946SEd Maste current_file_size = file_size; 35150185946SEd Maste return (0); 35250185946SEd Maste } 35350185946SEd Maste 35450185946SEd Maste page_buffer = malloc(file_size); 35550185946SEd Maste if (page_buffer == NULL) 35650185946SEd Maste FAIL_ERR("malloc") 35750185946SEd Maste bzero(page_buffer, file_size); 35850185946SEd Maste 35950185946SEd Maste len = write(file_fd, page_buffer, file_size); 36050185946SEd Maste if (len < 0) 36150185946SEd Maste FAIL_ERR("write") 36250185946SEd Maste 36350185946SEd Maste len = lseek(file_fd, 0, SEEK_SET); 36450185946SEd Maste if (len < 0) 36550185946SEd Maste FAIL_ERR("lseek") 36650185946SEd Maste if (len != 0) 36750185946SEd Maste FAIL("len != 0") 36850185946SEd Maste 36950185946SEd Maste free(page_buffer); 37050185946SEd Maste current_file_size = file_size; 37150185946SEd Maste return (0); 37250185946SEd Maste } 37350185946SEd Maste 3740fb57f87SRobert Watson static void 3750fb57f87SRobert Watson run_parent(void) 3760fb57f87SRobert Watson { 3770fb57f87SRobert Watson int connect_socket; 3788dd83f1eSRebecca Cran int status; 3798dd83f1eSRebecca Cran int test_num; 38050185946SEd Maste int test_count; 3818dd83f1eSRebecca Cran int pid; 38250185946SEd Maste size_t desired_file_size = 0; 3830fb57f87SRobert Watson 3848dd83f1eSRebecca Cran const int pagesize = getpagesize(); 3858dd83f1eSRebecca Cran 38650185946SEd Maste struct sendfile_test tests[] = { 3878dd83f1eSRebecca Cran { .hdr_length = 0, .offset = 0, .length = 1 }, 3888dd83f1eSRebecca Cran { .hdr_length = 0, .offset = 0, .length = pagesize }, 3898dd83f1eSRebecca Cran { .hdr_length = 0, .offset = 1, .length = 1 }, 3908dd83f1eSRebecca Cran { .hdr_length = 0, .offset = 1, .length = pagesize }, 3918dd83f1eSRebecca Cran { .hdr_length = 0, .offset = pagesize, .length = pagesize }, 3928dd83f1eSRebecca Cran { .hdr_length = 0, .offset = 0, .length = 2*pagesize }, 3938dd83f1eSRebecca Cran { .hdr_length = 0, .offset = 0, .length = 0 }, 3948dd83f1eSRebecca Cran { .hdr_length = 0, .offset = pagesize, .length = 0 }, 3958dd83f1eSRebecca Cran { .hdr_length = 0, .offset = 2*pagesize, .length = 0 }, 39650185946SEd Maste { .hdr_length = 0, .offset = TEST_PAGES*pagesize, .length = 0 }, 39750185946SEd Maste { .hdr_length = 0, .offset = 0, .length = pagesize, 39850185946SEd Maste .file_size = 1 } 3998dd83f1eSRebecca Cran }; 4008dd83f1eSRebecca Cran 40150185946SEd Maste test_count = sizeof(tests) / sizeof(tests[0]); 40250185946SEd Maste printf("1..%d\n", test_count); 4038dd83f1eSRebecca Cran 40450185946SEd Maste for (test_num = 1; test_num <= test_count; test_num++) { 40550185946SEd Maste 40650185946SEd Maste desired_file_size = tests[test_num - 1].file_size; 40750185946SEd Maste if (desired_file_size == 0) 40850185946SEd Maste desired_file_size = TEST_PAGES * pagesize; 40950185946SEd Maste if (write_test_file(desired_file_size) != 0) { 41050185946SEd Maste printf("not ok %d\n", test_num); 41150185946SEd Maste continue; 41250185946SEd Maste } 4138dd83f1eSRebecca Cran 4148dd83f1eSRebecca Cran pid = fork(); 4158dd83f1eSRebecca Cran if (pid == -1) { 4168dd83f1eSRebecca Cran printf("not ok %d\n", test_num); 4178dd83f1eSRebecca Cran continue; 4188dd83f1eSRebecca Cran } 4198dd83f1eSRebecca Cran 4208dd83f1eSRebecca Cran if (pid == 0) 4218dd83f1eSRebecca Cran run_child(); 4228dd83f1eSRebecca Cran 4238dd83f1eSRebecca Cran usleep(250000); 4248dd83f1eSRebecca Cran 4258dd83f1eSRebecca Cran if (new_test_socket(&connect_socket) != 0) { 4268dd83f1eSRebecca Cran printf("not ok %d\n", test_num); 4278dd83f1eSRebecca Cran kill(pid, SIGALRM); 4280fb57f87SRobert Watson close(connect_socket); 4298dd83f1eSRebecca Cran continue; 4308dd83f1eSRebecca Cran } 4310fb57f87SRobert Watson 4328dd83f1eSRebecca Cran if (send_test(connect_socket, tests[test_num-1]) != 0) { 4338dd83f1eSRebecca Cran printf("not ok %d\n", test_num); 4348dd83f1eSRebecca Cran kill(pid, SIGALRM); 4350fb57f87SRobert Watson close(connect_socket); 4368dd83f1eSRebecca Cran continue; 4378dd83f1eSRebecca Cran } 4380fb57f87SRobert Watson 4390fb57f87SRobert Watson close(connect_socket); 4408dd83f1eSRebecca Cran if (waitpid(pid, &status, 0) == pid) { 4418dd83f1eSRebecca Cran if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 4428dd83f1eSRebecca Cran printf("%s %d\n", "ok", test_num); 4438dd83f1eSRebecca Cran else 4448dd83f1eSRebecca Cran printf("%s %d\n", "not ok", test_num); 4458dd83f1eSRebecca Cran } 4468dd83f1eSRebecca Cran else { 4478dd83f1eSRebecca Cran printf("not ok %d\n", test_num); 4488dd83f1eSRebecca Cran } 4498dd83f1eSRebecca Cran } 4508dd83f1eSRebecca Cran } 4510fb57f87SRobert Watson 4528dd83f1eSRebecca Cran static void 4538dd83f1eSRebecca Cran cleanup(void) 4548dd83f1eSRebecca Cran { 455*b74bcac4SEnji Cooper 4568dd83f1eSRebecca Cran unlink(path); 4570fb57f87SRobert Watson } 4580fb57f87SRobert Watson 4590fb57f87SRobert Watson int 46076423e6eSPawel Jakub Dawidek main(int argc, char *argv[]) 4610fb57f87SRobert Watson { 4620fb57f87SRobert Watson int pagesize; 4630fb57f87SRobert Watson 464*b74bcac4SEnji Cooper path[0] = '\0'; 4658dd83f1eSRebecca Cran 4660fb57f87SRobert Watson pagesize = getpagesize(); 4670fb57f87SRobert Watson 46876423e6eSPawel Jakub Dawidek if (argc == 1) { 469*b74bcac4SEnji Cooper snprintf(path, sizeof(path), "sendfile.XXXXXXXXXXXX"); 4700fb57f87SRobert Watson file_fd = mkstemp(path); 47176423e6eSPawel Jakub Dawidek if (file_fd == -1) 47276423e6eSPawel Jakub Dawidek FAIL_ERR("mkstemp"); 47376423e6eSPawel Jakub Dawidek } else if (argc == 2) { 47476423e6eSPawel Jakub Dawidek (void)strlcpy(path, argv[1], sizeof(path)); 47576423e6eSPawel Jakub Dawidek file_fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600); 47676423e6eSPawel Jakub Dawidek if (file_fd == -1) 47776423e6eSPawel Jakub Dawidek FAIL_ERR("open"); 47876423e6eSPawel Jakub Dawidek } else { 47976423e6eSPawel Jakub Dawidek FAIL("usage: sendfile [path]"); 48076423e6eSPawel Jakub Dawidek } 48176423e6eSPawel Jakub Dawidek 4828dd83f1eSRebecca Cran atexit(cleanup); 4830fb57f87SRobert Watson 4840fb57f87SRobert Watson run_parent(); 4850fb57f87SRobert Watson return (0); 4860fb57f87SRobert Watson } 487