sendfile.c revision 168854
1158910Srwatson/*- 2158910Srwatson * Copyright (c) 2006 Robert N. M. Watson 3158910Srwatson * All rights reserved. 4158910Srwatson * 5158910Srwatson * Redistribution and use in source and binary forms, with or without 6158910Srwatson * modification, are permitted provided that the following conditions 7158910Srwatson * are met: 8158910Srwatson * 1. Redistributions of source code must retain the above copyright 9158910Srwatson * notice, this list of conditions and the following disclaimer. 10158910Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11158910Srwatson * notice, this list of conditions and the following disclaimer in the 12158910Srwatson * documentation and/or other materials provided with the distribution. 13158910Srwatson * 14158910Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15158910Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16158910Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17158910Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18158910Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19158910Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20158910Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21158910Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22158910Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23158910Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24158910Srwatson * SUCH DAMAGE. 25158910Srwatson * 26158910Srwatson * $FreeBSD: head/tools/regression/sockets/sendfile/sendfile.c 168854 2007-04-19 06:01:08Z pjd $ 27158910Srwatson */ 28158910Srwatson 29158910Srwatson#include <sys/types.h> 30158910Srwatson#include <sys/socket.h> 31168854Spjd#include <sys/stat.h> 32158910Srwatson 33158910Srwatson#include <netinet/in.h> 34158910Srwatson 35158910Srwatson#include <err.h> 36158910Srwatson#include <limits.h> 37158910Srwatson#include <signal.h> 38158910Srwatson#include <stdio.h> 39158910Srwatson#include <stdlib.h> 40158910Srwatson#include <string.h> 41158910Srwatson#include <unistd.h> 42158910Srwatson 43158910Srwatson/* 44158910Srwatson * Simple regression test for sendfile. Creates a file sized at three pages 45158910Srwatson * and then proceeds to send it over a series of sockets, exercising a number 46158910Srwatson * of cases and performing limited validation. 47158910Srwatson */ 48158910Srwatson 49158910Srwatson#define TEST_PORT 5678 50158910Srwatson#define TEST_MAGIC 0x4440f7bb 51168854Spjd#define TEST_PAGES 4 52158910Srwatson#define TEST_SECONDS 30 53158910Srwatson 54158910Srwatsonstruct test_header { 55158910Srwatson u_int32_t th_magic; 56158910Srwatson u_int32_t th_header_length; 57158910Srwatson u_int32_t th_offset; 58158910Srwatson u_int32_t th_length; 59158910Srwatson}; 60158910Srwatson 61158910Srwatsonpid_t child_pid, parent_pid; 62158910Srwatsonint listen_socket; 63158910Srwatsonint file_fd; 64158910Srwatson 65158910Srwatsonstatic int 66158910Srwatsontest_th(struct test_header *th, u_int32_t *header_length, u_int32_t *offset, 67158910Srwatson u_int32_t *length) 68158910Srwatson{ 69158910Srwatson 70158910Srwatson if (th->th_magic != htonl(TEST_MAGIC)) 71158910Srwatson return (0); 72158910Srwatson *header_length = ntohl(th->th_header_length); 73158910Srwatson *offset = ntohl(th->th_offset); 74158910Srwatson *length = ntohl(th->th_length); 75158910Srwatson return (1); 76158910Srwatson} 77158910Srwatson 78158910Srwatsonstatic void 79158910Srwatsonsignal_alarm(int signum) 80158910Srwatson{ 81158910Srwatson 82158910Srwatson} 83158910Srwatson 84158910Srwatsonstatic void 85158910Srwatsonsetup_alarm(int seconds) 86158910Srwatson{ 87158910Srwatson 88158910Srwatson signal(SIGALRM, signal_alarm); 89158910Srwatson alarm(seconds); 90158910Srwatson} 91158910Srwatson 92158910Srwatsonstatic void 93158910Srwatsoncancel_alarm(void) 94158910Srwatson{ 95158910Srwatson 96158910Srwatson alarm(0); 97158910Srwatson signal(SIGALRM, SIG_DFL); 98158910Srwatson} 99158910Srwatson 100158910Srwatsonstatic void 101158910Srwatsonreceive_test(int accept_socket) 102158910Srwatson{ 103158910Srwatson u_int32_t header_length, offset, length, counter; 104158910Srwatson struct test_header th; 105158910Srwatson ssize_t len; 106158910Srwatson char ch; 107158910Srwatson 108158910Srwatson len = read(accept_socket, &th, sizeof(th)); 109158910Srwatson if (len < 0) 110158910Srwatson err(-1, "read"); 111158910Srwatson if (len < sizeof(th)) 112158910Srwatson errx(-1, "read: %d", len); 113158910Srwatson 114158910Srwatson if (test_th(&th, &header_length, &offset, &length) == 0) 115158910Srwatson errx(-1, "test_th: bad"); 116158910Srwatson 117158910Srwatson counter = 0; 118158910Srwatson while (1) { 119158910Srwatson len = read(accept_socket, &ch, sizeof(ch)); 120158910Srwatson if (len < 0) 121158910Srwatson err(-1, "read"); 122158910Srwatson if (len == 0) 123158910Srwatson break; 124158910Srwatson counter++; 125158910Srwatson /* XXXRW: Validate byte here. */ 126158910Srwatson } 127158910Srwatson if (counter != header_length + length) 128158910Srwatson errx(-1, "receive_test: expected (%d, %d) received %d", 129158910Srwatson header_length, length, counter); 130158910Srwatson} 131158910Srwatson 132158910Srwatsonstatic void 133158910Srwatsonrun_child(void) 134158910Srwatson{ 135158910Srwatson int accept_socket; 136158910Srwatson 137158910Srwatson while (1) { 138158910Srwatson accept_socket = accept(listen_socket, NULL, NULL); 139158910Srwatson setup_alarm(TEST_SECONDS); 140158910Srwatson receive_test(accept_socket); 141158910Srwatson cancel_alarm(); 142158910Srwatson close(accept_socket); 143158910Srwatson } 144158910Srwatson} 145158910Srwatson 146158910Srwatsonstatic int 147158910Srwatsonnew_test_socket(void) 148158910Srwatson{ 149158910Srwatson struct sockaddr_in sin; 150158910Srwatson int connect_socket; 151158910Srwatson 152158910Srwatson connect_socket = socket(PF_INET, SOCK_STREAM, 0); 153158910Srwatson if (connect_socket < 0) 154158910Srwatson err(-1, "socket"); 155158910Srwatson 156158910Srwatson bzero(&sin, sizeof(sin)); 157158910Srwatson sin.sin_len = sizeof(sin); 158158910Srwatson sin.sin_family = AF_INET; 159158910Srwatson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 160158910Srwatson sin.sin_port = htons(TEST_PORT); 161158910Srwatson 162158910Srwatson if (connect(connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) 163158910Srwatson err(-1, "connect"); 164158910Srwatson 165158910Srwatson return (connect_socket); 166158910Srwatson} 167158910Srwatson 168158910Srwatsonstatic void 169158910Srwatsoninit_th(struct test_header *th, u_int32_t header_length, u_int32_t offset, 170158910Srwatson u_int32_t length) 171158910Srwatson{ 172158910Srwatson 173158910Srwatson bzero(th, sizeof(*th)); 174158910Srwatson th->th_magic = htonl(TEST_MAGIC); 175158910Srwatson th->th_header_length = htonl(header_length); 176158910Srwatson th->th_offset = htonl(offset); 177158910Srwatson th->th_length = htonl(length); 178158910Srwatson} 179158910Srwatson 180158910Srwatsonstatic void 181158910Srwatsonsend_test(int connect_socket, u_int32_t header_length, u_int32_t offset, 182158910Srwatson u_int32_t length) 183158910Srwatson{ 184158910Srwatson struct test_header th; 185158910Srwatson struct sf_hdtr hdtr, *hdtrp; 186158910Srwatson struct iovec headers; 187158910Srwatson char *header; 188158910Srwatson ssize_t len; 189158910Srwatson off_t off; 190158910Srwatson 191158910Srwatson len = lseek(file_fd, 0, SEEK_SET); 192158910Srwatson if (len < 0) 193158910Srwatson err(-1, "lseek"); 194158910Srwatson if (len != 0) 195158910Srwatson errx(-1, "lseek: %d", len); 196158910Srwatson 197158910Srwatson init_th(&th, header_length, offset, length); 198158910Srwatson 199158910Srwatson len = write(connect_socket, &th, sizeof(th)); 200158910Srwatson if (len < 0) 201158910Srwatson err(-1, "send"); 202158910Srwatson if (len != sizeof(th)) 203158910Srwatson err(-1, "send: %d", len); 204158910Srwatson 205158910Srwatson if (header_length != 0) { 206158910Srwatson header = malloc(header_length); 207158910Srwatson if (header == NULL) 208158910Srwatson err(-1, "malloc"); 209158910Srwatson hdtrp = &hdtr; 210158910Srwatson bzero(&headers, sizeof(headers)); 211158910Srwatson headers.iov_base = header; 212158910Srwatson headers.iov_len = header_length; 213158910Srwatson bzero(&hdtr, sizeof(hdtr)); 214158910Srwatson hdtr.headers = &headers; 215158910Srwatson hdtr.hdr_cnt = 1; 216158910Srwatson hdtr.trailers = NULL; 217158910Srwatson hdtr.trl_cnt = 0; 218158910Srwatson } else { 219158910Srwatson hdtrp = NULL; 220158910Srwatson header = NULL; 221158910Srwatson } 222158910Srwatson 223158910Srwatson if (sendfile(file_fd, connect_socket, offset, length, hdtrp, &off, 224158910Srwatson 0) < 0) 225158910Srwatson err(-1, "sendfile"); 226158910Srwatson 227168854Spjd if (length == 0) { 228168854Spjd struct stat sb; 229158910Srwatson 230168854Spjd if (fstat(file_fd, &sb) < 0) 231168854Spjd err(-1, "fstat"); 232168854Spjd length = sb.st_size; 233168854Spjd } 234168854Spjd 235168854Spjd if (off != length) { 236168854Spjd errx(-1, "sendfile: off(%llu) != length(%llu)", off, 237168854Spjd (unsigned long long)length); 238168854Spjd } 239168854Spjd 240158910Srwatson if (header != NULL) 241158910Srwatson free(header); 242158910Srwatson} 243158910Srwatson 244158910Srwatsonstatic void 245158910Srwatsonrun_parent(void) 246158910Srwatson{ 247158910Srwatson int connect_socket; 248158910Srwatson 249158910Srwatson connect_socket = new_test_socket(); 250158910Srwatson send_test(connect_socket, 0, 0, 1); 251158910Srwatson close(connect_socket); 252158910Srwatson 253158910Srwatson sleep(1); 254158910Srwatson 255158910Srwatson connect_socket = new_test_socket(); 256158910Srwatson send_test(connect_socket, 0, 0, getpagesize()); 257158910Srwatson close(connect_socket); 258158910Srwatson 259158910Srwatson sleep(1); 260158910Srwatson 261158910Srwatson connect_socket = new_test_socket(); 262158910Srwatson send_test(connect_socket, 0, 1, 1); 263158910Srwatson close(connect_socket); 264158910Srwatson 265158910Srwatson sleep(1); 266158910Srwatson 267158910Srwatson connect_socket = new_test_socket(); 268158910Srwatson send_test(connect_socket, 0, 1, getpagesize()); 269158910Srwatson close(connect_socket); 270158910Srwatson 271158910Srwatson sleep(1); 272158910Srwatson 273158910Srwatson connect_socket = new_test_socket(); 274158910Srwatson send_test(connect_socket, 0, getpagesize(), getpagesize()); 275158910Srwatson close(connect_socket); 276158910Srwatson 277158910Srwatson sleep(1); 278158910Srwatson 279168854Spjd connect_socket = new_test_socket(); 280168854Spjd send_test(connect_socket, 0, 0, 2 * getpagesize()); 281168854Spjd close(connect_socket); 282168854Spjd 283168854Spjd sleep(1); 284168854Spjd 285168854Spjd connect_socket = new_test_socket(); 286168854Spjd send_test(connect_socket, 0, 0, 0); 287168854Spjd close(connect_socket); 288168854Spjd 289168854Spjd sleep(1); 290168854Spjd 291168854Spjd connect_socket = new_test_socket(); 292168854Spjd send_test(connect_socket, 0, getpagesize(), 0); 293168854Spjd close(connect_socket); 294168854Spjd 295168854Spjd sleep(1); 296168854Spjd 297168854Spjd connect_socket = new_test_socket(); 298168854Spjd send_test(connect_socket, 0, 2 * getpagesize(), 0); 299168854Spjd close(connect_socket); 300168854Spjd 301168854Spjd sleep(1); 302168854Spjd 303158910Srwatson (void)kill(child_pid, SIGKILL); 304158910Srwatson} 305158910Srwatson 306158910Srwatsonint 307158910Srwatsonmain(int argc, char *argv[]) 308158910Srwatson{ 309158910Srwatson char path[PATH_MAX], *page_buffer; 310158910Srwatson struct sockaddr_in sin; 311158910Srwatson int pagesize; 312158910Srwatson ssize_t len; 313158910Srwatson 314158910Srwatson pagesize = getpagesize(); 315158910Srwatson page_buffer = malloc(TEST_PAGES * pagesize); 316158910Srwatson if (page_buffer == NULL) 317158910Srwatson err(-1, "malloc"); 318158910Srwatson bzero(page_buffer, TEST_PAGES * pagesize); 319158910Srwatson 320158910Srwatson listen_socket = socket(PF_INET, SOCK_STREAM, 0); 321158910Srwatson if (listen_socket < 0) 322158910Srwatson err(-1, "socket"); 323158910Srwatson 324158910Srwatson bzero(&sin, sizeof(sin)); 325158910Srwatson sin.sin_len = sizeof(sin); 326158910Srwatson sin.sin_family = AF_INET; 327158910Srwatson sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 328158910Srwatson sin.sin_port = htons(TEST_PORT); 329158910Srwatson 330158910Srwatson snprintf(path, PATH_MAX, "/tmp/sendfile.XXXXXXXXXXXX"); 331158910Srwatson file_fd = mkstemp(path); 332158910Srwatson (void)unlink(path); 333158910Srwatson 334158910Srwatson len = write(file_fd, page_buffer, TEST_PAGES * pagesize); 335158910Srwatson if (len < 0) 336158910Srwatson err(-1, "write"); 337158910Srwatson 338158910Srwatson len = lseek(file_fd, 0, SEEK_SET); 339158910Srwatson if (len < 0) 340158910Srwatson err(-1, "lseek"); 341158910Srwatson if (len != 0) 342158910Srwatson errx(-1, "lseek: %d", len); 343158910Srwatson 344158910Srwatson if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) 345158910Srwatson err(-1, "bind"); 346158910Srwatson 347158910Srwatson if (listen(listen_socket, -1) < 0) 348158910Srwatson err(-1, "listen"); 349158910Srwatson 350158910Srwatson parent_pid = getpid(); 351158910Srwatson child_pid = fork(); 352158910Srwatson if (child_pid < 0) 353158910Srwatson err(-1, "fork"); 354158910Srwatson if (child_pid == 0) { 355158910Srwatson child_pid = getpid(); 356158910Srwatson run_child(); 357158910Srwatson } else 358158910Srwatson run_parent(); 359158910Srwatson 360158910Srwatson return (0); 361158910Srwatson} 362