2 * Copyright (c) 2018 Enji Cooper.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
32 #include <sys/socket.h>
34 #include <sys/sysctl.h>
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";
51 #define SOURCE_FILE "source"
52 #define DESTINATION_FILE "dest"
54 #define PORTRANGE_FIRST "net.inet.ip.portrange.first"
55 #define PORTRANGE_LAST "net.inet.ip.portrange.last"
57 static int portrange_first, portrange_last;
60 get_int_via_sysctlbyname(const char *oidname)
65 oldlen = sizeof(int_value);
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");
75 generate_random_port(int seed)
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);
85 if (portrange_last == 0) {
86 portrange_last = get_int_via_sysctlbyname(PORTRANGE_LAST);
87 printf("Port range upper bound: %d\n", portrange_last);
90 srand((unsigned)seed);
92 random_port = rand() % (portrange_last - portrange_first) +
95 printf("Random port generated: %d\n", random_port);
100 resolve_localhost(struct addrinfo **res, int domain, int type, int port)
104 struct addrinfo hints;
115 atf_tc_fail("unhandled domain: %d", domain);
118 ATF_REQUIRE_MSG(asprintf(&serv, "%d", port) >= 0,
119 "asprintf failed: %s", strerror(errno));
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;
126 error = getaddrinfo(host, serv, &hints, res);
127 ATF_REQUIRE_EQ_MSG(error, 0,
128 "getaddrinfo failed: %s", gai_strerror(error));
133 make_socket(int domain, int type, int protocol)
137 sock = socket(domain, type, protocol);
138 ATF_REQUIRE_MSG(sock != -1, "socket(%d, %d, 0) failed: %s",
139 domain, type, strerror(errno));
145 setup_client(int domain, int type, int port)
147 struct addrinfo *res;
148 char host[NI_MAXHOST+1];
151 resolve_localhost(&res, domain, type, port);
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));
158 "Will try to connect to host='%s', address_family=%d, "
160 host, res->ai_family, res->ai_socktype);
161 /* Avoid a double print when forked by flushing. */
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);
166 ATF_REQUIRE_EQ_MSG(error, 0, "connect failed: %s", strerror(errno));
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.
176 setup_server(int domain, int type, int port)
178 struct addrinfo *res;
179 char host[NI_MAXHOST+1];
182 resolve_localhost(&res, domain, type, port);
183 sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
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));
191 "Will try to bind socket to host='%s', address_family=%d, "
193 host, res->ai_family, res->ai_socktype);
194 /* Avoid a double print when forked by flushing. */
196 error = bind(sock, res->ai_addr, res->ai_addrlen);
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));
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
211 server_cat(const char *dest_filename, int server_sock, size_t len)
213 char *buffer, *buf_window_ptr;
216 ssize_t received_bytes, recv_ret;
219 * Ensure that there isn't excess data sent across the wire by
220 * capturing 10 extra bytes (plus 1 for nul).
222 buffer_size = len + 10 + 1;
223 buffer = calloc(buffer_size, sizeof(char));
225 err(1, "malloc failed");
227 recv_sock = accept(server_sock, NULL, 0);
229 err(1, "accept failed");
231 buf_window_ptr = buffer;
234 recv_ret = recv(recv_sock, buf_window_ptr,
235 buffer_size - received_bytes, 0);
238 buf_window_ptr += recv_ret;
239 received_bytes += recv_ret;
240 } while (received_bytes < buffer_size);
242 atf_utils_create_file(dest_filename, "%s", buffer);
244 (void)close(recv_sock);
245 (void)close(server_sock);
248 if (received_bytes != len)
249 errx(1, "received unexpected data: %zd != %zd", received_bytes,
254 setup_tcp_server(int domain, int port)
257 return (setup_server(domain, SOCK_STREAM, port));
261 setup_tcp_client(int domain, int port)
264 return (setup_client(domain, SOCK_STREAM, port));
268 file_size_from_fd(int fd)
272 ATF_REQUIRE_EQ_MSG(0, fstat(fd, &st),
273 "fstat failed: %s", strerror(errno));
279 * NB: `nbytes` == 0 has special connotations given the sendfile(2) API
280 * contract. In short, "send the whole file" (paraphrased).
283 verify_source_and_dest(const char* dest_filename, int src_fd, off_t offset,
286 char *dest_pointer, *src_pointer;
287 off_t dest_file_size, src_file_size;
291 atf_utils_cat_file(dest_filename, "dest_file: ");
293 dest_fd = open(dest_filename, O_RDONLY);
294 ATF_REQUIRE_MSG(dest_fd != -1, "open failed");
296 dest_file_size = file_size_from_fd(dest_fd);
297 src_file_size = file_size_from_fd(src_fd);
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).
304 length = (nbytes == 0) ? (size_t)(src_file_size - offset) : nbytes;
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,
311 ATF_REQUIRE_EQ_MSG(0, lseek(src_fd, offset, SEEK_SET),
312 "lseek failed: %s", strerror(errno));
314 dest_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, dest_fd, 0);
315 ATF_REQUIRE_MSG(dest_pointer != MAP_FAILED, "mmap failed: %s",
318 printf("Will mmap in the source file from offset=%jd to length=%zu\n",
321 src_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, src_fd, offset);
322 ATF_REQUIRE_MSG(src_pointer != MAP_FAILED, "mmap failed: %s",
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);
329 (void)munmap(src_pointer, length);
330 (void)munmap(dest_pointer, length);
331 (void)close(dest_fd);
335 fd_positive_file_test(int domain)
338 size_t nbytes, pattern_size;
339 int client_sock, error, fd, port, server_sock;
342 pattern_size = strlen(DETERMINISTIC_PATTERN);
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));
348 port = generate_random_port(__LINE__ + domain);
349 server_sock = setup_tcp_server(domain, port);
350 client_sock = setup_tcp_client(domain, port);
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);
358 (void)close(server_sock);
362 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
364 ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
365 (void)close(client_sock);
367 atf_utils_wait(server_pid, 0, "", "");
368 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
373 ATF_TC(fd_positive_file_v4);
374 ATF_TC_HEAD(fd_positive_file_v4, tc)
377 atf_tc_set_md_var(tc, "descr",
378 "Verify regular file as file descriptor support (IPv4)");
380 ATF_TC_BODY(fd_positive_file_v4, tc)
383 fd_positive_file_test(AF_INET);
386 ATF_TC(fd_positive_file_v6);
387 ATF_TC_HEAD(fd_positive_file_v6, tc)
390 atf_tc_set_md_var(tc, "descr",
391 "Verify regular file as file descriptor support (IPv6)");
393 ATF_TC_BODY(fd_positive_file_v6, tc)
396 fd_positive_file_test(AF_INET6);
400 fd_positive_shm_test(int domain)
404 size_t nbytes, pattern_size;
406 int client_sock, error, fd, port, server_sock;
408 pattern_size = strlen(DETERMINISTIC_PATTERN);
410 printf("pattern size: %zu\n", pattern_size);
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,
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);
426 port = generate_random_port(__LINE__ + domain);
427 server_sock = setup_tcp_server(domain, port);
428 client_sock = setup_tcp_client(domain, port);
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);
436 (void)close(server_sock);
440 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
442 ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
443 (void)close(client_sock);
445 atf_utils_wait(server_pid, 0, "", "");
446 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
448 (void)munmap(shm_pointer, sizeof(DETERMINISTIC_PATTERN));
452 ATF_TC(fd_positive_shm_v4);
453 ATF_TC_HEAD(fd_positive_shm_v4, tc)
456 atf_tc_set_md_var(tc, "descr",
457 "Verify shared memory as file descriptor support (IPv4)");
459 ATF_TC_BODY(fd_positive_shm_v4, tc)
462 fd_positive_shm_test(AF_INET);
465 ATF_TC(fd_positive_shm_v6);
466 ATF_TC_HEAD(fd_positive_shm_v6, tc)
469 atf_tc_set_md_var(tc, "descr",
470 "Verify shared memory as file descriptor support (IPv6))");
472 ATF_TC_BODY(fd_positive_shm_v6, tc)
475 fd_positive_shm_test(AF_INET6);
479 fd_negative_bad_fd_test(int domain)
481 int client_sock, error, fd, port, server_sock;
483 port = generate_random_port(__LINE__ + domain);
484 server_sock = setup_tcp_server(domain, port);
485 client_sock = setup_tcp_client(domain, port);
489 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
490 ATF_REQUIRE_ERRNO(EBADF, error == -1);
492 (void)close(client_sock);
493 (void)close(server_sock);
496 ATF_TC(fd_negative_bad_fd_v4);
497 ATF_TC_HEAD(fd_negative_bad_fd_v4, tc)
500 atf_tc_set_md_var(tc, "descr",
501 "Verify bad file descriptor returns EBADF (IPv4)");
503 ATF_TC_BODY(fd_negative_bad_fd_v4, tc)
506 fd_negative_bad_fd_test(AF_INET);
509 ATF_TC(fd_negative_bad_fd_v6);
510 ATF_TC_HEAD(fd_negative_bad_fd_v6, tc)
513 atf_tc_set_md_var(tc, "descr",
514 "Verify bad file descriptor returns EBADF (IPv6)");
516 ATF_TC_BODY(fd_negative_bad_fd_v6, tc)
519 fd_negative_bad_fd_test(AF_INET6);
523 flags_test(int domain)
526 size_t nbytes, pattern_size;
527 int client_sock, error, fd, i, port, server_sock;
529 int16_t number_pages = 10;
531 pattern_size = strlen(DETERMINISTIC_PATTERN);
534 int16_t readahead_pages, flags;
536 /* This is covered in `:fd_positive_file` */
539 .readahead_pages = 0,
544 .readahead_pages = 0,
547 #ifdef SF_USER_READAHEAD
549 .readahead_pages = 0,
550 .flags = SF_NOCACHE|SF_USER_READAHEAD
553 .readahead_pages = 0,
554 .flags = SF_USER_READAHEAD
558 .readahead_pages = number_pages,
562 .readahead_pages = number_pages,
565 #ifdef SF_USER_READAHEAD
567 .readahead_pages = number_pages,
568 .flags = SF_NOCACHE|SF_USER_READAHEAD
572 .readahead_pages = number_pages,
576 .readahead_pages = number_pages,
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));
586 port = generate_random_port(i * __LINE__ + domain);
587 server_sock = setup_tcp_server(domain, port);
588 client_sock = setup_tcp_client(domain, port);
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);
596 (void)close(server_sock);
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",
604 (void)close(client_sock);
606 atf_utils_wait(server_pid, 0, "", "");
607 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
614 ATF_TC_HEAD(flags_v4, tc)
617 atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv4)");
619 ATF_TC_BODY(flags_v4, tc)
626 ATF_TC_HEAD(flags_v6, tc)
629 atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv6)");
631 ATF_TC_BODY(flags_v6, tc)
634 flags_test(AF_INET6);
638 hdtr_positive_test(int domain)
640 struct iovec headers[1], trailers[1];
642 bool include_headers, include_trailers;
644 /* This is covered in `:fd_positive_file` */
647 .include_headers = false,
648 .include_trailers = false
652 .include_headers = true,
653 .include_trailers = false
656 .include_headers = false,
657 .include_trailers = true
660 .include_headers = true,
661 .include_trailers = true
666 int client_sock, error, fd, fd2, i, port, rc, server_sock;
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);
676 for (i = 0; i < nitems(testcases); i++) {
680 if (testcases[i].include_headers) {
681 hdtr.headers = headers;
682 hdtr.hdr_cnt = nitems(headers);
688 if (testcases[i].include_trailers) {
689 hdtr.trailers = trailers;
690 hdtr.trl_cnt = nitems(trailers);
692 hdtr.trailers = NULL;
696 port = generate_random_port(i * __LINE__ + domain);
697 server_sock = setup_tcp_server(domain, port);
698 client_sock = setup_tcp_client(domain, port);
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));
706 atf_utils_create_file(SOURCE_FILE ".full", "%s", pattern);
707 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
709 fd = open(SOURCE_FILE, O_RDONLY);
710 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
712 fd2 = open(SOURCE_FILE ".full", O_RDONLY);
713 ATF_REQUIRE_MSG(fd2 != -1, "open failed: %s", strerror(errno));
715 server_pid = atf_utils_fork();
716 if (server_pid == 0) {
717 (void)close(client_sock);
718 server_cat(DESTINATION_FILE, server_sock,
722 (void)close(server_sock);
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",
728 (void)close(client_sock);
730 atf_utils_wait(server_pid, 0, "", "");
731 verify_source_and_dest(DESTINATION_FILE, fd2, offset, nbytes);
740 ATF_TC(hdtr_positive_v4);
741 ATF_TC_HEAD(hdtr_positive_v4, tc)
744 atf_tc_set_md_var(tc, "descr",
745 "Verify positive hdtr functionality (IPv4)");
747 ATF_TC_BODY(hdtr_positive_v4, tc)
750 hdtr_positive_test(AF_INET);
753 ATF_TC(hdtr_positive_v6);
754 ATF_TC_HEAD(hdtr_positive_v6, tc)
757 atf_tc_set_md_var(tc, "descr",
758 "Verify positive hdtr functionality (IPv6)");
760 ATF_TC_BODY(hdtr_positive_v6, tc)
763 hdtr_positive_test(AF_INET);
767 hdtr_negative_bad_pointers_test(int domain)
769 int client_sock, error, fd, port, server_sock;
770 struct sf_hdtr *hdtr1, hdtr2, hdtr3;
772 port = generate_random_port(__LINE__ + domain);
774 hdtr1 = (struct sf_hdtr*)-1;
776 memset(&hdtr2, 0, sizeof(hdtr2));
778 hdtr2.headers = (struct iovec*)-1;
780 memset(&hdtr3, 0, sizeof(hdtr3));
782 hdtr3.trailers = (struct iovec*)-1;
784 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
785 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
787 server_sock = setup_tcp_server(domain, port);
788 client_sock = setup_tcp_client(domain, port);
790 error = sendfile(fd, client_sock, 0, 0, hdtr1, NULL, SF_FLAGS(0, 0));
791 ATF_CHECK_ERRNO(EFAULT, error == -1);
793 error = sendfile(fd, client_sock, 0, 0, &hdtr2, NULL, SF_FLAGS(0, 0));
794 ATF_CHECK_ERRNO(EFAULT, error == -1);
796 error = sendfile(fd, client_sock, 0, 0, &hdtr3, NULL, SF_FLAGS(0, 0));
797 ATF_CHECK_ERRNO(EFAULT, error == -1);
800 (void)close(client_sock);
801 (void)close(server_sock);
804 ATF_TC(hdtr_negative_bad_pointers_v4);
805 ATF_TC_HEAD(hdtr_negative_bad_pointers_v4, tc)
808 atf_tc_set_md_var(tc, "descr",
809 "Verify that bad pointers for hdtr storage result in EFAULT (IPv4)");
811 ATF_TC_BODY(hdtr_negative_bad_pointers_v4, tc)
814 hdtr_negative_bad_pointers_test(AF_INET);
817 ATF_TC(hdtr_negative_bad_pointers_v6);
818 ATF_TC_HEAD(hdtr_negative_bad_pointers_v6, tc)
821 atf_tc_set_md_var(tc, "descr",
822 "Verify that bad pointers for hdtr storage result in EFAULT (IPv6)");
824 ATF_TC_BODY(hdtr_negative_bad_pointers_v6, tc)
827 hdtr_negative_bad_pointers_test(AF_INET6);
831 offset_negative_value_less_than_zero_test(int domain)
833 int client_sock, error, fd, port, server_sock;
835 port = generate_random_port(__LINE__ + domain);
836 server_sock = setup_tcp_server(domain, port);
837 client_sock = setup_tcp_client(domain, port);
839 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
840 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
842 error = sendfile(fd, client_sock, -1, 0, NULL, NULL, SF_FLAGS(0, 0));
843 ATF_REQUIRE_ERRNO(EINVAL, error == -1);
846 (void)close(client_sock);
847 (void)close(server_sock);
850 ATF_TC(offset_negative_value_less_than_zero_v4);
851 ATF_TC_HEAD(offset_negative_value_less_than_zero_v4, tc)
854 atf_tc_set_md_var(tc, "descr",
855 "Verify that a negative offset results in EINVAL (IPv4)");
857 ATF_TC_BODY(offset_negative_value_less_than_zero_v4, tc)
860 offset_negative_value_less_than_zero_test(AF_INET);
863 ATF_TC(offset_negative_value_less_than_zero_v6);
864 ATF_TC_HEAD(offset_negative_value_less_than_zero_v6, tc)
867 atf_tc_set_md_var(tc, "descr",
868 "Verify that a negative offset results in EINVAL (IPv6)");
870 ATF_TC_BODY(offset_negative_value_less_than_zero_v6, tc)
873 offset_negative_value_less_than_zero_test(AF_INET6);
877 sbytes_positive_test(int domain)
879 size_t pattern_size = strlen(DETERMINISTIC_PATTERN);
881 int client_sock, error, fd, port, server_sock;
883 port = generate_random_port(__LINE__ + domain);
884 server_sock = setup_tcp_server(domain, port);
885 client_sock = setup_tcp_client(domain, port);
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));
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));
895 (void)close(client_sock);
896 (void)close(server_sock);
898 ATF_CHECK_EQ_MSG(pattern_size, sbytes,
899 "the value returned by sbytes does not match the expected pattern "
903 ATF_TC(sbytes_positive_v4);
904 ATF_TC_HEAD(sbytes_positive_v4, tc)
907 atf_tc_set_md_var(tc, "descr",
908 "Verify positive `sbytes` functionality (IPv4)");
910 ATF_TC_BODY(sbytes_positive_v4, tc)
913 sbytes_positive_test(AF_INET);
916 ATF_TC(sbytes_positive_v6);
917 ATF_TC_HEAD(sbytes_positive_v6, tc)
920 atf_tc_set_md_var(tc, "descr",
921 "Verify positive `sbytes` functionality (IPv6)");
923 ATF_TC_BODY(sbytes_positive_v6, tc)
926 sbytes_positive_test(AF_INET6);
930 sbytes_negative_test(int domain)
932 off_t *sbytes_p = (off_t*)-1;
933 int client_sock, error, fd, port, server_sock;
935 port = generate_random_port(__LINE__ + domain);
936 server_sock = setup_tcp_server(domain, port);
937 client_sock = setup_tcp_client(domain, port);
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));
944 "bug 232210: EFAULT assert fails because copyout(9) call is not checked");
946 error = sendfile(fd, client_sock, 0, 0, NULL, sbytes_p, SF_FLAGS(0, 0));
947 ATF_REQUIRE_ERRNO(EFAULT, error == -1);
950 (void)close(client_sock);
951 (void)close(server_sock);
954 ATF_TC(sbytes_negative_v4);
955 ATF_TC_HEAD(sbytes_negative_v4, tc)
958 atf_tc_set_md_var(tc, "descr",
959 "Verify negative `sbytes` functionality (IPv4)");
961 ATF_TC_BODY(sbytes_negative_v4, tc)
964 sbytes_negative_test(AF_INET);
967 ATF_TC(sbytes_negative_v6);
968 ATF_TC_HEAD(sbytes_negative_v6, tc)
971 atf_tc_set_md_var(tc, "descr",
972 "Verify negative `sbytes` functionality (IPv6)");
974 ATF_TC_BODY(sbytes_negative_v6, tc)
977 sbytes_negative_test(AF_INET6);
981 s_negative_not_connected_socket_test(int domain)
983 int client_sock, error, fd, port;
985 port = generate_random_port(__LINE__ + domain);
986 client_sock = setup_tcp_server(domain, port);
988 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
989 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
991 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
992 ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
995 (void)close(client_sock);
998 ATF_TC(s_negative_not_connected_socket_v4);
999 ATF_TC_HEAD(s_negative_not_connected_socket_v4, tc)
1002 atf_tc_set_md_var(tc, "descr",
1003 "Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv4)");
1006 ATF_TC_BODY(s_negative_not_connected_socket_v4, tc)
1009 s_negative_not_connected_socket_test(AF_INET);
1012 ATF_TC(s_negative_not_connected_socket_v6);
1013 ATF_TC_HEAD(s_negative_not_connected_socket_v6, tc)
1016 atf_tc_set_md_var(tc, "descr",
1017 "Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv6)");
1020 ATF_TC_BODY(s_negative_not_connected_socket_v6, tc)
1023 s_negative_not_connected_socket_test(AF_INET6);
1026 ATF_TC(s_negative_not_descriptor);
1027 ATF_TC_HEAD(s_negative_not_descriptor, tc)
1030 atf_tc_set_md_var(tc, "descr",
1031 "Verify that an invalid file descriptor, e.g., -1, fails with EBADF");
1034 ATF_TC_BODY(s_negative_not_descriptor, tc)
1036 int client_sock, error, fd;
1040 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1041 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1043 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1044 ATF_REQUIRE_ERRNO(EBADF, error == -1);
1049 ATF_TC(s_negative_not_socket_file_descriptor);
1050 ATF_TC_HEAD(s_negative_not_socket_file_descriptor, tc)
1053 atf_tc_set_md_var(tc, "descr",
1054 "Verify that a non-socket file descriptor fails with ENOTSOCK");
1057 ATF_TC_BODY(s_negative_not_socket_file_descriptor, tc)
1059 int client_sock, error, fd;
1061 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1062 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1064 client_sock = open(_PATH_DEVNULL, O_WRONLY);
1065 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1067 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1068 ATF_REQUIRE_ERRNO(ENOTSOCK, error == -1);
1071 (void)close(client_sock);
1075 s_negative_udp_socket_test(int domain)
1077 int client_sock, error, fd, port;
1079 port = generate_random_port(__LINE__ + domain);
1080 client_sock = setup_client(domain, SOCK_DGRAM, port);
1082 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1083 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1085 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1086 ATF_REQUIRE_ERRNO(EINVAL, error == -1);
1089 (void)close(client_sock);
1092 ATF_TC(s_negative_udp_socket_v4);
1093 ATF_TC_HEAD(s_negative_udp_socket_v4, tc)
1096 atf_tc_set_md_var(tc, "descr",
1097 "Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv4)");
1099 ATF_TC_BODY(s_negative_udp_socket_v4, tc)
1102 s_negative_udp_socket_test(AF_INET);
1105 ATF_TC(s_negative_udp_socket_v6);
1106 ATF_TC_HEAD(s_negative_udp_socket_v6, tc)
1109 atf_tc_set_md_var(tc, "descr",
1110 "Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv6)");
1112 ATF_TC_BODY(s_negative_udp_socket_v6, tc)
1115 s_negative_udp_socket_test(AF_INET6);
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);
1130 * TODO: the negative case for SF_NODISKIO (returns EBUSY if file in
1131 * use) is not covered yet.
1133 * Need to lock a file in a subprocess in write mode, then try and
1134 * send the data in read mode with sendfile.
1136 * This should work with FFS/UFS, but there are no guarantees about
1137 * other filesystem implementations of sendfile(2), e.g., ZFS.
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);
1156 return (atf_no_error());