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