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