1 /*- 2 * Copyright (c) 2018 Enji Cooper. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/mman.h> 32 #include <sys/socket.h> 33 #include <sys/stat.h> 34 #include <sys/sysctl.h> 35 #include <sys/uio.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <netdb.h> 40 #include <paths.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include <atf-c.h> 47 48 const char DETERMINISTIC_PATTERN[] = 49 "The past is already gone, the future is not yet here. There's only one moment for you to live.\n"; 50 51 #define SOURCE_FILE "source" 52 #define DESTINATION_FILE "dest" 53 54 #define PORTRANGE_FIRST "net.inet.ip.portrange.first" 55 #define PORTRANGE_LAST "net.inet.ip.portrange.last" 56 57 static int portrange_first, portrange_last; 58 59 static int 60 get_int_via_sysctlbyname(const char *oidname) 61 { 62 size_t oldlen; 63 int int_value; 64 65 ATF_REQUIRE_EQ_MSG(sysctlbyname(oidname, &int_value, &oldlen, NULL, 0), 66 0, "sysctlbyname(%s, ...) failed: %s", oidname, strerror(errno)); 67 ATF_REQUIRE_EQ_MSG(sizeof(int_value), oldlen, "sanity check failed"); 68 69 return (int_value); 70 } 71 72 static int 73 generate_random_port(int seed) 74 { 75 int random_port; 76 77 printf("Generating a random port with seed=%d\n", seed); 78 if (portrange_first == 0) { 79 portrange_first = get_int_via_sysctlbyname(PORTRANGE_FIRST); 80 printf("Port range lower bound: %d\n", portrange_first); 81 } 82 83 if (portrange_last == 0) { 84 portrange_last = get_int_via_sysctlbyname(PORTRANGE_LAST); 85 printf("Port range upper bound: %d\n", portrange_last); 86 } 87 88 srand((unsigned)seed); 89 90 random_port = rand() % (portrange_last - portrange_first) + 91 portrange_first; 92 93 printf("Random port generated: %d\n", random_port); 94 return (random_port); 95 } 96 97 static void 98 resolve_localhost(struct addrinfo **res, int domain, int type, int port) 99 { 100 const char *host; 101 char *serv; 102 struct addrinfo hints; 103 int error; 104 105 switch (domain) { 106 case AF_INET: 107 host = "127.0.0.1"; 108 break; 109 case AF_INET6: 110 host = "::1"; 111 break; 112 default: 113 atf_tc_fail("unhandled domain: %d", domain); 114 } 115 116 ATF_REQUIRE_MSG(asprintf(&serv, "%d", port) >= 0, 117 "asprintf failed: %s", strerror(errno)); 118 119 memset(&hints, 0, sizeof(hints)); 120 hints.ai_family = domain; 121 hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV|AI_NUMERICHOST; 122 hints.ai_socktype = type; 123 124 error = getaddrinfo(host, serv, &hints, res); 125 ATF_REQUIRE_EQ_MSG(error, 0, 126 "getaddrinfo failed: %s", gai_strerror(error)); 127 free(serv); 128 } 129 130 static int 131 make_socket(int domain, int type, int protocol) 132 { 133 int sock; 134 135 sock = socket(domain, type, protocol); 136 ATF_REQUIRE_MSG(sock != -1, "socket(%d, %d, 0) failed: %s", 137 domain, type, strerror(errno)); 138 139 return (sock); 140 } 141 142 static int 143 setup_client(int domain, int type, int port) 144 { 145 struct addrinfo *res; 146 char host[NI_MAXHOST+1]; 147 int error, sock; 148 149 resolve_localhost(&res, domain, type, port); 150 error = getnameinfo( 151 (const struct sockaddr*)res->ai_addr, res->ai_addrlen, 152 host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST); 153 ATF_REQUIRE_EQ_MSG(error, 0, 154 "getnameinfo failed: %s", gai_strerror(error)); 155 printf( 156 "Will try to connect to host='%s', address_family=%d, " 157 "socket_type=%d\n", 158 host, res->ai_family, res->ai_socktype); 159 /* Avoid a double print when forked by flushing. */ 160 fflush(stdout); 161 sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol); 162 error = connect(sock, (struct sockaddr*)res->ai_addr, res->ai_addrlen); 163 freeaddrinfo(res); 164 ATF_REQUIRE_EQ_MSG(error, 0, "connect failed: %s", strerror(errno)); 165 return (sock); 166 } 167 168 /* 169 * XXX: use linear probing to find a free port and eliminate `port` argument as 170 * a [const] int (it will need to be a pointer so it can be passed back out of 171 * the function and can influence which port `setup_client(..)` connects on. 172 */ 173 static int 174 setup_server(int domain, int type, int port) 175 { 176 struct addrinfo *res; 177 char host[NI_MAXHOST+1]; 178 int error, sock; 179 180 resolve_localhost(&res, domain, type, port); 181 sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol); 182 183 error = getnameinfo( 184 (const struct sockaddr*)res->ai_addr, res->ai_addrlen, 185 host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST); 186 ATF_REQUIRE_EQ_MSG(error, 0, 187 "getnameinfo failed: %s", gai_strerror(error)); 188 printf( 189 "Will try to bind socket to host='%s', address_family=%d, " 190 "socket_type=%d\n", 191 host, res->ai_family, res->ai_socktype); 192 /* Avoid a double print when forked by flushing. */ 193 fflush(stdout); 194 error = bind(sock, res->ai_addr, res->ai_addrlen); 195 freeaddrinfo(res); 196 ATF_REQUIRE_EQ_MSG(error, 0, "bind failed: %s", strerror(errno)); 197 error = listen(sock, 1); 198 ATF_REQUIRE_EQ_MSG(error, 0, "listen failed: %s", strerror(errno)); 199 200 return (sock); 201 } 202 203 /* 204 * This function is a helper routine for taking data being sent by `sendfile` via 205 * `server_sock`, and pushing the received stream out to a file, denoted by 206 * `dest_filename`. 207 */ 208 static void 209 server_cat(const char *dest_filename, int server_sock, size_t len) 210 { 211 char *buffer, *buf_window_ptr; 212 int recv_sock; 213 size_t buffer_size; 214 ssize_t received_bytes, recv_ret; 215 216 /* 217 * Ensure that there isn't excess data sent across the wire by 218 * capturing 10 extra bytes (plus 1 for nul). 219 */ 220 buffer_size = len + 10 + 1; 221 buffer = calloc(buffer_size, sizeof(char)); 222 if (buffer == NULL) 223 err(1, "malloc failed"); 224 225 recv_sock = accept(server_sock, NULL, 0); 226 if (recv_sock == -1) 227 err(1, "accept failed"); 228 229 buf_window_ptr = buffer; 230 received_bytes = 0; 231 do { 232 recv_ret = recv(recv_sock, buf_window_ptr, 233 buffer_size - received_bytes, 0); 234 if (recv_ret <= 0) 235 break; 236 buf_window_ptr += recv_ret; 237 received_bytes += recv_ret; 238 } while (received_bytes < buffer_size); 239 240 atf_utils_create_file(dest_filename, "%s", buffer); 241 242 (void)close(recv_sock); 243 (void)close(server_sock); 244 free(buffer); 245 246 if (received_bytes != len) 247 errx(1, "received unexpected data: %zd != %zd", received_bytes, 248 len); 249 } 250 251 static int 252 setup_tcp_server(int domain, int port) 253 { 254 255 return (setup_server(domain, SOCK_STREAM, port)); 256 } 257 258 static int 259 setup_tcp_client(int domain, int port) 260 { 261 262 return (setup_client(domain, SOCK_STREAM, port)); 263 } 264 265 static off_t 266 file_size_from_fd(int fd) 267 { 268 struct stat st; 269 270 ATF_REQUIRE_EQ_MSG(0, fstat(fd, &st), 271 "fstat failed: %s", strerror(errno)); 272 273 return (st.st_size); 274 } 275 276 /* 277 * NB: `nbytes` == 0 has special connotations given the sendfile(2) API 278 * contract. In short, "send the whole file" (paraphrased). 279 */ 280 static void 281 verify_source_and_dest(const char* dest_filename, int src_fd, off_t offset, 282 size_t nbytes) 283 { 284 char *dest_pointer, *src_pointer; 285 off_t dest_file_size, src_file_size; 286 size_t length; 287 int dest_fd; 288 289 atf_utils_cat_file(dest_filename, "dest_file: "); 290 291 dest_fd = open(dest_filename, O_RDONLY); 292 ATF_REQUIRE_MSG(dest_fd != -1, "open failed"); 293 294 dest_file_size = file_size_from_fd(dest_fd); 295 src_file_size = file_size_from_fd(src_fd); 296 297 /* 298 * Per sendfile(2), "send the whole file" (paraphrased). This means 299 * that we need to grab the file size, as passing in length = 0 with 300 * mmap(2) will result in a failure with EINVAL (length = 0 is invalid). 301 */ 302 length = (nbytes == 0) ? (size_t)(src_file_size - offset) : nbytes; 303 304 ATF_REQUIRE_EQ_MSG(dest_file_size, length, 305 "number of bytes written out to %s (%ju) doesn't match the " 306 "expected number of bytes (%zu)", dest_filename, dest_file_size, 307 length); 308 309 ATF_REQUIRE_EQ_MSG(0, lseek(src_fd, offset, SEEK_SET), 310 "lseek failed: %s", strerror(errno)); 311 312 dest_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, dest_fd, 0); 313 ATF_REQUIRE_MSG(dest_pointer != MAP_FAILED, "mmap failed: %s", 314 strerror(errno)); 315 316 printf("Will mmap in the source file from offset=%jd to length=%zu\n", 317 offset, length); 318 319 src_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, src_fd, offset); 320 ATF_REQUIRE_MSG(src_pointer != MAP_FAILED, "mmap failed: %s", 321 strerror(errno)); 322 323 ATF_REQUIRE_EQ_MSG(0, memcmp(src_pointer, dest_pointer, length), 324 "Contents of source and destination do not match. '%s' != '%s'", 325 src_pointer, dest_pointer); 326 327 (void)munmap(src_pointer, length); 328 (void)munmap(dest_pointer, length); 329 (void)close(dest_fd); 330 } 331 332 static void 333 fd_positive_file_test(int domain) 334 { 335 off_t offset; 336 size_t nbytes, pattern_size; 337 int client_sock, error, fd, port, server_sock; 338 pid_t server_pid; 339 340 pattern_size = strlen(DETERMINISTIC_PATTERN); 341 342 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN); 343 fd = open(SOURCE_FILE, O_RDONLY); 344 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 345 346 port = generate_random_port(__LINE__ + domain); 347 server_sock = setup_tcp_server(domain, port); 348 client_sock = setup_tcp_client(domain, port); 349 350 server_pid = atf_utils_fork(); 351 if (server_pid == 0) { 352 (void)close(client_sock); 353 server_cat(DESTINATION_FILE, server_sock, pattern_size); 354 _exit(0); 355 } else 356 (void)close(server_sock); 357 358 nbytes = 0; 359 offset = 0; 360 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL, 361 SF_FLAGS(0, 0)); 362 ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno)); 363 (void)close(client_sock); 364 365 atf_utils_wait(server_pid, 0, "", ""); 366 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes); 367 368 (void)close(fd); 369 } 370 371 ATF_TC(fd_positive_file_v4); 372 ATF_TC_HEAD(fd_positive_file_v4, tc) 373 { 374 375 atf_tc_set_md_var(tc, "descr", 376 "Verify regular file as file descriptor support (IPv4)"); 377 } 378 ATF_TC_BODY(fd_positive_file_v4, tc) 379 { 380 381 fd_positive_file_test(AF_INET); 382 } 383 384 ATF_TC(fd_positive_file_v6); 385 ATF_TC_HEAD(fd_positive_file_v6, tc) 386 { 387 388 atf_tc_set_md_var(tc, "descr", 389 "Verify regular file as file descriptor support (IPv6)"); 390 } 391 ATF_TC_BODY(fd_positive_file_v6, tc) 392 { 393 394 fd_positive_file_test(AF_INET6); 395 } 396 397 static void 398 fd_positive_shm_test(int domain) 399 { 400 char *shm_pointer; 401 off_t offset; 402 size_t nbytes, pattern_size; 403 pid_t server_pid; 404 int client_sock, error, fd, port, server_sock; 405 406 pattern_size = strlen(DETERMINISTIC_PATTERN); 407 408 printf("pattern size: %zu\n", pattern_size); 409 410 fd = shm_open(SHM_ANON, O_RDWR|O_CREAT, 0600); 411 ATF_REQUIRE_MSG(fd != -1, "shm_open failed: %s", strerror(errno)); 412 ATF_REQUIRE_EQ_MSG(0, ftruncate(fd, pattern_size), 413 "ftruncate failed: %s", strerror(errno)); 414 shm_pointer = mmap(NULL, pattern_size, PROT_READ|PROT_WRITE, 415 MAP_SHARED, fd, 0); 416 ATF_REQUIRE_MSG(shm_pointer != MAP_FAILED, 417 "mmap failed: %s", strerror(errno)); 418 memcpy(shm_pointer, DETERMINISTIC_PATTERN, pattern_size); 419 ATF_REQUIRE_EQ_MSG(0, 420 memcmp(shm_pointer, DETERMINISTIC_PATTERN, pattern_size), 421 "memcmp showed data mismatch: '%s' != '%s'", 422 DETERMINISTIC_PATTERN, shm_pointer); 423 424 port = generate_random_port(__LINE__ + domain); 425 server_sock = setup_tcp_server(domain, port); 426 client_sock = setup_tcp_client(domain, port); 427 428 server_pid = atf_utils_fork(); 429 if (server_pid == 0) { 430 (void)close(client_sock); 431 server_cat(DESTINATION_FILE, server_sock, pattern_size); 432 _exit(0); 433 } else 434 (void)close(server_sock); 435 436 nbytes = 0; 437 offset = 0; 438 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL, 439 SF_FLAGS(0, 0)); 440 ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno)); 441 (void)close(client_sock); 442 443 atf_utils_wait(server_pid, 0, "", ""); 444 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes); 445 446 (void)munmap(shm_pointer, sizeof(DETERMINISTIC_PATTERN)); 447 (void)close(fd); 448 } 449 450 ATF_TC(fd_positive_shm_v4); 451 ATF_TC_HEAD(fd_positive_shm_v4, tc) 452 { 453 454 atf_tc_set_md_var(tc, "descr", 455 "Verify shared memory as file descriptor support (IPv4)"); 456 } 457 ATF_TC_BODY(fd_positive_shm_v4, tc) 458 { 459 460 fd_positive_shm_test(AF_INET); 461 } 462 463 ATF_TC(fd_positive_shm_v6); 464 ATF_TC_HEAD(fd_positive_shm_v6, tc) 465 { 466 467 atf_tc_set_md_var(tc, "descr", 468 "Verify shared memory as file descriptor support (IPv6))"); 469 } 470 ATF_TC_BODY(fd_positive_shm_v6, tc) 471 { 472 473 fd_positive_shm_test(AF_INET6); 474 } 475 476 static void 477 fd_negative_bad_fd_test(int domain) 478 { 479 int client_sock, error, fd, port, server_sock; 480 481 port = generate_random_port(__LINE__ + domain); 482 server_sock = setup_tcp_server(domain, port); 483 client_sock = setup_tcp_client(domain, port); 484 485 fd = -1; 486 487 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0)); 488 ATF_REQUIRE_ERRNO(EBADF, error == -1); 489 490 (void)close(client_sock); 491 (void)close(server_sock); 492 } 493 494 ATF_TC(fd_negative_bad_fd_v4); 495 ATF_TC_HEAD(fd_negative_bad_fd_v4, tc) 496 { 497 498 atf_tc_set_md_var(tc, "descr", 499 "Verify bad file descriptor returns EBADF (IPv4)"); 500 } 501 ATF_TC_BODY(fd_negative_bad_fd_v4, tc) 502 { 503 504 fd_negative_bad_fd_test(AF_INET); 505 } 506 507 ATF_TC(fd_negative_bad_fd_v6); 508 ATF_TC_HEAD(fd_negative_bad_fd_v6, tc) 509 { 510 511 atf_tc_set_md_var(tc, "descr", 512 "Verify bad file descriptor returns EBADF (IPv6)"); 513 } 514 ATF_TC_BODY(fd_negative_bad_fd_v6, tc) 515 { 516 517 fd_negative_bad_fd_test(AF_INET6); 518 } 519 520 static void 521 flags_test(int domain) 522 { 523 off_t offset; 524 size_t nbytes, pattern_size; 525 int client_sock, error, fd, i, port, server_sock; 526 pid_t server_pid; 527 int16_t number_pages = 10; 528 529 pattern_size = strlen(DETERMINISTIC_PATTERN); 530 531 struct testcase { 532 int16_t readahead_pages, flags; 533 } testcases[] = { 534 /* This is covered in `:fd_positive_file` */ 535 #if 0 536 { 537 .readahead_pages = 0, 538 .flags = 0 539 }, 540 #endif 541 { 542 .readahead_pages = 0, 543 .flags = SF_NOCACHE 544 }, 545 #ifdef SF_USER_READAHEAD 546 { 547 .readahead_pages = 0, 548 .flags = SF_NOCACHE|SF_USER_READAHEAD 549 }, 550 { 551 .readahead_pages = 0, 552 .flags = SF_USER_READAHEAD 553 }, 554 #endif 555 { 556 .readahead_pages = number_pages, 557 .flags = 0 558 }, 559 { 560 .readahead_pages = number_pages, 561 .flags = SF_NOCACHE 562 }, 563 #ifdef SF_USER_READAHEAD 564 { 565 .readahead_pages = number_pages, 566 .flags = SF_NOCACHE|SF_USER_READAHEAD 567 }, 568 #endif 569 { 570 .readahead_pages = number_pages, 571 .flags = SF_NOCACHE 572 }, 573 { 574 .readahead_pages = number_pages, 575 .flags = SF_NODISKIO 576 } 577 }; 578 579 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN); 580 for (i = 0; i < nitems(testcases); i++) { 581 fd = open(SOURCE_FILE, O_RDONLY); 582 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 583 584 port = generate_random_port(i * __LINE__ + domain); 585 server_sock = setup_tcp_server(domain, port); 586 client_sock = setup_tcp_client(domain, port); 587 588 server_pid = atf_utils_fork(); 589 if (server_pid == 0) { 590 (void)close(client_sock); 591 server_cat(DESTINATION_FILE, server_sock, pattern_size); 592 _exit(0); 593 } else 594 (void)close(server_sock); 595 596 nbytes = 0; 597 offset = 0; 598 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL, 599 SF_FLAGS(testcases[i].readahead_pages, testcases[i].flags)); 600 ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s", 601 i, strerror(errno)); 602 (void)close(client_sock); 603 604 atf_utils_wait(server_pid, 0, "", ""); 605 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes); 606 607 (void)close(fd); 608 } 609 } 610 611 ATF_TC(flags_v4); 612 ATF_TC_HEAD(flags_v4, tc) 613 { 614 615 atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv4)"); 616 } 617 ATF_TC_BODY(flags_v4, tc) 618 { 619 620 flags_test(AF_INET); 621 } 622 623 ATF_TC(flags_v6); 624 ATF_TC_HEAD(flags_v6, tc) 625 { 626 627 atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv6)"); 628 } 629 ATF_TC_BODY(flags_v6, tc) 630 { 631 632 flags_test(AF_INET6); 633 } 634 635 static void 636 hdtr_positive_test(int domain) 637 { 638 struct iovec headers[1], trailers[1]; 639 struct testcase { 640 bool include_headers, include_trailers; 641 } testcases[] = { 642 /* This is covered in `:fd_positive_file` */ 643 #if 0 644 { 645 .include_headers = false, 646 .include_trailers = false 647 }, 648 #endif 649 { 650 .include_headers = true, 651 .include_trailers = false 652 }, 653 { 654 .include_headers = false, 655 .include_trailers = true 656 }, 657 { 658 .include_headers = true, 659 .include_trailers = true 660 } 661 }; 662 off_t offset; 663 size_t nbytes; 664 int client_sock, error, fd, fd2, i, port, rc, server_sock; 665 pid_t server_pid; 666 667 headers[0].iov_base = "This is a header"; 668 headers[0].iov_len = strlen(headers[0].iov_base); 669 trailers[0].iov_base = "This is a trailer"; 670 trailers[0].iov_len = strlen(trailers[0].iov_base); 671 offset = 0; 672 nbytes = 0; 673 674 for (i = 0; i < nitems(testcases); i++) { 675 struct sf_hdtr hdtr; 676 char *pattern; 677 678 if (testcases[i].include_headers) { 679 hdtr.headers = headers; 680 hdtr.hdr_cnt = nitems(headers); 681 } else { 682 hdtr.headers = NULL; 683 hdtr.hdr_cnt = 0; 684 } 685 686 if (testcases[i].include_trailers) { 687 hdtr.trailers = trailers; 688 hdtr.trl_cnt = nitems(trailers); 689 } else { 690 hdtr.trailers = NULL; 691 hdtr.trl_cnt = 0; 692 } 693 694 port = generate_random_port(i * __LINE__ + domain); 695 server_sock = setup_tcp_server(domain, port); 696 client_sock = setup_tcp_client(domain, port); 697 698 rc = asprintf(&pattern, "%s%s%s", 699 testcases[i].include_headers ? (char *)headers[0].iov_base : "", 700 DETERMINISTIC_PATTERN, 701 testcases[i].include_trailers ? (char *)trailers[0].iov_base : ""); 702 ATF_REQUIRE_MSG(rc != -1, "asprintf failed: %s", strerror(errno)); 703 704 atf_utils_create_file(SOURCE_FILE ".full", "%s", pattern); 705 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN); 706 707 fd = open(SOURCE_FILE, O_RDONLY); 708 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 709 710 fd2 = open(SOURCE_FILE ".full", O_RDONLY); 711 ATF_REQUIRE_MSG(fd2 != -1, "open failed: %s", strerror(errno)); 712 713 server_pid = atf_utils_fork(); 714 if (server_pid == 0) { 715 (void)close(client_sock); 716 server_cat(DESTINATION_FILE, server_sock, 717 strlen(pattern)); 718 _exit(0); 719 } else 720 (void)close(server_sock); 721 722 error = sendfile(fd, client_sock, offset, nbytes, &hdtr, 723 NULL, SF_FLAGS(0, 0)); 724 ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s", 725 i, strerror(errno)); 726 (void)close(client_sock); 727 728 atf_utils_wait(server_pid, 0, "", ""); 729 verify_source_and_dest(DESTINATION_FILE, fd2, offset, nbytes); 730 731 (void)close(fd); 732 (void)close(fd2); 733 free(pattern); 734 pattern = NULL; 735 } 736 } 737 738 ATF_TC(hdtr_positive_v4); 739 ATF_TC_HEAD(hdtr_positive_v4, tc) 740 { 741 742 atf_tc_set_md_var(tc, "descr", 743 "Verify positive hdtr functionality (IPv4)"); 744 } 745 ATF_TC_BODY(hdtr_positive_v4, tc) 746 { 747 748 hdtr_positive_test(AF_INET); 749 } 750 751 ATF_TC(hdtr_positive_v6); 752 ATF_TC_HEAD(hdtr_positive_v6, tc) 753 { 754 755 atf_tc_set_md_var(tc, "descr", 756 "Verify positive hdtr functionality (IPv6)"); 757 } 758 ATF_TC_BODY(hdtr_positive_v6, tc) 759 { 760 761 hdtr_positive_test(AF_INET); 762 } 763 764 static void 765 hdtr_negative_bad_pointers_test(int domain) 766 { 767 int client_sock, error, fd, port, server_sock; 768 struct sf_hdtr *hdtr1, hdtr2, hdtr3; 769 770 port = generate_random_port(__LINE__ + domain); 771 772 hdtr1 = (struct sf_hdtr*)-1; 773 774 memset(&hdtr2, 0, sizeof(hdtr2)); 775 hdtr2.hdr_cnt = 1; 776 hdtr2.headers = (struct iovec*)-1; 777 778 memset(&hdtr3, 0, sizeof(hdtr3)); 779 hdtr3.trl_cnt = 1; 780 hdtr3.trailers = (struct iovec*)-1; 781 782 fd = open(SOURCE_FILE, O_CREAT|O_RDWR); 783 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 784 785 server_sock = setup_tcp_server(domain, port); 786 client_sock = setup_tcp_client(domain, port); 787 788 error = sendfile(fd, client_sock, 0, 0, hdtr1, NULL, SF_FLAGS(0, 0)); 789 ATF_CHECK_ERRNO(EFAULT, error == -1); 790 791 error = sendfile(fd, client_sock, 0, 0, &hdtr2, NULL, SF_FLAGS(0, 0)); 792 ATF_CHECK_ERRNO(EFAULT, error == -1); 793 794 error = sendfile(fd, client_sock, 0, 0, &hdtr3, NULL, SF_FLAGS(0, 0)); 795 ATF_CHECK_ERRNO(EFAULT, error == -1); 796 797 (void)close(fd); 798 (void)close(client_sock); 799 (void)close(server_sock); 800 } 801 802 ATF_TC(hdtr_negative_bad_pointers_v4); 803 ATF_TC_HEAD(hdtr_negative_bad_pointers_v4, tc) 804 { 805 806 atf_tc_set_md_var(tc, "descr", 807 "Verify that bad pointers for hdtr storage result in EFAULT (IPv4)"); 808 } 809 ATF_TC_BODY(hdtr_negative_bad_pointers_v4, tc) 810 { 811 812 hdtr_negative_bad_pointers_test(AF_INET); 813 } 814 815 ATF_TC(hdtr_negative_bad_pointers_v6); 816 ATF_TC_HEAD(hdtr_negative_bad_pointers_v6, tc) 817 { 818 819 atf_tc_set_md_var(tc, "descr", 820 "Verify that bad pointers for hdtr storage result in EFAULT (IPv6)"); 821 } 822 ATF_TC_BODY(hdtr_negative_bad_pointers_v6, tc) 823 { 824 825 hdtr_negative_bad_pointers_test(AF_INET6); 826 } 827 828 static void 829 offset_negative_value_less_than_zero_test(int domain) 830 { 831 int client_sock, error, fd, port, server_sock; 832 833 port = generate_random_port(__LINE__ + domain); 834 server_sock = setup_tcp_server(domain, port); 835 client_sock = setup_tcp_client(domain, port); 836 837 fd = open(SOURCE_FILE, O_CREAT|O_RDWR); 838 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 839 840 error = sendfile(fd, client_sock, -1, 0, NULL, NULL, SF_FLAGS(0, 0)); 841 ATF_REQUIRE_ERRNO(EINVAL, error == -1); 842 843 (void)close(fd); 844 (void)close(client_sock); 845 (void)close(server_sock); 846 } 847 848 ATF_TC(offset_negative_value_less_than_zero_v4); 849 ATF_TC_HEAD(offset_negative_value_less_than_zero_v4, tc) 850 { 851 852 atf_tc_set_md_var(tc, "descr", 853 "Verify that a negative offset results in EINVAL (IPv4)"); 854 } 855 ATF_TC_BODY(offset_negative_value_less_than_zero_v4, tc) 856 { 857 858 offset_negative_value_less_than_zero_test(AF_INET); 859 } 860 861 ATF_TC(offset_negative_value_less_than_zero_v6); 862 ATF_TC_HEAD(offset_negative_value_less_than_zero_v6, tc) 863 { 864 865 atf_tc_set_md_var(tc, "descr", 866 "Verify that a negative offset results in EINVAL (IPv6)"); 867 } 868 ATF_TC_BODY(offset_negative_value_less_than_zero_v6, tc) 869 { 870 871 offset_negative_value_less_than_zero_test(AF_INET6); 872 } 873 874 static void 875 sbytes_positive_test(int domain) 876 { 877 size_t pattern_size = strlen(DETERMINISTIC_PATTERN); 878 off_t sbytes; 879 int client_sock, error, fd, port, server_sock; 880 881 port = generate_random_port(__LINE__ + domain); 882 server_sock = setup_tcp_server(domain, port); 883 client_sock = setup_tcp_client(domain, port); 884 885 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN); 886 fd = open(SOURCE_FILE, O_RDONLY); 887 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 888 889 error = sendfile(fd, client_sock, 0, 0, NULL, &sbytes, SF_FLAGS(0, 0)); 890 ATF_CHECK_EQ_MSG(error, 0, "sendfile failed: %s", strerror(errno)); 891 892 (void)close(fd); 893 (void)close(client_sock); 894 (void)close(server_sock); 895 896 ATF_CHECK_EQ_MSG(pattern_size, sbytes, 897 "the value returned by sbytes does not match the expected pattern " 898 "size"); 899 } 900 901 ATF_TC(sbytes_positive_v4); 902 ATF_TC_HEAD(sbytes_positive_v4, tc) 903 { 904 905 atf_tc_set_md_var(tc, "descr", 906 "Verify positive `sbytes` functionality (IPv4)"); 907 } 908 ATF_TC_BODY(sbytes_positive_v4, tc) 909 { 910 911 sbytes_positive_test(AF_INET); 912 } 913 914 ATF_TC(sbytes_positive_v6); 915 ATF_TC_HEAD(sbytes_positive_v6, tc) 916 { 917 918 atf_tc_set_md_var(tc, "descr", 919 "Verify positive `sbytes` functionality (IPv6)"); 920 } 921 ATF_TC_BODY(sbytes_positive_v6, tc) 922 { 923 924 sbytes_positive_test(AF_INET6); 925 } 926 927 static void 928 sbytes_negative_test(int domain) 929 { 930 off_t *sbytes_p = (off_t*)-1; 931 int client_sock, error, fd, port, server_sock; 932 933 port = generate_random_port(__LINE__ + domain); 934 server_sock = setup_tcp_server(domain, port); 935 client_sock = setup_tcp_client(domain, port); 936 937 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN); 938 fd = open(SOURCE_FILE, O_RDONLY); 939 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 940 941 atf_tc_expect_fail( 942 "bug 232210: EFAULT assert fails because copyout(9) call is not checked"); 943 944 error = sendfile(fd, client_sock, 0, 0, NULL, sbytes_p, SF_FLAGS(0, 0)); 945 ATF_REQUIRE_ERRNO(EFAULT, error == -1); 946 947 (void)close(fd); 948 (void)close(client_sock); 949 (void)close(server_sock); 950 } 951 952 ATF_TC(sbytes_negative_v4); 953 ATF_TC_HEAD(sbytes_negative_v4, tc) 954 { 955 956 atf_tc_set_md_var(tc, "descr", 957 "Verify negative `sbytes` functionality (IPv4)"); 958 } 959 ATF_TC_BODY(sbytes_negative_v4, tc) 960 { 961 962 sbytes_negative_test(AF_INET); 963 } 964 965 ATF_TC(sbytes_negative_v6); 966 ATF_TC_HEAD(sbytes_negative_v6, tc) 967 { 968 969 atf_tc_set_md_var(tc, "descr", 970 "Verify negative `sbytes` functionality (IPv6)"); 971 } 972 ATF_TC_BODY(sbytes_negative_v6, tc) 973 { 974 975 sbytes_negative_test(AF_INET6); 976 } 977 978 static void 979 s_negative_not_connected_socket_test(int domain) 980 { 981 int client_sock, error, fd, port; 982 983 port = generate_random_port(__LINE__ + domain); 984 client_sock = setup_tcp_server(domain, port); 985 986 fd = open(SOURCE_FILE, O_CREAT|O_RDWR); 987 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 988 989 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0)); 990 ATF_REQUIRE_ERRNO(ENOTCONN, error == -1); 991 992 (void)close(fd); 993 (void)close(client_sock); 994 } 995 996 ATF_TC(s_negative_not_connected_socket_v4); 997 ATF_TC_HEAD(s_negative_not_connected_socket_v4, tc) 998 { 999 1000 atf_tc_set_md_var(tc, "descr", 1001 "Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv4)"); 1002 } 1003 1004 ATF_TC_BODY(s_negative_not_connected_socket_v4, tc) 1005 { 1006 1007 s_negative_not_connected_socket_test(AF_INET); 1008 } 1009 1010 ATF_TC(s_negative_not_connected_socket_v6); 1011 ATF_TC_HEAD(s_negative_not_connected_socket_v6, tc) 1012 { 1013 1014 atf_tc_set_md_var(tc, "descr", 1015 "Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv6)"); 1016 } 1017 1018 ATF_TC_BODY(s_negative_not_connected_socket_v6, tc) 1019 { 1020 1021 s_negative_not_connected_socket_test(AF_INET6); 1022 } 1023 1024 ATF_TC(s_negative_not_descriptor); 1025 ATF_TC_HEAD(s_negative_not_descriptor, tc) 1026 { 1027 1028 atf_tc_set_md_var(tc, "descr", 1029 "Verify that an invalid file descriptor, e.g., -1, fails with EBADF"); 1030 } 1031 1032 ATF_TC_BODY(s_negative_not_descriptor, tc) 1033 { 1034 int client_sock, error, fd; 1035 1036 client_sock = -1; 1037 1038 fd = open(SOURCE_FILE, O_CREAT|O_RDWR); 1039 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 1040 1041 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0)); 1042 ATF_REQUIRE_ERRNO(EBADF, error == -1); 1043 1044 (void)close(fd); 1045 } 1046 1047 ATF_TC(s_negative_not_socket_file_descriptor); 1048 ATF_TC_HEAD(s_negative_not_socket_file_descriptor, tc) 1049 { 1050 1051 atf_tc_set_md_var(tc, "descr", 1052 "Verify that a non-socket file descriptor fails with ENOTSOCK"); 1053 } 1054 1055 ATF_TC_BODY(s_negative_not_socket_file_descriptor, tc) 1056 { 1057 int client_sock, error, fd; 1058 1059 fd = open(SOURCE_FILE, O_CREAT|O_RDWR); 1060 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 1061 1062 client_sock = open(_PATH_DEVNULL, O_WRONLY); 1063 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 1064 1065 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0)); 1066 ATF_REQUIRE_ERRNO(ENOTSOCK, error == -1); 1067 1068 (void)close(fd); 1069 (void)close(client_sock); 1070 } 1071 1072 static void 1073 s_negative_udp_socket_test(int domain) 1074 { 1075 int client_sock, error, fd, port; 1076 1077 port = generate_random_port(__LINE__ + domain); 1078 client_sock = setup_client(domain, SOCK_DGRAM, port); 1079 1080 fd = open(SOURCE_FILE, O_CREAT|O_RDWR); 1081 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); 1082 1083 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0)); 1084 ATF_REQUIRE_ERRNO(EINVAL, error == -1); 1085 1086 (void)close(fd); 1087 (void)close(client_sock); 1088 } 1089 1090 ATF_TC(s_negative_udp_socket_v4); 1091 ATF_TC_HEAD(s_negative_udp_socket_v4, tc) 1092 { 1093 1094 atf_tc_set_md_var(tc, "descr", 1095 "Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv4)"); 1096 } 1097 ATF_TC_BODY(s_negative_udp_socket_v4, tc) 1098 { 1099 1100 s_negative_udp_socket_test(AF_INET); 1101 } 1102 1103 ATF_TC(s_negative_udp_socket_v6); 1104 ATF_TC_HEAD(s_negative_udp_socket_v6, tc) 1105 { 1106 1107 atf_tc_set_md_var(tc, "descr", 1108 "Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv6)"); 1109 } 1110 ATF_TC_BODY(s_negative_udp_socket_v6, tc) 1111 { 1112 1113 s_negative_udp_socket_test(AF_INET6); 1114 } 1115 1116 ATF_TP_ADD_TCS(tp) 1117 { 1118 1119 ATF_TP_ADD_TC(tp, fd_positive_file_v4); 1120 ATF_TP_ADD_TC(tp, fd_positive_file_v6); 1121 ATF_TP_ADD_TC(tp, fd_positive_shm_v4); 1122 ATF_TP_ADD_TC(tp, fd_positive_shm_v6); 1123 ATF_TP_ADD_TC(tp, fd_negative_bad_fd_v4); 1124 ATF_TP_ADD_TC(tp, fd_negative_bad_fd_v6); 1125 ATF_TP_ADD_TC(tp, flags_v4); 1126 ATF_TP_ADD_TC(tp, flags_v6); 1127 /* 1128 * TODO: the negative case for SF_NODISKIO (returns EBUSY if file in 1129 * use) is not covered yet. 1130 * 1131 * Need to lock a file in a subprocess in write mode, then try and 1132 * send the data in read mode with sendfile. 1133 * 1134 * This should work with FFS/UFS, but there are no guarantees about 1135 * other filesystem implementations of sendfile(2), e.g., ZFS. 1136 */ 1137 ATF_TP_ADD_TC(tp, hdtr_positive_v4); 1138 ATF_TP_ADD_TC(tp, hdtr_positive_v6); 1139 ATF_TP_ADD_TC(tp, hdtr_negative_bad_pointers_v4); 1140 ATF_TP_ADD_TC(tp, hdtr_negative_bad_pointers_v6); 1141 ATF_TP_ADD_TC(tp, offset_negative_value_less_than_zero_v4); 1142 ATF_TP_ADD_TC(tp, offset_negative_value_less_than_zero_v6); 1143 ATF_TP_ADD_TC(tp, sbytes_positive_v4); 1144 ATF_TP_ADD_TC(tp, sbytes_positive_v6); 1145 ATF_TP_ADD_TC(tp, sbytes_negative_v4); 1146 ATF_TP_ADD_TC(tp, sbytes_negative_v6); 1147 ATF_TP_ADD_TC(tp, s_negative_not_connected_socket_v4); 1148 ATF_TP_ADD_TC(tp, s_negative_not_connected_socket_v6); 1149 ATF_TP_ADD_TC(tp, s_negative_not_descriptor); 1150 ATF_TP_ADD_TC(tp, s_negative_not_socket_file_descriptor); 1151 ATF_TP_ADD_TC(tp, s_negative_udp_socket_v4); 1152 ATF_TP_ADD_TC(tp, s_negative_udp_socket_v6); 1153 1154 return (atf_no_error()); 1155 } 1156