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