freebsd-nq/lib/libc/tests/sys/sendfile_test.c

1158 lines
29 KiB
C
Raw Normal View History

Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
/*-
* Copyright (c) 2018 Enji Cooper.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
const char DETERMINISTIC_PATTERN[] =
"The past is already gone, the future is not yet here. There's only one moment for you to live.\n";
#define SOURCE_FILE "source"
#define DESTINATION_FILE "dest"
#define PORTRANGE_FIRST "net.inet.ip.portrange.first"
#define PORTRANGE_LAST "net.inet.ip.portrange.last"
static int portrange_first, portrange_last;
static int
get_int_via_sysctlbyname(const char *oidname)
{
size_t oldlen;
int int_value;
oldlen = sizeof(int_value);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_EQ_MSG(sysctlbyname(oidname, &int_value, &oldlen, NULL, 0),
0, "sysctlbyname(%s, ...) failed: %s", oidname, strerror(errno));
ATF_REQUIRE_EQ_MSG(sizeof(int_value), oldlen, "sanity check failed");
return (int_value);
}
static int
generate_random_port(int seed)
{
int random_port;
printf("Generating a random port with seed=%d\n", seed);
if (portrange_first == 0) {
portrange_first = get_int_via_sysctlbyname(PORTRANGE_FIRST);
printf("Port range lower bound: %d\n", portrange_first);
}
if (portrange_last == 0) {
portrange_last = get_int_via_sysctlbyname(PORTRANGE_LAST);
printf("Port range upper bound: %d\n", portrange_last);
}
srand((unsigned)seed);
random_port = rand() % (portrange_last - portrange_first) +
portrange_first;
printf("Random port generated: %d\n", random_port);
return (random_port);
}
static void
resolve_localhost(struct addrinfo **res, int domain, int type, int port)
{
const char *host;
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
char *serv;
struct addrinfo hints;
int error;
switch (domain) {
case AF_INET:
host = "127.0.0.1";
break;
case AF_INET6:
host = "::1";
break;
default:
atf_tc_fail("unhandled domain: %d", domain);
}
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_MSG(asprintf(&serv, "%d", port) >= 0,
"asprintf failed: %s", strerror(errno));
memset(&hints, 0, sizeof(hints));
hints.ai_family = domain;
hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV|AI_NUMERICHOST;
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
hints.ai_socktype = type;
error = getaddrinfo(host, serv, &hints, res);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_EQ_MSG(error, 0,
"getaddrinfo failed: %s", gai_strerror(error));
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
free(serv);
}
static int
make_socket(int domain, int type, int protocol)
{
int sock;
sock = socket(domain, type, protocol);
ATF_REQUIRE_MSG(sock != -1, "socket(%d, %d, 0) failed: %s",
domain, type, strerror(errno));
return (sock);
}
static int
setup_client(int domain, int type, int port)
{
struct addrinfo *res;
char host[NI_MAXHOST+1];
int error, sock;
resolve_localhost(&res, domain, type, port);
error = getnameinfo(
(const struct sockaddr*)res->ai_addr, res->ai_addrlen,
host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST);
ATF_REQUIRE_EQ_MSG(error, 0,
"getnameinfo failed: %s", gai_strerror(error));
printf(
"Will try to connect to host='%s', address_family=%d, "
"socket_type=%d\n",
host, res->ai_family, res->ai_socktype);
/* Avoid a double print when forked by flushing. */
fflush(stdout);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
error = connect(sock, (struct sockaddr*)res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
ATF_REQUIRE_EQ_MSG(error, 0, "connect failed: %s", strerror(errno));
return (sock);
}
/*
* XXX: use linear probing to find a free port and eliminate `port` argument as
* a [const] int (it will need to be a pointer so it can be passed back out of
* the function and can influence which port `setup_client(..)` connects on.
*/
static int
setup_server(int domain, int type, int port)
{
struct addrinfo *res;
char host[NI_MAXHOST+1];
int error, sock;
resolve_localhost(&res, domain, type, port);
sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
error = getnameinfo(
(const struct sockaddr*)res->ai_addr, res->ai_addrlen,
host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST);
ATF_REQUIRE_EQ_MSG(error, 0,
"getnameinfo failed: %s", gai_strerror(error));
printf(
"Will try to bind socket to host='%s', address_family=%d, "
"socket_type=%d\n",
host, res->ai_family, res->ai_socktype);
/* Avoid a double print when forked by flushing. */
fflush(stdout);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
error = bind(sock, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
ATF_REQUIRE_EQ_MSG(error, 0, "bind failed: %s", strerror(errno));
error = listen(sock, 1);
ATF_REQUIRE_EQ_MSG(error, 0, "listen failed: %s", strerror(errno));
return (sock);
}
/*
* This function is a helper routine for taking data being sent by `sendfile` via
* `server_sock`, and pushing the received stream out to a file, denoted by
* `dest_filename`.
*/
static void
server_cat(const char *dest_filename, int server_sock, size_t len)
{
char *buffer, *buf_window_ptr;
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
int recv_sock;
size_t buffer_size;
ssize_t received_bytes, recv_ret;
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
/*
* Ensure that there isn't excess data sent across the wire by
* capturing 10 extra bytes (plus 1 for nul).
*/
buffer_size = len + 10 + 1;
buffer = calloc(buffer_size, sizeof(char));
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
if (buffer == NULL)
err(1, "malloc failed");
recv_sock = accept(server_sock, NULL, 0);
if (recv_sock == -1)
err(1, "accept failed");
buf_window_ptr = buffer;
received_bytes = 0;
do {
recv_ret = recv(recv_sock, buf_window_ptr,
buffer_size - received_bytes, 0);
if (recv_ret <= 0)
break;
buf_window_ptr += recv_ret;
received_bytes += recv_ret;
} while (received_bytes < buffer_size);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
atf_utils_create_file(dest_filename, "%s", buffer);
(void)close(recv_sock);
(void)close(server_sock);
free(buffer);
if (received_bytes != len)
errx(1, "received unexpected data: %zd != %zd", received_bytes,
len);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
}
static int
setup_tcp_server(int domain, int port)
{
return (setup_server(domain, SOCK_STREAM, port));
}
static int
setup_tcp_client(int domain, int port)
{
return (setup_client(domain, SOCK_STREAM, port));
}
static off_t
file_size_from_fd(int fd)
{
struct stat st;
ATF_REQUIRE_EQ_MSG(0, fstat(fd, &st),
"fstat failed: %s", strerror(errno));
return (st.st_size);
}
/*
* NB: `nbytes` == 0 has special connotations given the sendfile(2) API
* contract. In short, "send the whole file" (paraphrased).
*/
static void
verify_source_and_dest(const char* dest_filename, int src_fd, off_t offset,
size_t nbytes)
{
char *dest_pointer, *src_pointer;
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
off_t dest_file_size, src_file_size;
size_t length;
int dest_fd;
atf_utils_cat_file(dest_filename, "dest_file: ");
dest_fd = open(dest_filename, O_RDONLY);
ATF_REQUIRE_MSG(dest_fd != -1, "open failed");
dest_file_size = file_size_from_fd(dest_fd);
src_file_size = file_size_from_fd(src_fd);
/*
* Per sendfile(2), "send the whole file" (paraphrased). This means
* that we need to grab the file size, as passing in length = 0 with
* mmap(2) will result in a failure with EINVAL (length = 0 is invalid).
*/
length = (nbytes == 0) ? (size_t)(src_file_size - offset) : nbytes;
ATF_REQUIRE_EQ_MSG(dest_file_size, length,
"number of bytes written out to %s (%ju) doesn't match the "
"expected number of bytes (%zu)", dest_filename, dest_file_size,
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
length);
ATF_REQUIRE_EQ_MSG(0, lseek(src_fd, offset, SEEK_SET),
"lseek failed: %s", strerror(errno));
dest_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, dest_fd, 0);
ATF_REQUIRE_MSG(dest_pointer != MAP_FAILED, "mmap failed: %s",
strerror(errno));
printf("Will mmap in the source file from offset=%jd to length=%zu\n",
offset, length);
src_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, src_fd, offset);
ATF_REQUIRE_MSG(src_pointer != MAP_FAILED, "mmap failed: %s",
strerror(errno));
ATF_REQUIRE_EQ_MSG(0, memcmp(src_pointer, dest_pointer, length),
"Contents of source and destination do not match. '%s' != '%s'",
src_pointer, dest_pointer);
(void)munmap(src_pointer, length);
(void)munmap(dest_pointer, length);
(void)close(dest_fd);
}
static void
fd_positive_file_test(int domain)
{
off_t offset;
size_t nbytes, pattern_size;
int client_sock, error, fd, port, server_sock;
pid_t server_pid;
pattern_size = strlen(DETERMINISTIC_PATTERN);
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
server_pid = atf_utils_fork();
if (server_pid == 0) {
(void)close(client_sock);
server_cat(DESTINATION_FILE, server_sock, pattern_size);
_exit(0);
} else
(void)close(server_sock);
nbytes = 0;
offset = 0;
error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
SF_FLAGS(0, 0));
ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
(void)close(client_sock);
atf_utils_wait(server_pid, 0, "", "");
verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
(void)close(fd);
}
ATF_TC(fd_positive_file_v4);
ATF_TC_HEAD(fd_positive_file_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify regular file as file descriptor support (IPv4)");
}
ATF_TC_BODY(fd_positive_file_v4, tc)
{
fd_positive_file_test(AF_INET);
}
ATF_TC(fd_positive_file_v6);
ATF_TC_HEAD(fd_positive_file_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify regular file as file descriptor support (IPv6)");
}
ATF_TC_BODY(fd_positive_file_v6, tc)
{
fd_positive_file_test(AF_INET6);
}
static void
fd_positive_shm_test(int domain)
{
char *shm_pointer;
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
off_t offset;
size_t nbytes, pattern_size;
pid_t server_pid;
int client_sock, error, fd, port, server_sock;
pattern_size = strlen(DETERMINISTIC_PATTERN);
printf("pattern size: %zu\n", pattern_size);
fd = shm_open(SHM_ANON, O_RDWR|O_CREAT, 0600);
ATF_REQUIRE_MSG(fd != -1, "shm_open failed: %s", strerror(errno));
ATF_REQUIRE_EQ_MSG(0, ftruncate(fd, pattern_size),
"ftruncate failed: %s", strerror(errno));
shm_pointer = mmap(NULL, pattern_size, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
ATF_REQUIRE_MSG(shm_pointer != MAP_FAILED,
"mmap failed: %s", strerror(errno));
memcpy(shm_pointer, DETERMINISTIC_PATTERN, pattern_size);
ATF_REQUIRE_EQ_MSG(0,
memcmp(shm_pointer, DETERMINISTIC_PATTERN, pattern_size),
"memcmp showed data mismatch: '%s' != '%s'",
DETERMINISTIC_PATTERN, shm_pointer);
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
server_pid = atf_utils_fork();
if (server_pid == 0) {
(void)close(client_sock);
server_cat(DESTINATION_FILE, server_sock, pattern_size);
_exit(0);
} else
(void)close(server_sock);
nbytes = 0;
offset = 0;
error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
SF_FLAGS(0, 0));
ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
(void)close(client_sock);
atf_utils_wait(server_pid, 0, "", "");
verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
(void)munmap(shm_pointer, sizeof(DETERMINISTIC_PATTERN));
(void)close(fd);
}
ATF_TC(fd_positive_shm_v4);
ATF_TC_HEAD(fd_positive_shm_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify shared memory as file descriptor support (IPv4)");
}
ATF_TC_BODY(fd_positive_shm_v4, tc)
{
fd_positive_shm_test(AF_INET);
}
ATF_TC(fd_positive_shm_v6);
ATF_TC_HEAD(fd_positive_shm_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify shared memory as file descriptor support (IPv6))");
}
ATF_TC_BODY(fd_positive_shm_v6, tc)
{
fd_positive_shm_test(AF_INET6);
}
static void
fd_negative_bad_fd_test(int domain)
{
int client_sock, error, fd, port, server_sock;
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
fd = -1;
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EBADF, error == -1);
(void)close(client_sock);
(void)close(server_sock);
}
ATF_TC(fd_negative_bad_fd_v4);
ATF_TC_HEAD(fd_negative_bad_fd_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify bad file descriptor returns EBADF (IPv4)");
}
ATF_TC_BODY(fd_negative_bad_fd_v4, tc)
{
fd_negative_bad_fd_test(AF_INET);
}
ATF_TC(fd_negative_bad_fd_v6);
ATF_TC_HEAD(fd_negative_bad_fd_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify bad file descriptor returns EBADF (IPv6)");
}
ATF_TC_BODY(fd_negative_bad_fd_v6, tc)
{
fd_negative_bad_fd_test(AF_INET6);
}
static void
flags_test(int domain)
{
off_t offset;
size_t nbytes, pattern_size;
int client_sock, error, fd, i, port, server_sock;
pid_t server_pid;
int16_t number_pages = 10;
pattern_size = strlen(DETERMINISTIC_PATTERN);
struct testcase {
int16_t readahead_pages, flags;
} testcases[] = {
/* This is covered in `:fd_positive_file` */
#if 0
{
.readahead_pages = 0,
.flags = 0
},
#endif
{
.readahead_pages = 0,
.flags = SF_NOCACHE
},
#ifdef SF_USER_READAHEAD
{
.readahead_pages = 0,
.flags = SF_NOCACHE|SF_USER_READAHEAD
},
{
.readahead_pages = 0,
.flags = SF_USER_READAHEAD
},
#endif
{
.readahead_pages = number_pages,
.flags = 0
},
{
.readahead_pages = number_pages,
.flags = SF_NOCACHE
},
#ifdef SF_USER_READAHEAD
{
.readahead_pages = number_pages,
.flags = SF_NOCACHE|SF_USER_READAHEAD
},
#endif
{
.readahead_pages = number_pages,
.flags = SF_NOCACHE
},
{
.readahead_pages = number_pages,
.flags = SF_NODISKIO
}
};
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
for (i = 0; i < nitems(testcases); i++) {
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
port = generate_random_port(i * __LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
server_pid = atf_utils_fork();
if (server_pid == 0) {
(void)close(client_sock);
server_cat(DESTINATION_FILE, server_sock, pattern_size);
_exit(0);
} else
(void)close(server_sock);
nbytes = 0;
offset = 0;
error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
SF_FLAGS(testcases[i].readahead_pages, testcases[i].flags));
ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s",
i, strerror(errno));
(void)close(client_sock);
atf_utils_wait(server_pid, 0, "", "");
verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
(void)close(fd);
}
}
ATF_TC(flags_v4);
ATF_TC_HEAD(flags_v4, tc)
{
atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv4)");
}
ATF_TC_BODY(flags_v4, tc)
{
flags_test(AF_INET);
}
ATF_TC(flags_v6);
ATF_TC_HEAD(flags_v6, tc)
{
atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv6)");
}
ATF_TC_BODY(flags_v6, tc)
{
flags_test(AF_INET6);
}
static void
hdtr_positive_test(int domain)
{
struct iovec headers[1], trailers[1];
struct testcase {
bool include_headers, include_trailers;
} testcases[] = {
/* This is covered in `:fd_positive_file` */
#if 0
{
.include_headers = false,
.include_trailers = false
},
#endif
{
.include_headers = true,
.include_trailers = false
},
{
.include_headers = false,
.include_trailers = true
},
{
.include_headers = true,
.include_trailers = true
}
};
off_t offset;
size_t nbytes;
int client_sock, error, fd, fd2, i, port, rc, server_sock;
pid_t server_pid;
headers[0].iov_base = "This is a header";
headers[0].iov_len = strlen(headers[0].iov_base);
trailers[0].iov_base = "This is a trailer";
trailers[0].iov_len = strlen(trailers[0].iov_base);
offset = 0;
nbytes = 0;
for (i = 0; i < nitems(testcases); i++) {
struct sf_hdtr hdtr;
char *pattern;
if (testcases[i].include_headers) {
hdtr.headers = headers;
hdtr.hdr_cnt = nitems(headers);
} else {
hdtr.headers = NULL;
hdtr.hdr_cnt = 0;
}
if (testcases[i].include_trailers) {
hdtr.trailers = trailers;
hdtr.trl_cnt = nitems(trailers);
} else {
hdtr.trailers = NULL;
hdtr.trl_cnt = 0;
}
port = generate_random_port(i * __LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
rc = asprintf(&pattern, "%s%s%s",
testcases[i].include_headers ? (char *)headers[0].iov_base : "",
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
DETERMINISTIC_PATTERN,
testcases[i].include_trailers ? (char *)trailers[0].iov_base : "");
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_MSG(rc != -1, "asprintf failed: %s", strerror(errno));
atf_utils_create_file(SOURCE_FILE ".full", "%s", pattern);
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
fd2 = open(SOURCE_FILE ".full", O_RDONLY);
ATF_REQUIRE_MSG(fd2 != -1, "open failed: %s", strerror(errno));
server_pid = atf_utils_fork();
if (server_pid == 0) {
(void)close(client_sock);
server_cat(DESTINATION_FILE, server_sock,
strlen(pattern));
_exit(0);
} else
(void)close(server_sock);
error = sendfile(fd, client_sock, offset, nbytes, &hdtr,
NULL, SF_FLAGS(0, 0));
ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s",
i, strerror(errno));
(void)close(client_sock);
atf_utils_wait(server_pid, 0, "", "");
verify_source_and_dest(DESTINATION_FILE, fd2, offset, nbytes);
(void)close(fd);
(void)close(fd2);
free(pattern);
pattern = NULL;
}
}
ATF_TC(hdtr_positive_v4);
ATF_TC_HEAD(hdtr_positive_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify positive hdtr functionality (IPv4)");
}
ATF_TC_BODY(hdtr_positive_v4, tc)
{
hdtr_positive_test(AF_INET);
}
ATF_TC(hdtr_positive_v6);
ATF_TC_HEAD(hdtr_positive_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify positive hdtr functionality (IPv6)");
}
ATF_TC_BODY(hdtr_positive_v6, tc)
{
hdtr_positive_test(AF_INET);
}
static void
hdtr_negative_bad_pointers_test(int domain)
{
int client_sock, error, fd, port, server_sock;
struct sf_hdtr *hdtr1, hdtr2, hdtr3;
port = generate_random_port(__LINE__ + domain);
hdtr1 = (struct sf_hdtr*)-1;
memset(&hdtr2, 0, sizeof(hdtr2));
hdtr2.hdr_cnt = 1;
hdtr2.headers = (struct iovec*)-1;
memset(&hdtr3, 0, sizeof(hdtr3));
hdtr3.trl_cnt = 1;
hdtr3.trailers = (struct iovec*)-1;
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
error = sendfile(fd, client_sock, 0, 0, hdtr1, NULL, SF_FLAGS(0, 0));
ATF_CHECK_ERRNO(EFAULT, error == -1);
error = sendfile(fd, client_sock, 0, 0, &hdtr2, NULL, SF_FLAGS(0, 0));
ATF_CHECK_ERRNO(EFAULT, error == -1);
error = sendfile(fd, client_sock, 0, 0, &hdtr3, NULL, SF_FLAGS(0, 0));
ATF_CHECK_ERRNO(EFAULT, error == -1);
(void)close(fd);
(void)close(client_sock);
(void)close(server_sock);
}
ATF_TC(hdtr_negative_bad_pointers_v4);
ATF_TC_HEAD(hdtr_negative_bad_pointers_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that bad pointers for hdtr storage result in EFAULT (IPv4)");
}
ATF_TC_BODY(hdtr_negative_bad_pointers_v4, tc)
{
hdtr_negative_bad_pointers_test(AF_INET);
}
ATF_TC(hdtr_negative_bad_pointers_v6);
ATF_TC_HEAD(hdtr_negative_bad_pointers_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that bad pointers for hdtr storage result in EFAULT (IPv6)");
}
ATF_TC_BODY(hdtr_negative_bad_pointers_v6, tc)
{
hdtr_negative_bad_pointers_test(AF_INET6);
}
static void
offset_negative_value_less_than_zero_test(int domain)
{
int client_sock, error, fd, port, server_sock;
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, -1, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
(void)close(fd);
(void)close(client_sock);
(void)close(server_sock);
}
ATF_TC(offset_negative_value_less_than_zero_v4);
ATF_TC_HEAD(offset_negative_value_less_than_zero_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a negative offset results in EINVAL (IPv4)");
}
ATF_TC_BODY(offset_negative_value_less_than_zero_v4, tc)
{
offset_negative_value_less_than_zero_test(AF_INET);
}
ATF_TC(offset_negative_value_less_than_zero_v6);
ATF_TC_HEAD(offset_negative_value_less_than_zero_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a negative offset results in EINVAL (IPv6)");
}
ATF_TC_BODY(offset_negative_value_less_than_zero_v6, tc)
{
offset_negative_value_less_than_zero_test(AF_INET6);
}
static void
sbytes_positive_test(int domain)
{
size_t pattern_size = strlen(DETERMINISTIC_PATTERN);
off_t sbytes;
int client_sock, error, fd, port, server_sock;
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, &sbytes, SF_FLAGS(0, 0));
ATF_CHECK_EQ_MSG(error, 0, "sendfile failed: %s", strerror(errno));
(void)close(fd);
(void)close(client_sock);
(void)close(server_sock);
ATF_CHECK_EQ_MSG(pattern_size, sbytes,
"the value returned by sbytes does not match the expected pattern "
"size");
}
ATF_TC(sbytes_positive_v4);
ATF_TC_HEAD(sbytes_positive_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify positive `sbytes` functionality (IPv4)");
}
ATF_TC_BODY(sbytes_positive_v4, tc)
{
sbytes_positive_test(AF_INET);
}
ATF_TC(sbytes_positive_v6);
ATF_TC_HEAD(sbytes_positive_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify positive `sbytes` functionality (IPv6)");
}
ATF_TC_BODY(sbytes_positive_v6, tc)
{
sbytes_positive_test(AF_INET6);
}
static void
sbytes_negative_test(int domain)
{
off_t *sbytes_p = (off_t*)-1;
int client_sock, error, fd, port, server_sock;
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
atf_tc_expect_fail(
"bug 232210: EFAULT assert fails because copyout(9) call is not checked");
error = sendfile(fd, client_sock, 0, 0, NULL, sbytes_p, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EFAULT, error == -1);
(void)close(fd);
(void)close(client_sock);
(void)close(server_sock);
}
ATF_TC(sbytes_negative_v4);
ATF_TC_HEAD(sbytes_negative_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify negative `sbytes` functionality (IPv4)");
}
ATF_TC_BODY(sbytes_negative_v4, tc)
{
sbytes_negative_test(AF_INET);
}
ATF_TC(sbytes_negative_v6);
ATF_TC_HEAD(sbytes_negative_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify negative `sbytes` functionality (IPv6)");
}
ATF_TC_BODY(sbytes_negative_v6, tc)
{
sbytes_negative_test(AF_INET6);
}
static void
s_negative_not_connected_socket_test(int domain)
{
int client_sock, error, fd, port;
port = generate_random_port(__LINE__ + domain);
client_sock = setup_tcp_server(domain, port);
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
(void)close(fd);
(void)close(client_sock);
}
ATF_TC(s_negative_not_connected_socket_v4);
ATF_TC_HEAD(s_negative_not_connected_socket_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv4)");
}
ATF_TC_BODY(s_negative_not_connected_socket_v4, tc)
{
s_negative_not_connected_socket_test(AF_INET);
}
ATF_TC(s_negative_not_connected_socket_v6);
ATF_TC_HEAD(s_negative_not_connected_socket_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv6)");
}
ATF_TC_BODY(s_negative_not_connected_socket_v6, tc)
{
s_negative_not_connected_socket_test(AF_INET6);
}
ATF_TC(s_negative_not_descriptor);
ATF_TC_HEAD(s_negative_not_descriptor, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that an invalid file descriptor, e.g., -1, fails with EBADF");
}
ATF_TC_BODY(s_negative_not_descriptor, tc)
{
int client_sock, error, fd;
client_sock = -1;
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EBADF, error == -1);
(void)close(fd);
}
ATF_TC(s_negative_not_socket_file_descriptor);
ATF_TC_HEAD(s_negative_not_socket_file_descriptor, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-socket file descriptor fails with ENOTSOCK");
}
ATF_TC_BODY(s_negative_not_socket_file_descriptor, tc)
{
int client_sock, error, fd;
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
client_sock = open(_PATH_DEVNULL, O_WRONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(ENOTSOCK, error == -1);
(void)close(fd);
(void)close(client_sock);
}
static void
s_negative_udp_socket_test(int domain)
{
int client_sock, error, fd, port;
port = generate_random_port(__LINE__ + domain);
client_sock = setup_client(domain, SOCK_DGRAM, port);
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
Add [initial] functional tests for sendfile(2) as lib/libc/sys/sendfile These testcases exercise a number of functional requirements for sendfile(2). The testcases use IPv4 and IPv6 domain sockets with TCP, and were confirmed functional on UFS and ZFS. UDP address family sockets cannot be used per the sendfile(2) contract, thus using UDP sockets is outside the scope of testing the syscall in positive cases. As seen in `:s_negative_udp_socket_test`, UDP is used to test the sendfile(2) contract to ensure that EINVAL is returned by sendfile(2). The testcases added explicitly avoid testing out `SF_SYNC` due to the complexity of verifying that support. However, this is a good next logical item to verify. The `hdtr_positive*` testcases work to a certain degree (the header testcases pass), but the trailer testcases do not work (it is an expected failure). In particular, the value received by the mock server doesn't match the expected value, and instead looks something like the following (using python array notation): `trailer[:]message[1:]` instead of: `message[:]trailer[:]` This makes me think there's a buffer overrun issue or problem with the offset somewhere in the sendfile(2) system call, but I need to do some other testing first to verify that the code is indeed sane, and my assumptions/code isn't buggy. The `sbytes_negative` testcases that check `sbytes` being set to an invalid value resulting in `EFAULT` fails today as the other change (which checks `copyout(9)`) has not been committed [1]. Thus, it should remain an expected failure (see bug 232210 for more details on this item). Next steps for testing sendfile(2): 1. Fix the header/trailer testcases so that they pass. 2. Setup if_tap interface and test with it, instead of using "localhost", per @asomers's suggestion. 3. Handle short recv(2)'s in `server_cat(..)`. 4. Add `SF_SYNC` support. 5. Add some more negative tests outside the scope of the functional contract. MFC after: 1 month Reviewed by: asomers Approved by: emaste (mentor) PR: 232210 Sponsored by: Netflix, Inc Differential Revision: https://reviews.freebsd.org/D18625
2019-01-23 22:00:17 +00:00
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
(void)close(fd);
(void)close(client_sock);
}
ATF_TC(s_negative_udp_socket_v4);
ATF_TC_HEAD(s_negative_udp_socket_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv4)");
}
ATF_TC_BODY(s_negative_udp_socket_v4, tc)
{
s_negative_udp_socket_test(AF_INET);
}
ATF_TC(s_negative_udp_socket_v6);
ATF_TC_HEAD(s_negative_udp_socket_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv6)");
}
ATF_TC_BODY(s_negative_udp_socket_v6, tc)
{
s_negative_udp_socket_test(AF_INET6);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, fd_positive_file_v4);
ATF_TP_ADD_TC(tp, fd_positive_file_v6);
ATF_TP_ADD_TC(tp, fd_positive_shm_v4);
ATF_TP_ADD_TC(tp, fd_positive_shm_v6);
ATF_TP_ADD_TC(tp, fd_negative_bad_fd_v4);
ATF_TP_ADD_TC(tp, fd_negative_bad_fd_v6);
ATF_TP_ADD_TC(tp, flags_v4);
ATF_TP_ADD_TC(tp, flags_v6);
/*
* TODO: the negative case for SF_NODISKIO (returns EBUSY if file in
* use) is not covered yet.
*
* Need to lock a file in a subprocess in write mode, then try and
* send the data in read mode with sendfile.
*
* This should work with FFS/UFS, but there are no guarantees about
* other filesystem implementations of sendfile(2), e.g., ZFS.
*/
ATF_TP_ADD_TC(tp, hdtr_positive_v4);
ATF_TP_ADD_TC(tp, hdtr_positive_v6);
ATF_TP_ADD_TC(tp, hdtr_negative_bad_pointers_v4);
ATF_TP_ADD_TC(tp, hdtr_negative_bad_pointers_v6);
ATF_TP_ADD_TC(tp, offset_negative_value_less_than_zero_v4);
ATF_TP_ADD_TC(tp, offset_negative_value_less_than_zero_v6);
ATF_TP_ADD_TC(tp, sbytes_positive_v4);
ATF_TP_ADD_TC(tp, sbytes_positive_v6);
ATF_TP_ADD_TC(tp, sbytes_negative_v4);
ATF_TP_ADD_TC(tp, sbytes_negative_v6);
ATF_TP_ADD_TC(tp, s_negative_not_connected_socket_v4);
ATF_TP_ADD_TC(tp, s_negative_not_connected_socket_v6);
ATF_TP_ADD_TC(tp, s_negative_not_descriptor);
ATF_TP_ADD_TC(tp, s_negative_not_socket_file_descriptor);
ATF_TP_ADD_TC(tp, s_negative_udp_socket_v4);
ATF_TP_ADD_TC(tp, s_negative_udp_socket_v6);
return (atf_no_error());
}