summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/sendfile_socket.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux/sendfile_socket.cc')
-rw-r--r--test/syscalls/linux/sendfile_socket.cc242
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