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 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");
73 generate_random_port(int seed)
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);
83 if (portrange_last == 0) {
84 portrange_last = get_int_via_sysctlbyname(PORTRANGE_LAST);
85 printf("Port range upper bound: %d\n", portrange_last);
88 srand((unsigned)seed);
90 random_port = rand() % (portrange_last - portrange_first) +
93 printf("Random port generated: %d\n", random_port);
98 resolve_localhost(struct addrinfo **res, int domain, int type, int port)
101 struct addrinfo hints;
104 ATF_REQUIRE_MSG(domain == AF_INET || domain == AF_INET6,
105 "unhandled domain: %d", domain);
107 ATF_REQUIRE_MSG(asprintf(&serv, "%d", port) >= 0,
108 "asprintf failed: %s", strerror(errno));
110 memset(&hints, 0, sizeof(hints));
111 hints.ai_family = domain;
112 hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV;
113 hints.ai_socktype = type;
115 error = getaddrinfo("localhost", serv, &hints, res);
116 ATF_REQUIRE_EQ_MSG(error, 0,
117 "getaddrinfo failed: %s", gai_strerror(errno));
122 make_socket(int domain, int type, int protocol)
126 sock = socket(domain, type, protocol);
127 ATF_REQUIRE_MSG(sock != -1, "socket(%d, %d, 0) failed: %s",
128 domain, type, strerror(errno));
134 setup_client(int domain, int type, int port)
136 struct addrinfo *res;
137 char host[NI_MAXHOST+1];
140 resolve_localhost(&res, domain, type, port);
142 (const struct sockaddr*)res->ai_addr, res->ai_addrlen,
143 host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST);
144 ATF_REQUIRE_EQ_MSG(error, 0,
145 "getnameinfo failed: %s", gai_strerror(error));
147 "Will try to connect to host='%s', address_family=%d, "
149 host, res->ai_family, res->ai_socktype);
150 sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
151 error = connect(sock, (struct sockaddr*)res->ai_addr, res->ai_addrlen);
153 ATF_REQUIRE_EQ_MSG(error, 0, "connect failed: %s", strerror(errno));
158 * XXX: use linear probing to find a free port and eliminate `port` argument as
159 * a [const] int (it will need to be a pointer so it can be passed back out of
160 * the function and can influence which port `setup_client(..)` connects on.
163 setup_server(int domain, int type, int port)
165 struct addrinfo *res;
166 char host[NI_MAXHOST+1];
169 resolve_localhost(&res, domain, type, port);
170 sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
173 (const struct sockaddr*)res->ai_addr, res->ai_addrlen,
174 host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST);
175 ATF_REQUIRE_EQ_MSG(error, 0,
176 "getnameinfo failed: %s", gai_strerror(error));
178 "Will try to bind socket to host='%s', address_family=%d, "
180 host, res->ai_family, res->ai_socktype);
181 error = bind(sock, res->ai_addr, res->ai_addrlen);
183 ATF_REQUIRE_EQ_MSG(error, 0, "bind failed: %s", strerror(errno));
184 error = listen(sock, 1);
185 ATF_REQUIRE_EQ_MSG(error, 0, "listen failed: %s", strerror(errno));
191 * This function is a helper routine for taking data being sent by `sendfile` via
192 * `server_sock`, and pushing the received stream out to a file, denoted by
196 server_cat(const char *dest_filename, int server_sock, size_t len)
200 ssize_t received_bytes;
202 buffer = calloc(len + 1, sizeof(char));
204 err(1, "malloc failed");
206 recv_sock = accept(server_sock, NULL, 0);
208 err(1, "accept failed");
211 * XXX: this assumes the simplest case where all data is received in a
212 * single recv(2) call.
214 if (recv(recv_sock, buffer, len, 0) == -1)
215 err(1, "recv failed");
217 atf_utils_create_file(dest_filename, "%s", buffer);
220 * This recv(2) call helps ensure the amount of sent data is exactly
221 * what was specified by `len`.
223 received_bytes = recv(recv_sock, buffer, len, 0);
224 switch (received_bytes) {
226 err(1, "recv failed");
230 errx(1, "received unexpected data: %s", buffer);
233 (void)close(recv_sock);
234 (void)close(server_sock);
239 setup_tcp_server(int domain, int port)
242 return (setup_server(domain, SOCK_STREAM, port));
246 setup_tcp_client(int domain, int port)
249 return (setup_client(domain, SOCK_STREAM, port));
253 file_size_from_fd(int fd)
257 ATF_REQUIRE_EQ_MSG(0, fstat(fd, &st),
258 "fstat failed: %s", strerror(errno));
264 * NB: `nbytes` == 0 has special connotations given the sendfile(2) API
265 * contract. In short, "send the whole file" (paraphrased).
268 verify_source_and_dest(const char* dest_filename, int src_fd, off_t offset,
271 char *dest_pointer, *src_pointer;
272 off_t dest_file_size, src_file_size;
276 atf_utils_cat_file(dest_filename, "dest_file: ");
278 dest_fd = open(dest_filename, O_RDONLY);
279 ATF_REQUIRE_MSG(dest_fd != -1, "open failed");
281 dest_file_size = file_size_from_fd(dest_fd);
282 src_file_size = file_size_from_fd(src_fd);
285 * Per sendfile(2), "send the whole file" (paraphrased). This means
286 * that we need to grab the file size, as passing in length = 0 with
287 * mmap(2) will result in a failure with EINVAL (length = 0 is invalid).
289 length = (nbytes == 0) ? (size_t)(src_file_size - offset) : nbytes;
291 ATF_REQUIRE_EQ_MSG(dest_file_size, length,
292 "number of bytes written out to %s (%ju) doesn't match the "
293 "expected number of bytes (%ju)", dest_filename, dest_file_size,
296 ATF_REQUIRE_EQ_MSG(0, lseek(src_fd, offset, SEEK_SET),
297 "lseek failed: %s", strerror(errno));
299 dest_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, dest_fd, 0);
300 ATF_REQUIRE_MSG(dest_pointer != MAP_FAILED, "mmap failed: %s",
303 printf("Will mmap in the source file from offset=%jd to length=%zu\n",
306 src_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, src_fd, offset);
307 ATF_REQUIRE_MSG(src_pointer != MAP_FAILED, "mmap failed: %s",
310 ATF_REQUIRE_EQ_MSG(0, memcmp(src_pointer, dest_pointer, length),
311 "Contents of source and destination do not match. '%s' != '%s'",
312 src_pointer, dest_pointer);
314 (void)munmap(src_pointer, length);
315 (void)munmap(dest_pointer, length);
316 (void)close(dest_fd);
320 fd_positive_file_test(int domain)
323 size_t nbytes, pattern_size;
324 int client_sock, error, fd, port, server_sock;
327 pattern_size = strlen(DETERMINISTIC_PATTERN);
329 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
330 fd = open(SOURCE_FILE, O_RDONLY);
331 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
333 port = generate_random_port(__LINE__ + domain);
334 server_sock = setup_tcp_server(domain, port);
335 client_sock = setup_tcp_client(domain, port);
337 server_pid = atf_utils_fork();
338 if (server_pid == 0) {
339 (void)close(client_sock);
340 server_cat(DESTINATION_FILE, server_sock, pattern_size);
343 (void)close(server_sock);
347 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
349 ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
350 (void)close(client_sock);
352 atf_utils_wait(server_pid, 0, "", "");
353 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
358 ATF_TC(fd_positive_file_v4);
359 ATF_TC_HEAD(fd_positive_file_v4, tc)
362 atf_tc_set_md_var(tc, "descr",
363 "Verify regular file as file descriptor support (IPv4)");
365 ATF_TC_BODY(fd_positive_file_v4, tc)
368 fd_positive_file_test(AF_INET);
371 ATF_TC(fd_positive_file_v6);
372 ATF_TC_HEAD(fd_positive_file_v6, tc)
375 atf_tc_set_md_var(tc, "descr",
376 "Verify regular file as file descriptor support (IPv6)");
378 ATF_TC_BODY(fd_positive_file_v6, tc)
381 fd_positive_file_test(AF_INET6);
385 fd_positive_shm_test(int domain)
389 size_t nbytes, pattern_size;
391 int client_sock, error, fd, port, server_sock;
393 pattern_size = strlen(DETERMINISTIC_PATTERN);
395 printf("pattern size: %zu\n", pattern_size);
397 fd = shm_open(SHM_ANON, O_RDWR|O_CREAT, 0600);
398 ATF_REQUIRE_MSG(fd != -1, "shm_open failed: %s", strerror(errno));
399 ATF_REQUIRE_EQ_MSG(0, ftruncate(fd, pattern_size),
400 "ftruncate failed: %s", strerror(errno));
401 shm_pointer = mmap(NULL, pattern_size, PROT_READ|PROT_WRITE,
403 ATF_REQUIRE_MSG(shm_pointer != MAP_FAILED,
404 "mmap failed: %s", strerror(errno));
405 memcpy(shm_pointer, DETERMINISTIC_PATTERN, pattern_size);
406 ATF_REQUIRE_EQ_MSG(0,
407 memcmp(shm_pointer, DETERMINISTIC_PATTERN, pattern_size),
408 "memcmp showed data mismatch: '%s' != '%s'",
409 DETERMINISTIC_PATTERN, shm_pointer);
411 port = generate_random_port(__LINE__ + domain);
412 server_sock = setup_tcp_server(domain, port);
413 client_sock = setup_tcp_client(domain, port);
415 server_pid = atf_utils_fork();
416 if (server_pid == 0) {
417 (void)close(client_sock);
418 server_cat(DESTINATION_FILE, server_sock, pattern_size);
421 (void)close(server_sock);
425 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
427 ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
428 (void)close(client_sock);
430 atf_utils_wait(server_pid, 0, "", "");
431 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
433 (void)munmap(shm_pointer, sizeof(DETERMINISTIC_PATTERN));
437 ATF_TC(fd_positive_shm_v4);
438 ATF_TC_HEAD(fd_positive_shm_v4, tc)
441 atf_tc_set_md_var(tc, "descr",
442 "Verify shared memory as file descriptor support (IPv4)");
444 ATF_TC_BODY(fd_positive_shm_v4, tc)
447 fd_positive_shm_test(AF_INET);
450 ATF_TC(fd_positive_shm_v6);
451 ATF_TC_HEAD(fd_positive_shm_v6, tc)
454 atf_tc_set_md_var(tc, "descr",
455 "Verify shared memory as file descriptor support (IPv6))");
457 ATF_TC_BODY(fd_positive_shm_v6, tc)
460 fd_positive_shm_test(AF_INET6);
464 fd_negative_bad_fd_test(int domain)
466 int client_sock, error, fd, port, server_sock;
468 port = generate_random_port(__LINE__ + domain);
469 server_sock = setup_tcp_server(domain, port);
470 client_sock = setup_tcp_client(domain, port);
474 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
475 ATF_REQUIRE_ERRNO(EBADF, error == -1);
477 (void)close(client_sock);
478 (void)close(server_sock);
481 ATF_TC(fd_negative_bad_fd_v4);
482 ATF_TC_HEAD(fd_negative_bad_fd_v4, tc)
485 atf_tc_set_md_var(tc, "descr",
486 "Verify bad file descriptor returns EBADF (IPv4)");
488 ATF_TC_BODY(fd_negative_bad_fd_v4, tc)
491 fd_negative_bad_fd_test(AF_INET);
494 ATF_TC(fd_negative_bad_fd_v6);
495 ATF_TC_HEAD(fd_negative_bad_fd_v6, tc)
498 atf_tc_set_md_var(tc, "descr",
499 "Verify bad file descriptor returns EBADF (IPv6)");
501 ATF_TC_BODY(fd_negative_bad_fd_v6, tc)
504 fd_negative_bad_fd_test(AF_INET6);
508 flags_test(int domain)
511 size_t nbytes, pattern_size;
512 int client_sock, error, fd, i, port, server_sock;
514 int16_t number_pages = 10;
516 pattern_size = strlen(DETERMINISTIC_PATTERN);
519 int16_t readahead_pages, flags;
521 /* This is covered in `:fd_positive_file` */
524 .readahead_pages = 0,
529 .readahead_pages = 0,
532 #ifdef SF_USER_READAHEAD
534 .readahead_pages = 0,
535 .flags = SF_NOCACHE|SF_USER_READAHEAD
538 .readahead_pages = 0,
539 .flags = SF_USER_READAHEAD
543 .readahead_pages = number_pages,
547 .readahead_pages = number_pages,
550 #ifdef SF_USER_READAHEAD
552 .readahead_pages = number_pages,
553 .flags = SF_NOCACHE|SF_USER_READAHEAD
557 .readahead_pages = number_pages,
561 .readahead_pages = number_pages,
566 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
567 for (i = 0; i < nitems(testcases); i++) {
568 fd = open(SOURCE_FILE, O_RDONLY);
569 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
571 port = generate_random_port(i * __LINE__ + domain);
572 server_sock = setup_tcp_server(domain, port);
573 client_sock = setup_tcp_client(domain, port);
575 server_pid = atf_utils_fork();
576 if (server_pid == 0) {
577 (void)close(client_sock);
578 server_cat(DESTINATION_FILE, server_sock, pattern_size);
581 (void)close(server_sock);
585 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
586 SF_FLAGS(testcases[i].readahead_pages, testcases[i].flags));
587 ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s",
589 (void)close(client_sock);
591 atf_utils_wait(server_pid, 0, "", "");
592 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
599 ATF_TC_HEAD(flags_v4, tc)
602 atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv4)");
604 ATF_TC_BODY(flags_v4, tc)
611 ATF_TC_HEAD(flags_v6, tc)
614 atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv6)");
616 ATF_TC_BODY(flags_v6, tc)
619 flags_test(AF_INET6);
623 hdtr_positive_test(int domain)
625 struct iovec headers[1], trailers[1];
627 bool include_headers, include_trailers;
629 /* This is covered in `:fd_positive_file` */
632 .include_headers = false,
633 .include_trailers = false
637 .include_headers = true,
638 .include_trailers = false
641 .include_headers = false,
642 .include_trailers = true
645 .include_headers = true,
646 .include_trailers = true
651 int client_sock, error, fd, fd2, i, port, rc, server_sock;
654 headers[0].iov_base = "This is a header";
655 headers[0].iov_len = strlen(headers[0].iov_base);
656 trailers[0].iov_base = "This is a trailer";
657 trailers[0].iov_len = strlen(trailers[0].iov_base);
662 "The header/trailer testcases fail today with a data mismatch; "
665 for (i = 0; i < nitems(testcases); i++) {
669 if (testcases[i].include_headers) {
670 hdtr.headers = headers;
671 hdtr.hdr_cnt = nitems(headers);
677 if (testcases[i].include_trailers) {
678 hdtr.trailers = trailers;
679 hdtr.trl_cnt = nitems(trailers);
681 hdtr.trailers = NULL;
685 port = generate_random_port(i * __LINE__ + domain);
686 server_sock = setup_tcp_server(domain, port);
687 client_sock = setup_tcp_client(domain, port);
689 rc = asprintf(&pattern, "%s%s%s",
690 testcases[i].include_headers ? (char *)headers[0].iov_base : "",
691 DETERMINISTIC_PATTERN,
692 testcases[i].include_trailers ? (char *)trailers[0].iov_base : "");
693 ATF_REQUIRE_MSG(rc != -1, "asprintf failed: %s", strerror(errno));
695 atf_utils_create_file(SOURCE_FILE ".full", "%s", pattern);
696 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
698 fd = open(SOURCE_FILE, O_RDONLY);
699 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
701 fd2 = open(SOURCE_FILE ".full", O_RDONLY);
702 ATF_REQUIRE_MSG(fd2 != -1, "open failed: %s", strerror(errno));
704 server_pid = atf_utils_fork();
705 if (server_pid == 0) {
706 (void)close(client_sock);
707 server_cat(DESTINATION_FILE, server_sock,
711 (void)close(server_sock);
713 error = sendfile(fd, client_sock, offset, nbytes, &hdtr,
714 NULL, SF_FLAGS(0, 0));
715 ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s",
717 (void)close(client_sock);
719 atf_utils_wait(server_pid, 0, "", "");
720 verify_source_and_dest(DESTINATION_FILE, fd2, offset, nbytes);
729 ATF_TC(hdtr_positive_v4);
730 ATF_TC_HEAD(hdtr_positive_v4, tc)
733 atf_tc_set_md_var(tc, "descr",
734 "Verify positive hdtr functionality (IPv4)");
736 ATF_TC_BODY(hdtr_positive_v4, tc)
739 hdtr_positive_test(AF_INET);
742 ATF_TC(hdtr_positive_v6);
743 ATF_TC_HEAD(hdtr_positive_v6, tc)
746 atf_tc_set_md_var(tc, "descr",
747 "Verify positive hdtr functionality (IPv6)");
749 ATF_TC_BODY(hdtr_positive_v6, tc)
752 hdtr_positive_test(AF_INET);
756 hdtr_negative_bad_pointers_test(int domain)
758 int client_sock, error, fd, port, server_sock;
759 struct sf_hdtr *hdtr1, hdtr2, hdtr3;
761 port = generate_random_port(__LINE__ + domain);
763 hdtr1 = (struct sf_hdtr*)-1;
765 memset(&hdtr2, 0, sizeof(hdtr2));
767 hdtr2.headers = (struct iovec*)-1;
769 memset(&hdtr3, 0, sizeof(hdtr3));
771 hdtr3.trailers = (struct iovec*)-1;
773 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
774 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
776 server_sock = setup_tcp_server(domain, port);
777 client_sock = setup_tcp_client(domain, port);
779 error = sendfile(fd, client_sock, 0, 0, hdtr1, NULL, SF_FLAGS(0, 0));
780 ATF_CHECK_ERRNO(EFAULT, error == -1);
782 error = sendfile(fd, client_sock, 0, 0, &hdtr2, NULL, SF_FLAGS(0, 0));
783 ATF_CHECK_ERRNO(EFAULT, error == -1);
785 error = sendfile(fd, client_sock, 0, 0, &hdtr3, NULL, SF_FLAGS(0, 0));
786 ATF_CHECK_ERRNO(EFAULT, error == -1);
789 (void)close(client_sock);
790 (void)close(server_sock);
793 ATF_TC(hdtr_negative_bad_pointers_v4);
794 ATF_TC_HEAD(hdtr_negative_bad_pointers_v4, tc)
797 atf_tc_set_md_var(tc, "descr",
798 "Verify that bad pointers for hdtr storage result in EFAULT (IPv4)");
800 ATF_TC_BODY(hdtr_negative_bad_pointers_v4, tc)
803 hdtr_negative_bad_pointers_test(AF_INET);
806 ATF_TC(hdtr_negative_bad_pointers_v6);
807 ATF_TC_HEAD(hdtr_negative_bad_pointers_v6, tc)
810 atf_tc_set_md_var(tc, "descr",
811 "Verify that bad pointers for hdtr storage result in EFAULT (IPv6)");
813 ATF_TC_BODY(hdtr_negative_bad_pointers_v6, tc)
816 hdtr_negative_bad_pointers_test(AF_INET6);
820 offset_negative_value_less_than_zero_test(int domain)
822 int client_sock, error, fd, port, server_sock;
824 port = generate_random_port(__LINE__ + domain);
825 server_sock = setup_tcp_server(domain, port);
826 client_sock = setup_tcp_client(domain, port);
828 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
829 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
831 error = sendfile(fd, client_sock, -1, 0, NULL, NULL, SF_FLAGS(0, 0));
832 ATF_REQUIRE_ERRNO(EINVAL, error == -1);
835 (void)close(client_sock);
836 (void)close(server_sock);
839 ATF_TC(offset_negative_value_less_than_zero_v4);
840 ATF_TC_HEAD(offset_negative_value_less_than_zero_v4, tc)
843 atf_tc_set_md_var(tc, "descr",
844 "Verify that a negative offset results in EINVAL (IPv4)");
846 ATF_TC_BODY(offset_negative_value_less_than_zero_v4, tc)
849 offset_negative_value_less_than_zero_test(AF_INET);
852 ATF_TC(offset_negative_value_less_than_zero_v6);
853 ATF_TC_HEAD(offset_negative_value_less_than_zero_v6, tc)
856 atf_tc_set_md_var(tc, "descr",
857 "Verify that a negative offset results in EINVAL (IPv6)");
859 ATF_TC_BODY(offset_negative_value_less_than_zero_v6, tc)
862 offset_negative_value_less_than_zero_test(AF_INET6);
866 sbytes_positive_test(int domain)
868 size_t pattern_size = strlen(DETERMINISTIC_PATTERN);
870 int client_sock, error, fd, port, server_sock;
872 port = generate_random_port(__LINE__ + domain);
873 server_sock = setup_tcp_server(domain, port);
874 client_sock = setup_tcp_client(domain, port);
876 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
877 fd = open(SOURCE_FILE, O_RDONLY);
878 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
880 error = sendfile(fd, client_sock, 0, 0, NULL, &sbytes, SF_FLAGS(0, 0));
881 ATF_CHECK_EQ_MSG(error, 0, "sendfile failed: %s", strerror(errno));
884 (void)close(client_sock);
885 (void)close(server_sock);
887 ATF_CHECK_EQ_MSG(pattern_size, sbytes,
888 "the value returned by sbytes does not match the expected pattern "
892 ATF_TC(sbytes_positive_v4);
893 ATF_TC_HEAD(sbytes_positive_v4, tc)
896 atf_tc_set_md_var(tc, "descr",
897 "Verify positive `sbytes` functionality (IPv4)");
899 ATF_TC_BODY(sbytes_positive_v4, tc)
902 sbytes_positive_test(AF_INET);
905 ATF_TC(sbytes_positive_v6);
906 ATF_TC_HEAD(sbytes_positive_v6, tc)
909 atf_tc_set_md_var(tc, "descr",
910 "Verify positive `sbytes` functionality (IPv6)");
912 ATF_TC_BODY(sbytes_positive_v6, tc)
915 sbytes_positive_test(AF_INET6);
919 sbytes_negative_test(int domain)
921 off_t *sbytes_p = (off_t*)-1;
922 int client_sock, error, fd, port, server_sock;
924 port = generate_random_port(__LINE__ + domain);
925 server_sock = setup_tcp_server(domain, port);
926 client_sock = setup_tcp_client(domain, port);
928 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
929 fd = open(SOURCE_FILE, O_RDONLY);
930 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
933 "bug 232210: EFAULT assert fails because copyout(9) call is not checked");
935 error = sendfile(fd, client_sock, 0, 0, NULL, sbytes_p, SF_FLAGS(0, 0));
936 ATF_REQUIRE_ERRNO(EFAULT, error == -1);
939 (void)close(client_sock);
940 (void)close(server_sock);
943 ATF_TC(sbytes_negative_v4);
944 ATF_TC_HEAD(sbytes_negative_v4, tc)
947 atf_tc_set_md_var(tc, "descr",
948 "Verify negative `sbytes` functionality (IPv4)");
950 ATF_TC_BODY(sbytes_negative_v4, tc)
953 sbytes_negative_test(AF_INET);
956 ATF_TC(sbytes_negative_v6);
957 ATF_TC_HEAD(sbytes_negative_v6, tc)
960 atf_tc_set_md_var(tc, "descr",
961 "Verify negative `sbytes` functionality (IPv6)");
963 ATF_TC_BODY(sbytes_negative_v6, tc)
966 sbytes_negative_test(AF_INET6);
970 s_negative_not_connected_socket_test(int domain)
972 int client_sock, error, fd, port;
974 port = generate_random_port(__LINE__ + domain);
975 client_sock = setup_tcp_server(domain, port);
977 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
978 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
980 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
981 ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
984 (void)close(client_sock);
987 ATF_TC(s_negative_not_connected_socket_v4);
988 ATF_TC_HEAD(s_negative_not_connected_socket_v4, tc)
991 atf_tc_set_md_var(tc, "descr",
992 "Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv4)");
995 ATF_TC_BODY(s_negative_not_connected_socket_v4, tc)
998 s_negative_not_connected_socket_test(AF_INET);
1001 ATF_TC(s_negative_not_connected_socket_v6);
1002 ATF_TC_HEAD(s_negative_not_connected_socket_v6, tc)
1005 atf_tc_set_md_var(tc, "descr",
1006 "Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv6)");
1009 ATF_TC_BODY(s_negative_not_connected_socket_v6, tc)
1012 s_negative_not_connected_socket_test(AF_INET6);
1015 ATF_TC(s_negative_not_descriptor);
1016 ATF_TC_HEAD(s_negative_not_descriptor, tc)
1019 atf_tc_set_md_var(tc, "descr",
1020 "Verify that an invalid file descriptor, e.g., -1, fails with EBADF");
1023 ATF_TC_BODY(s_negative_not_descriptor, tc)
1025 int client_sock, error, fd;
1029 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1030 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1032 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1033 ATF_REQUIRE_ERRNO(EBADF, error == -1);
1038 ATF_TC(s_negative_not_socket_file_descriptor);
1039 ATF_TC_HEAD(s_negative_not_socket_file_descriptor, tc)
1042 atf_tc_set_md_var(tc, "descr",
1043 "Verify that a non-socket file descriptor fails with ENOTSOCK");
1046 ATF_TC_BODY(s_negative_not_socket_file_descriptor, tc)
1048 int client_sock, error, fd;
1050 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1051 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1053 client_sock = open(_PATH_DEVNULL, O_WRONLY);
1054 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1056 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1057 ATF_REQUIRE_ERRNO(ENOTSOCK, error == -1);
1060 (void)close(client_sock);
1064 s_negative_udp_socket_test(int domain)
1066 int client_sock, error, fd, port;
1068 port = generate_random_port(__LINE__ + domain);
1069 client_sock = setup_client(domain, SOCK_DGRAM, port);
1071 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1072 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1074 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1075 ATF_REQUIRE_ERRNO(EINVAL, error == -1);
1078 (void)close(client_sock);
1081 ATF_TC(s_negative_udp_socket_v4);
1082 ATF_TC_HEAD(s_negative_udp_socket_v4, tc)
1085 atf_tc_set_md_var(tc, "descr",
1086 "Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv4)");
1088 ATF_TC_BODY(s_negative_udp_socket_v4, tc)
1091 s_negative_udp_socket_test(AF_INET);
1094 ATF_TC(s_negative_udp_socket_v6);
1095 ATF_TC_HEAD(s_negative_udp_socket_v6, tc)
1098 atf_tc_set_md_var(tc, "descr",
1099 "Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv6)");
1101 ATF_TC_BODY(s_negative_udp_socket_v6, tc)
1104 s_negative_udp_socket_test(AF_INET6);
1110 ATF_TP_ADD_TC(tp, fd_positive_file_v4);
1111 ATF_TP_ADD_TC(tp, fd_positive_file_v6);
1112 ATF_TP_ADD_TC(tp, fd_positive_shm_v4);
1113 ATF_TP_ADD_TC(tp, fd_positive_shm_v6);
1114 ATF_TP_ADD_TC(tp, fd_negative_bad_fd_v4);
1115 ATF_TP_ADD_TC(tp, fd_negative_bad_fd_v6);
1116 ATF_TP_ADD_TC(tp, flags_v4);
1117 ATF_TP_ADD_TC(tp, flags_v6);
1119 * TODO: the negative case for SF_NODISKIO (returns EBUSY if file in
1120 * use) is not covered yet.
1122 * Need to lock a file in a subprocess in write mode, then try and
1123 * send the data in read mode with sendfile.
1125 * This should work with FFS/UFS, but there are no guarantees about
1126 * other filesystem implementations of sendfile(2), e.g., ZFS.
1128 ATF_TP_ADD_TC(tp, hdtr_positive_v4);
1129 ATF_TP_ADD_TC(tp, hdtr_positive_v6);
1130 ATF_TP_ADD_TC(tp, hdtr_negative_bad_pointers_v4);
1131 ATF_TP_ADD_TC(tp, hdtr_negative_bad_pointers_v6);
1132 ATF_TP_ADD_TC(tp, offset_negative_value_less_than_zero_v4);
1133 ATF_TP_ADD_TC(tp, offset_negative_value_less_than_zero_v6);
1134 ATF_TP_ADD_TC(tp, sbytes_positive_v4);
1135 ATF_TP_ADD_TC(tp, sbytes_positive_v6);
1136 ATF_TP_ADD_TC(tp, sbytes_negative_v4);
1137 ATF_TP_ADD_TC(tp, sbytes_negative_v6);
1138 ATF_TP_ADD_TC(tp, s_negative_not_connected_socket_v4);
1139 ATF_TP_ADD_TC(tp, s_negative_not_connected_socket_v6);
1140 ATF_TP_ADD_TC(tp, s_negative_not_descriptor);
1141 ATF_TP_ADD_TC(tp, s_negative_not_socket_file_descriptor);
1142 ATF_TP_ADD_TC(tp, s_negative_udp_socket_v4);
1143 ATF_TP_ADD_TC(tp, s_negative_udp_socket_v6);
1145 return (atf_no_error());