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)
102 struct addrinfo hints;
113 atf_tc_fail("unhandled domain: %d", domain);
116 ATF_REQUIRE_MSG(asprintf(&serv, "%d", port) >= 0,
117 "asprintf failed: %s", strerror(errno));
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;
124 error = getaddrinfo(host, serv, &hints, res);
125 ATF_REQUIRE_EQ_MSG(error, 0,
126 "getaddrinfo failed: %s", gai_strerror(error));
131 make_socket(int domain, int type, int protocol)
135 sock = socket(domain, type, protocol);
136 ATF_REQUIRE_MSG(sock != -1, "socket(%d, %d, 0) failed: %s",
137 domain, type, strerror(errno));
143 setup_client(int domain, int type, int port)
145 struct addrinfo *res;
146 char host[NI_MAXHOST+1];
149 resolve_localhost(&res, domain, type, port);
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));
156 "Will try to connect to host='%s', address_family=%d, "
158 host, res->ai_family, res->ai_socktype);
159 sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
160 error = connect(sock, (struct sockaddr*)res->ai_addr, res->ai_addrlen);
162 ATF_REQUIRE_EQ_MSG(error, 0, "connect failed: %s", strerror(errno));
167 * XXX: use linear probing to find a free port and eliminate `port` argument as
168 * a [const] int (it will need to be a pointer so it can be passed back out of
169 * the function and can influence which port `setup_client(..)` connects on.
172 setup_server(int domain, int type, int port)
174 struct addrinfo *res;
175 char host[NI_MAXHOST+1];
178 resolve_localhost(&res, domain, type, port);
179 sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
182 (const struct sockaddr*)res->ai_addr, res->ai_addrlen,
183 host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST);
184 ATF_REQUIRE_EQ_MSG(error, 0,
185 "getnameinfo failed: %s", gai_strerror(error));
187 "Will try to bind socket to host='%s', address_family=%d, "
189 host, res->ai_family, res->ai_socktype);
190 error = bind(sock, res->ai_addr, res->ai_addrlen);
192 ATF_REQUIRE_EQ_MSG(error, 0, "bind failed: %s", strerror(errno));
193 error = listen(sock, 1);
194 ATF_REQUIRE_EQ_MSG(error, 0, "listen failed: %s", strerror(errno));
200 * This function is a helper routine for taking data being sent by `sendfile` via
201 * `server_sock`, and pushing the received stream out to a file, denoted by
205 server_cat(const char *dest_filename, int server_sock, size_t len)
209 ssize_t received_bytes;
211 buffer = calloc(len + 1, sizeof(char));
213 err(1, "malloc failed");
215 recv_sock = accept(server_sock, NULL, 0);
217 err(1, "accept failed");
220 * XXX: this assumes the simplest case where all data is received in a
221 * single recv(2) call.
223 if (recv(recv_sock, buffer, len, 0) == -1)
224 err(1, "recv failed");
226 atf_utils_create_file(dest_filename, "%s", buffer);
229 * This recv(2) call helps ensure the amount of sent data is exactly
230 * what was specified by `len`.
232 received_bytes = recv(recv_sock, buffer, len, 0);
233 switch (received_bytes) {
235 err(1, "recv failed");
239 errx(1, "received unexpected data: %s", buffer);
242 (void)close(recv_sock);
243 (void)close(server_sock);
248 setup_tcp_server(int domain, int port)
251 return (setup_server(domain, SOCK_STREAM, port));
255 setup_tcp_client(int domain, int port)
258 return (setup_client(domain, SOCK_STREAM, port));
262 file_size_from_fd(int fd)
266 ATF_REQUIRE_EQ_MSG(0, fstat(fd, &st),
267 "fstat failed: %s", strerror(errno));
273 * NB: `nbytes` == 0 has special connotations given the sendfile(2) API
274 * contract. In short, "send the whole file" (paraphrased).
277 verify_source_and_dest(const char* dest_filename, int src_fd, off_t offset,
280 char *dest_pointer, *src_pointer;
281 off_t dest_file_size, src_file_size;
285 atf_utils_cat_file(dest_filename, "dest_file: ");
287 dest_fd = open(dest_filename, O_RDONLY);
288 ATF_REQUIRE_MSG(dest_fd != -1, "open failed");
290 dest_file_size = file_size_from_fd(dest_fd);
291 src_file_size = file_size_from_fd(src_fd);
294 * Per sendfile(2), "send the whole file" (paraphrased). This means
295 * that we need to grab the file size, as passing in length = 0 with
296 * mmap(2) will result in a failure with EINVAL (length = 0 is invalid).
298 length = (nbytes == 0) ? (size_t)(src_file_size - offset) : nbytes;
300 ATF_REQUIRE_EQ_MSG(dest_file_size, length,
301 "number of bytes written out to %s (%ju) doesn't match the "
302 "expected number of bytes (%zu)", dest_filename, dest_file_size,
305 ATF_REQUIRE_EQ_MSG(0, lseek(src_fd, offset, SEEK_SET),
306 "lseek failed: %s", strerror(errno));
308 dest_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, dest_fd, 0);
309 ATF_REQUIRE_MSG(dest_pointer != MAP_FAILED, "mmap failed: %s",
312 printf("Will mmap in the source file from offset=%jd to length=%zu\n",
315 src_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, src_fd, offset);
316 ATF_REQUIRE_MSG(src_pointer != MAP_FAILED, "mmap failed: %s",
319 ATF_REQUIRE_EQ_MSG(0, memcmp(src_pointer, dest_pointer, length),
320 "Contents of source and destination do not match. '%s' != '%s'",
321 src_pointer, dest_pointer);
323 (void)munmap(src_pointer, length);
324 (void)munmap(dest_pointer, length);
325 (void)close(dest_fd);
329 fd_positive_file_test(int domain)
332 size_t nbytes, pattern_size;
333 int client_sock, error, fd, port, server_sock;
336 pattern_size = strlen(DETERMINISTIC_PATTERN);
338 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
339 fd = open(SOURCE_FILE, O_RDONLY);
340 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
342 port = generate_random_port(__LINE__ + domain);
343 server_sock = setup_tcp_server(domain, port);
344 client_sock = setup_tcp_client(domain, port);
346 server_pid = atf_utils_fork();
347 if (server_pid == 0) {
348 (void)close(client_sock);
349 server_cat(DESTINATION_FILE, server_sock, pattern_size);
352 (void)close(server_sock);
356 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
358 ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
359 (void)close(client_sock);
361 atf_utils_wait(server_pid, 0, "", "");
362 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
367 ATF_TC(fd_positive_file_v4);
368 ATF_TC_HEAD(fd_positive_file_v4, tc)
371 atf_tc_set_md_var(tc, "descr",
372 "Verify regular file as file descriptor support (IPv4)");
374 ATF_TC_BODY(fd_positive_file_v4, tc)
377 fd_positive_file_test(AF_INET);
380 ATF_TC(fd_positive_file_v6);
381 ATF_TC_HEAD(fd_positive_file_v6, tc)
384 atf_tc_set_md_var(tc, "descr",
385 "Verify regular file as file descriptor support (IPv6)");
387 ATF_TC_BODY(fd_positive_file_v6, tc)
390 fd_positive_file_test(AF_INET6);
394 fd_positive_shm_test(int domain)
398 size_t nbytes, pattern_size;
400 int client_sock, error, fd, port, server_sock;
402 pattern_size = strlen(DETERMINISTIC_PATTERN);
404 printf("pattern size: %zu\n", pattern_size);
406 fd = shm_open(SHM_ANON, O_RDWR|O_CREAT, 0600);
407 ATF_REQUIRE_MSG(fd != -1, "shm_open failed: %s", strerror(errno));
408 ATF_REQUIRE_EQ_MSG(0, ftruncate(fd, pattern_size),
409 "ftruncate failed: %s", strerror(errno));
410 shm_pointer = mmap(NULL, pattern_size, PROT_READ|PROT_WRITE,
412 ATF_REQUIRE_MSG(shm_pointer != MAP_FAILED,
413 "mmap failed: %s", strerror(errno));
414 memcpy(shm_pointer, DETERMINISTIC_PATTERN, pattern_size);
415 ATF_REQUIRE_EQ_MSG(0,
416 memcmp(shm_pointer, DETERMINISTIC_PATTERN, pattern_size),
417 "memcmp showed data mismatch: '%s' != '%s'",
418 DETERMINISTIC_PATTERN, shm_pointer);
420 port = generate_random_port(__LINE__ + domain);
421 server_sock = setup_tcp_server(domain, port);
422 client_sock = setup_tcp_client(domain, port);
424 server_pid = atf_utils_fork();
425 if (server_pid == 0) {
426 (void)close(client_sock);
427 server_cat(DESTINATION_FILE, server_sock, pattern_size);
430 (void)close(server_sock);
434 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
436 ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
437 (void)close(client_sock);
439 atf_utils_wait(server_pid, 0, "", "");
440 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
442 (void)munmap(shm_pointer, sizeof(DETERMINISTIC_PATTERN));
446 ATF_TC(fd_positive_shm_v4);
447 ATF_TC_HEAD(fd_positive_shm_v4, tc)
450 atf_tc_set_md_var(tc, "descr",
451 "Verify shared memory as file descriptor support (IPv4)");
453 ATF_TC_BODY(fd_positive_shm_v4, tc)
456 fd_positive_shm_test(AF_INET);
459 ATF_TC(fd_positive_shm_v6);
460 ATF_TC_HEAD(fd_positive_shm_v6, tc)
463 atf_tc_set_md_var(tc, "descr",
464 "Verify shared memory as file descriptor support (IPv6))");
466 ATF_TC_BODY(fd_positive_shm_v6, tc)
469 fd_positive_shm_test(AF_INET6);
473 fd_negative_bad_fd_test(int domain)
475 int client_sock, error, fd, port, server_sock;
477 port = generate_random_port(__LINE__ + domain);
478 server_sock = setup_tcp_server(domain, port);
479 client_sock = setup_tcp_client(domain, port);
483 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
484 ATF_REQUIRE_ERRNO(EBADF, error == -1);
486 (void)close(client_sock);
487 (void)close(server_sock);
490 ATF_TC(fd_negative_bad_fd_v4);
491 ATF_TC_HEAD(fd_negative_bad_fd_v4, tc)
494 atf_tc_set_md_var(tc, "descr",
495 "Verify bad file descriptor returns EBADF (IPv4)");
497 ATF_TC_BODY(fd_negative_bad_fd_v4, tc)
500 fd_negative_bad_fd_test(AF_INET);
503 ATF_TC(fd_negative_bad_fd_v6);
504 ATF_TC_HEAD(fd_negative_bad_fd_v6, tc)
507 atf_tc_set_md_var(tc, "descr",
508 "Verify bad file descriptor returns EBADF (IPv6)");
510 ATF_TC_BODY(fd_negative_bad_fd_v6, tc)
513 fd_negative_bad_fd_test(AF_INET6);
517 flags_test(int domain)
520 size_t nbytes, pattern_size;
521 int client_sock, error, fd, i, port, server_sock;
523 int16_t number_pages = 10;
525 pattern_size = strlen(DETERMINISTIC_PATTERN);
528 int16_t readahead_pages, flags;
530 /* This is covered in `:fd_positive_file` */
533 .readahead_pages = 0,
538 .readahead_pages = 0,
541 #ifdef SF_USER_READAHEAD
543 .readahead_pages = 0,
544 .flags = SF_NOCACHE|SF_USER_READAHEAD
547 .readahead_pages = 0,
548 .flags = SF_USER_READAHEAD
552 .readahead_pages = number_pages,
556 .readahead_pages = number_pages,
559 #ifdef SF_USER_READAHEAD
561 .readahead_pages = number_pages,
562 .flags = SF_NOCACHE|SF_USER_READAHEAD
566 .readahead_pages = number_pages,
570 .readahead_pages = number_pages,
575 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
576 for (i = 0; i < nitems(testcases); i++) {
577 fd = open(SOURCE_FILE, O_RDONLY);
578 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
580 port = generate_random_port(i * __LINE__ + domain);
581 server_sock = setup_tcp_server(domain, port);
582 client_sock = setup_tcp_client(domain, port);
584 server_pid = atf_utils_fork();
585 if (server_pid == 0) {
586 (void)close(client_sock);
587 server_cat(DESTINATION_FILE, server_sock, pattern_size);
590 (void)close(server_sock);
594 error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
595 SF_FLAGS(testcases[i].readahead_pages, testcases[i].flags));
596 ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s",
598 (void)close(client_sock);
600 atf_utils_wait(server_pid, 0, "", "");
601 verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
608 ATF_TC_HEAD(flags_v4, tc)
611 atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv4)");
613 ATF_TC_BODY(flags_v4, tc)
620 ATF_TC_HEAD(flags_v6, tc)
623 atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv6)");
625 ATF_TC_BODY(flags_v6, tc)
628 flags_test(AF_INET6);
632 hdtr_positive_test(int domain)
634 struct iovec headers[1], trailers[1];
636 bool include_headers, include_trailers;
638 /* This is covered in `:fd_positive_file` */
641 .include_headers = false,
642 .include_trailers = false
646 .include_headers = true,
647 .include_trailers = false
650 .include_headers = false,
651 .include_trailers = true
654 .include_headers = true,
655 .include_trailers = true
660 int client_sock, error, fd, fd2, i, port, rc, server_sock;
663 headers[0].iov_base = "This is a header";
664 headers[0].iov_len = strlen(headers[0].iov_base);
665 trailers[0].iov_base = "This is a trailer";
666 trailers[0].iov_len = strlen(trailers[0].iov_base);
671 "The header/trailer testcases fail today with a data mismatch; "
674 for (i = 0; i < nitems(testcases); i++) {
678 if (testcases[i].include_headers) {
679 hdtr.headers = headers;
680 hdtr.hdr_cnt = nitems(headers);
686 if (testcases[i].include_trailers) {
687 hdtr.trailers = trailers;
688 hdtr.trl_cnt = nitems(trailers);
690 hdtr.trailers = NULL;
694 port = generate_random_port(i * __LINE__ + domain);
695 server_sock = setup_tcp_server(domain, port);
696 client_sock = setup_tcp_client(domain, port);
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));
704 atf_utils_create_file(SOURCE_FILE ".full", "%s", pattern);
705 atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
707 fd = open(SOURCE_FILE, O_RDONLY);
708 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
710 fd2 = open(SOURCE_FILE ".full", O_RDONLY);
711 ATF_REQUIRE_MSG(fd2 != -1, "open failed: %s", strerror(errno));
713 server_pid = atf_utils_fork();
714 if (server_pid == 0) {
715 (void)close(client_sock);
716 server_cat(DESTINATION_FILE, server_sock,
720 (void)close(server_sock);
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",
726 (void)close(client_sock);
728 atf_utils_wait(server_pid, 0, "", "");
729 verify_source_and_dest(DESTINATION_FILE, fd2, offset, nbytes);
738 ATF_TC(hdtr_positive_v4);
739 ATF_TC_HEAD(hdtr_positive_v4, tc)
742 atf_tc_set_md_var(tc, "descr",
743 "Verify positive hdtr functionality (IPv4)");
745 ATF_TC_BODY(hdtr_positive_v4, tc)
748 hdtr_positive_test(AF_INET);
751 ATF_TC(hdtr_positive_v6);
752 ATF_TC_HEAD(hdtr_positive_v6, tc)
755 atf_tc_set_md_var(tc, "descr",
756 "Verify positive hdtr functionality (IPv6)");
758 ATF_TC_BODY(hdtr_positive_v6, tc)
761 hdtr_positive_test(AF_INET);
765 hdtr_negative_bad_pointers_test(int domain)
767 int client_sock, error, fd, port, server_sock;
768 struct sf_hdtr *hdtr1, hdtr2, hdtr3;
770 port = generate_random_port(__LINE__ + domain);
772 hdtr1 = (struct sf_hdtr*)-1;
774 memset(&hdtr2, 0, sizeof(hdtr2));
776 hdtr2.headers = (struct iovec*)-1;
778 memset(&hdtr3, 0, sizeof(hdtr3));
780 hdtr3.trailers = (struct iovec*)-1;
782 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
783 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
785 server_sock = setup_tcp_server(domain, port);
786 client_sock = setup_tcp_client(domain, port);
788 error = sendfile(fd, client_sock, 0, 0, hdtr1, NULL, SF_FLAGS(0, 0));
789 ATF_CHECK_ERRNO(EFAULT, error == -1);
791 error = sendfile(fd, client_sock, 0, 0, &hdtr2, NULL, SF_FLAGS(0, 0));
792 ATF_CHECK_ERRNO(EFAULT, error == -1);
794 error = sendfile(fd, client_sock, 0, 0, &hdtr3, NULL, SF_FLAGS(0, 0));
795 ATF_CHECK_ERRNO(EFAULT, error == -1);
798 (void)close(client_sock);
799 (void)close(server_sock);
802 ATF_TC(hdtr_negative_bad_pointers_v4);
803 ATF_TC_HEAD(hdtr_negative_bad_pointers_v4, tc)
806 atf_tc_set_md_var(tc, "descr",
807 "Verify that bad pointers for hdtr storage result in EFAULT (IPv4)");
809 ATF_TC_BODY(hdtr_negative_bad_pointers_v4, tc)
812 hdtr_negative_bad_pointers_test(AF_INET);
815 ATF_TC(hdtr_negative_bad_pointers_v6);
816 ATF_TC_HEAD(hdtr_negative_bad_pointers_v6, tc)
819 atf_tc_set_md_var(tc, "descr",
820 "Verify that bad pointers for hdtr storage result in EFAULT (IPv6)");
822 ATF_TC_BODY(hdtr_negative_bad_pointers_v6, tc)
825 hdtr_negative_bad_pointers_test(AF_INET6);
829 offset_negative_value_less_than_zero_test(int domain)
831 int client_sock, error, fd, port, server_sock;
833 port = generate_random_port(__LINE__ + domain);
834 server_sock = setup_tcp_server(domain, port);
835 client_sock = setup_tcp_client(domain, port);
837 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
838 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
840 error = sendfile(fd, client_sock, -1, 0, NULL, NULL, SF_FLAGS(0, 0));
841 ATF_REQUIRE_ERRNO(EINVAL, error == -1);
844 (void)close(client_sock);
845 (void)close(server_sock);
848 ATF_TC(offset_negative_value_less_than_zero_v4);
849 ATF_TC_HEAD(offset_negative_value_less_than_zero_v4, tc)
852 atf_tc_set_md_var(tc, "descr",
853 "Verify that a negative offset results in EINVAL (IPv4)");
855 ATF_TC_BODY(offset_negative_value_less_than_zero_v4, tc)
858 offset_negative_value_less_than_zero_test(AF_INET);
861 ATF_TC(offset_negative_value_less_than_zero_v6);
862 ATF_TC_HEAD(offset_negative_value_less_than_zero_v6, tc)
865 atf_tc_set_md_var(tc, "descr",
866 "Verify that a negative offset results in EINVAL (IPv6)");
868 ATF_TC_BODY(offset_negative_value_less_than_zero_v6, tc)
871 offset_negative_value_less_than_zero_test(AF_INET6);
875 sbytes_positive_test(int domain)
877 size_t pattern_size = strlen(DETERMINISTIC_PATTERN);
879 int client_sock, error, fd, port, server_sock;
881 port = generate_random_port(__LINE__ + domain);
882 server_sock = setup_tcp_server(domain, port);
883 client_sock = setup_tcp_client(domain, port);
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));
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));
893 (void)close(client_sock);
894 (void)close(server_sock);
896 ATF_CHECK_EQ_MSG(pattern_size, sbytes,
897 "the value returned by sbytes does not match the expected pattern "
901 ATF_TC(sbytes_positive_v4);
902 ATF_TC_HEAD(sbytes_positive_v4, tc)
905 atf_tc_set_md_var(tc, "descr",
906 "Verify positive `sbytes` functionality (IPv4)");
908 ATF_TC_BODY(sbytes_positive_v4, tc)
911 sbytes_positive_test(AF_INET);
914 ATF_TC(sbytes_positive_v6);
915 ATF_TC_HEAD(sbytes_positive_v6, tc)
918 atf_tc_set_md_var(tc, "descr",
919 "Verify positive `sbytes` functionality (IPv6)");
921 ATF_TC_BODY(sbytes_positive_v6, tc)
924 sbytes_positive_test(AF_INET6);
928 sbytes_negative_test(int domain)
930 off_t *sbytes_p = (off_t*)-1;
931 int client_sock, error, fd, port, server_sock;
933 port = generate_random_port(__LINE__ + domain);
934 server_sock = setup_tcp_server(domain, port);
935 client_sock = setup_tcp_client(domain, port);
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));
942 "bug 232210: EFAULT assert fails because copyout(9) call is not checked");
944 error = sendfile(fd, client_sock, 0, 0, NULL, sbytes_p, SF_FLAGS(0, 0));
945 ATF_REQUIRE_ERRNO(EFAULT, error == -1);
948 (void)close(client_sock);
949 (void)close(server_sock);
952 ATF_TC(sbytes_negative_v4);
953 ATF_TC_HEAD(sbytes_negative_v4, tc)
956 atf_tc_set_md_var(tc, "descr",
957 "Verify negative `sbytes` functionality (IPv4)");
959 ATF_TC_BODY(sbytes_negative_v4, tc)
962 sbytes_negative_test(AF_INET);
965 ATF_TC(sbytes_negative_v6);
966 ATF_TC_HEAD(sbytes_negative_v6, tc)
969 atf_tc_set_md_var(tc, "descr",
970 "Verify negative `sbytes` functionality (IPv6)");
972 ATF_TC_BODY(sbytes_negative_v6, tc)
975 sbytes_negative_test(AF_INET6);
979 s_negative_not_connected_socket_test(int domain)
981 int client_sock, error, fd, port;
983 port = generate_random_port(__LINE__ + domain);
984 client_sock = setup_tcp_server(domain, port);
986 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
987 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
989 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
990 ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
993 (void)close(client_sock);
996 ATF_TC(s_negative_not_connected_socket_v4);
997 ATF_TC_HEAD(s_negative_not_connected_socket_v4, tc)
1000 atf_tc_set_md_var(tc, "descr",
1001 "Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv4)");
1004 ATF_TC_BODY(s_negative_not_connected_socket_v4, tc)
1007 s_negative_not_connected_socket_test(AF_INET);
1010 ATF_TC(s_negative_not_connected_socket_v6);
1011 ATF_TC_HEAD(s_negative_not_connected_socket_v6, tc)
1014 atf_tc_set_md_var(tc, "descr",
1015 "Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv6)");
1018 ATF_TC_BODY(s_negative_not_connected_socket_v6, tc)
1021 s_negative_not_connected_socket_test(AF_INET6);
1024 ATF_TC(s_negative_not_descriptor);
1025 ATF_TC_HEAD(s_negative_not_descriptor, tc)
1028 atf_tc_set_md_var(tc, "descr",
1029 "Verify that an invalid file descriptor, e.g., -1, fails with EBADF");
1032 ATF_TC_BODY(s_negative_not_descriptor, tc)
1034 int client_sock, error, fd;
1038 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1039 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1041 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1042 ATF_REQUIRE_ERRNO(EBADF, error == -1);
1047 ATF_TC(s_negative_not_socket_file_descriptor);
1048 ATF_TC_HEAD(s_negative_not_socket_file_descriptor, tc)
1051 atf_tc_set_md_var(tc, "descr",
1052 "Verify that a non-socket file descriptor fails with ENOTSOCK");
1055 ATF_TC_BODY(s_negative_not_socket_file_descriptor, tc)
1057 int client_sock, error, fd;
1059 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1060 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1062 client_sock = open(_PATH_DEVNULL, O_WRONLY);
1063 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1065 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1066 ATF_REQUIRE_ERRNO(ENOTSOCK, error == -1);
1069 (void)close(client_sock);
1073 s_negative_udp_socket_test(int domain)
1075 int client_sock, error, fd, port;
1077 port = generate_random_port(__LINE__ + domain);
1078 client_sock = setup_client(domain, SOCK_DGRAM, port);
1080 fd = open(SOURCE_FILE, O_CREAT|O_RDWR);
1081 ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
1083 error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
1084 ATF_REQUIRE_ERRNO(EINVAL, error == -1);
1087 (void)close(client_sock);
1090 ATF_TC(s_negative_udp_socket_v4);
1091 ATF_TC_HEAD(s_negative_udp_socket_v4, tc)
1094 atf_tc_set_md_var(tc, "descr",
1095 "Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv4)");
1097 ATF_TC_BODY(s_negative_udp_socket_v4, tc)
1100 s_negative_udp_socket_test(AF_INET);
1103 ATF_TC(s_negative_udp_socket_v6);
1104 ATF_TC_HEAD(s_negative_udp_socket_v6, tc)
1107 atf_tc_set_md_var(tc, "descr",
1108 "Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv6)");
1110 ATF_TC_BODY(s_negative_udp_socket_v6, tc)
1113 s_negative_udp_socket_test(AF_INET6);
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);
1128 * TODO: the negative case for SF_NODISKIO (returns EBUSY if file in
1129 * use) is not covered yet.
1131 * Need to lock a file in a subprocess in write mode, then try and
1132 * send the data in read mode with sendfile.
1134 * This should work with FFS/UFS, but there are no guarantees about
1135 * other filesystem implementations of sendfile(2), e.g., ZFS.
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);
1154 return (atf_no_error());