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