diff options
Diffstat (limited to 'test/syscalls/linux/sendfile_socket.cc')
-rw-r--r-- | test/syscalls/linux/sendfile_socket.cc | 242 |
1 files changed, 0 insertions, 242 deletions
diff --git a/test/syscalls/linux/sendfile_socket.cc b/test/syscalls/linux/sendfile_socket.cc deleted file mode 100644 index 8f7ee4163..000000000 --- a/test/syscalls/linux/sendfile_socket.cc +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include <arpa/inet.h> -#include <netinet/in.h> -#include <sys/sendfile.h> -#include <sys/socket.h> -#include <unistd.h> - -#include <iostream> -#include <vector> - -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "test/syscalls/linux/socket_test_util.h" -#include "test/util/file_descriptor.h" -#include "test/util/temp_path.h" -#include "test/util/test_util.h" -#include "test/util/thread_util.h" - -namespace gvisor { -namespace testing { -namespace { - -class SendFileTest : public ::testing::TestWithParam<int> { - protected: - PosixErrorOr<std::tuple<int, int>> Sockets() { - // Bind a server socket. - int family = GetParam(); - struct sockaddr server_addr = {}; - switch (family) { - case AF_INET: { - struct sockaddr_in* server_addr_in = - reinterpret_cast<struct sockaddr_in*>(&server_addr); - server_addr_in->sin_family = family; - server_addr_in->sin_addr.s_addr = INADDR_ANY; - break; - } - case AF_UNIX: { - struct sockaddr_un* server_addr_un = - reinterpret_cast<struct sockaddr_un*>(&server_addr); - server_addr_un->sun_family = family; - server_addr_un->sun_path[0] = '\0'; - break; - } - default: - return PosixError(EINVAL); - } - int server = socket(family, SOCK_STREAM, 0); - if (bind(server, &server_addr, sizeof(server_addr)) < 0) { - return PosixError(errno); - } - if (listen(server, 1) < 0) { - close(server); - return PosixError(errno); - } - - // Fetch the address; both are anonymous. - socklen_t length = sizeof(server_addr); - if (getsockname(server, &server_addr, &length) < 0) { - close(server); - return PosixError(errno); - } - - // Connect the client. - int client = socket(family, SOCK_STREAM, 0); - if (connect(client, &server_addr, length) < 0) { - close(server); - close(client); - return PosixError(errno); - } - - // Accept on the server. - int server_client = accept(server, nullptr, 0); - if (server_client < 0) { - close(server); - close(client); - return PosixError(errno); - } - close(server); - return std::make_tuple(client, server_client); - } -}; - -// Sends large file to exercise the path that read and writes data multiple -// times, esp. when more data is read than can be written. -TEST_P(SendFileTest, SendMultiple) { - std::vector<char> data(5 * 1024 * 1024); - RandomizeBuffer(data.data(), data.size()); - - // Create temp files. - const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( - GetAbsoluteTestTmpdir(), absl::string_view(data.data(), data.size()), - TempPath::kDefaultFileMode)); - const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); - - // Create sockets. - std::tuple<int, int> fds = ASSERT_NO_ERRNO_AND_VALUE(Sockets()); - const FileDescriptor server(std::get<0>(fds)); - FileDescriptor client(std::get<1>(fds)); // non-const, reset is used. - - // Thread that reads data from socket and dumps to a file. - ScopedThread th([&] { - FileDescriptor outf = - ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_WRONLY)); - - // Read until socket is closed. - char buf[10240]; - for (int cnt = 0;; cnt++) { - int r = RetryEINTR(read)(server.get(), buf, sizeof(buf)); - // We cannot afford to save on every read() call. - if (cnt % 1000 == 0) { - ASSERT_THAT(r, SyscallSucceeds()); - } else { - const DisableSave ds; - ASSERT_THAT(r, SyscallSucceeds()); - } - if (r == 0) { - // EOF - break; - } - int w = RetryEINTR(write)(outf.get(), buf, r); - // We cannot afford to save on every write() call. - if (cnt % 1010 == 0) { - ASSERT_THAT(w, SyscallSucceedsWithValue(r)); - } else { - const DisableSave ds; - ASSERT_THAT(w, SyscallSucceedsWithValue(r)); - } - } - }); - - // Open the input file as read only. - const FileDescriptor inf = - ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDONLY)); - - int cnt = 0; - for (size_t sent = 0; sent < data.size(); cnt++) { - const size_t remain = data.size() - sent; - std::cout << "sendfile, size=" << data.size() << ", sent=" << sent - << ", remain=" << remain; - - // Send data and verify that sendfile returns the correct value. - int res = sendfile(client.get(), inf.get(), nullptr, remain); - // We cannot afford to save on every sendfile() call. - if (cnt % 120 == 0) { - MaybeSave(); - } - if (res == 0) { - // EOF - break; - } - if (res > 0) { - sent += res; - } else { - ASSERT_TRUE(errno == EINTR || errno == EAGAIN) << "errno=" << errno; - } - } - - // Close socket to stop thread. - client.reset(); - th.Join(); - - // Verify that the output file has the correct data. - const FileDescriptor outf = - ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDONLY)); - std::vector<char> actual(data.size(), '\0'); - ASSERT_THAT(RetryEINTR(read)(outf.get(), actual.data(), actual.size()), - SyscallSucceedsWithValue(actual.size())); - ASSERT_EQ(memcmp(data.data(), actual.data(), data.size()), 0); -} - -TEST_P(SendFileTest, Shutdown) { - // Create a socket. - std::tuple<int, int> fds = ASSERT_NO_ERRNO_AND_VALUE(Sockets()); - const FileDescriptor client(std::get<0>(fds)); - FileDescriptor server(std::get<1>(fds)); // non-const, reset below. - - // If this is a TCP socket, then turn off linger. - if (GetParam() == AF_INET) { - struct linger sl; - sl.l_onoff = 1; - sl.l_linger = 0; - ASSERT_THAT( - setsockopt(server.get(), SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)), - SyscallSucceeds()); - } - - // Create a 1m file with random data. - std::vector<char> data(1024 * 1024); - RandomizeBuffer(data.data(), data.size()); - const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( - GetAbsoluteTestTmpdir(), absl::string_view(data.data(), data.size()), - TempPath::kDefaultFileMode)); - const FileDescriptor inf = - ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDONLY)); - - // Read some data, then shutdown the socket. We don't actually care about - // checking the contents (other tests do that), so we just re-use the same - // buffer as above. - ScopedThread t([&]() { - size_t done = 0; - while (done < data.size()) { - int n = RetryEINTR(read)(server.get(), data.data(), data.size()); - ASSERT_THAT(n, SyscallSucceeds()); - done += n; - } - // Close the server side socket. - server.reset(); - }); - - // Continuously stream from the file to the socket. Note we do not assert - // that a specific amount of data has been written at any time, just that some - // data is written. Eventually, we should get a connection reset error. - while (1) { - off_t offset = 0; // Always read from the start. - int n = sendfile(client.get(), inf.get(), &offset, data.size()); - EXPECT_THAT(n, AnyOf(SyscallFailsWithErrno(ECONNRESET), - SyscallFailsWithErrno(EPIPE), SyscallSucceeds())); - if (n <= 0) { - break; - } - } -} - -INSTANTIATE_TEST_SUITE_P(AddressFamily, SendFileTest, - ::testing::Values(AF_UNIX, AF_INET)); - -} // namespace -} // namespace testing -} // namespace gvisor |