summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/socket_test_util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux/socket_test_util.cc')
-rw-r--r--test/syscalls/linux/socket_test_util.cc894
1 files changed, 0 insertions, 894 deletions
diff --git a/test/syscalls/linux/socket_test_util.cc b/test/syscalls/linux/socket_test_util.cc
deleted file mode 100644
index c0c5ab3fe..000000000
--- a/test/syscalls/linux/socket_test_util.cc
+++ /dev/null
@@ -1,894 +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 "test/syscalls/linux/socket_test_util.h"
-
-#include <arpa/inet.h>
-#include <poll.h>
-#include <sys/socket.h>
-
-#include <memory>
-
-#include "gtest/gtest.h"
-#include "absl/memory/memory.h"
-#include "absl/strings/str_cat.h"
-#include "absl/time/clock.h"
-#include "absl/types/optional.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/posix_error.h"
-#include "test/util/temp_path.h"
-#include "test/util/thread_util.h"
-
-namespace gvisor {
-namespace testing {
-
-Creator<SocketPair> SyscallSocketPairCreator(int domain, int type,
- int protocol) {
- return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> {
- int pair[2];
- RETURN_ERROR_IF_SYSCALL_FAIL(socketpair(domain, type, protocol, pair));
- MaybeSave(); // Save on successful creation.
- return absl::make_unique<FDSocketPair>(pair[0], pair[1]);
- };
-}
-
-Creator<FileDescriptor> SyscallSocketCreator(int domain, int type,
- int protocol) {
- return [=]() -> PosixErrorOr<std::unique_ptr<FileDescriptor>> {
- int fd = 0;
- RETURN_ERROR_IF_SYSCALL_FAIL(fd = socket(domain, type, protocol));
- MaybeSave(); // Save on successful creation.
- return absl::make_unique<FileDescriptor>(fd);
- };
-}
-
-PosixErrorOr<struct sockaddr_un> UniqueUnixAddr(bool abstract, int domain) {
- struct sockaddr_un addr = {};
- std::string path = NewTempAbsPathInDir("/tmp");
- if (path.size() >= sizeof(addr.sun_path)) {
- return PosixError(EINVAL,
- "Unable to generate a temp path of appropriate length");
- }
-
- if (abstract) {
- // Indicate that the path is in the abstract namespace.
- path[0] = 0;
- }
- memcpy(addr.sun_path, path.c_str(), path.length());
- addr.sun_family = domain;
- return addr;
-}
-
-Creator<SocketPair> AcceptBindSocketPairCreator(bool abstract, int domain,
- int type, int protocol) {
- return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> {
- ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un bind_addr,
- UniqueUnixAddr(abstract, domain));
- ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un extra_addr,
- UniqueUnixAddr(abstract, domain));
-
- int bound;
- RETURN_ERROR_IF_SYSCALL_FAIL(bound = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
- RETURN_ERROR_IF_SYSCALL_FAIL(
- bind(bound, reinterpret_cast<struct sockaddr*>(&bind_addr),
- sizeof(bind_addr)));
- MaybeSave(); // Successful bind.
- RETURN_ERROR_IF_SYSCALL_FAIL(listen(bound, /* backlog = */ 5));
- MaybeSave(); // Successful listen.
-
- int connected;
- RETURN_ERROR_IF_SYSCALL_FAIL(connected = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
- RETURN_ERROR_IF_SYSCALL_FAIL(
- connect(connected, reinterpret_cast<struct sockaddr*>(&bind_addr),
- sizeof(bind_addr)));
- MaybeSave(); // Successful connect.
-
- int accepted;
- RETURN_ERROR_IF_SYSCALL_FAIL(
- accepted = accept4(bound, nullptr, nullptr,
- type & (SOCK_NONBLOCK | SOCK_CLOEXEC)));
- MaybeSave(); // Successful connect.
-
- // Cleanup no longer needed resources.
- RETURN_ERROR_IF_SYSCALL_FAIL(close(bound));
- MaybeSave(); // Dropped original socket.
-
- // Only unlink if path is not in abstract namespace.
- if (bind_addr.sun_path[0] != 0) {
- RETURN_ERROR_IF_SYSCALL_FAIL(unlink(bind_addr.sun_path));
- MaybeSave(); // Unlinked path.
- }
-
- // accepted is before connected to destruct connected before accepted.
- // Destructors for nonstatic member objects are called in the reverse order
- // in which they appear in the class declaration.
- return absl::make_unique<AddrFDSocketPair>(accepted, connected, bind_addr,
- extra_addr);
- };
-}
-
-Creator<SocketPair> FilesystemAcceptBindSocketPairCreator(int domain, int type,
- int protocol) {
- return AcceptBindSocketPairCreator(/* abstract= */ false, domain, type,
- protocol);
-}
-
-Creator<SocketPair> AbstractAcceptBindSocketPairCreator(int domain, int type,
- int protocol) {
- return AcceptBindSocketPairCreator(/* abstract= */ true, domain, type,
- protocol);
-}
-
-Creator<SocketPair> BidirectionalBindSocketPairCreator(bool abstract,
- int domain, int type,
- int protocol) {
- return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> {
- ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un addr1,
- UniqueUnixAddr(abstract, domain));
- ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un addr2,
- UniqueUnixAddr(abstract, domain));
-
- int sock1;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock1 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
- RETURN_ERROR_IF_SYSCALL_FAIL(
- bind(sock1, reinterpret_cast<struct sockaddr*>(&addr1), sizeof(addr1)));
- MaybeSave(); // Successful bind.
-
- int sock2;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock2 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
- RETURN_ERROR_IF_SYSCALL_FAIL(
- bind(sock2, reinterpret_cast<struct sockaddr*>(&addr2), sizeof(addr2)));
- MaybeSave(); // Successful bind.
-
- RETURN_ERROR_IF_SYSCALL_FAIL(connect(
- sock1, reinterpret_cast<struct sockaddr*>(&addr2), sizeof(addr2)));
- MaybeSave(); // Successful connect.
-
- RETURN_ERROR_IF_SYSCALL_FAIL(connect(
- sock2, reinterpret_cast<struct sockaddr*>(&addr1), sizeof(addr1)));
- MaybeSave(); // Successful connect.
-
- // Cleanup no longer needed resources.
-
- // Only unlink if path is not in abstract namespace.
- if (addr1.sun_path[0] != 0) {
- RETURN_ERROR_IF_SYSCALL_FAIL(unlink(addr1.sun_path));
- MaybeSave(); // Successful unlink.
- }
-
- // Only unlink if path is not in abstract namespace.
- if (addr2.sun_path[0] != 0) {
- RETURN_ERROR_IF_SYSCALL_FAIL(unlink(addr2.sun_path));
- MaybeSave(); // Successful unlink.
- }
-
- return absl::make_unique<FDSocketPair>(sock1, sock2);
- };
-}
-
-Creator<SocketPair> FilesystemBidirectionalBindSocketPairCreator(int domain,
- int type,
- int protocol) {
- return BidirectionalBindSocketPairCreator(/* abstract= */ false, domain, type,
- protocol);
-}
-
-Creator<SocketPair> AbstractBidirectionalBindSocketPairCreator(int domain,
- int type,
- int protocol) {
- return BidirectionalBindSocketPairCreator(/* abstract= */ true, domain, type,
- protocol);
-}
-
-Creator<SocketPair> SocketpairGoferSocketPairCreator(int domain, int type,
- int protocol) {
- return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> {
- struct sockaddr_un addr = {};
- constexpr char kSocketGoferPath[] = "/socket";
- memcpy(addr.sun_path, kSocketGoferPath, sizeof(kSocketGoferPath));
- addr.sun_family = domain;
-
- int sock1;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock1 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
- RETURN_ERROR_IF_SYSCALL_FAIL(connect(
- sock1, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)));
- MaybeSave(); // Successful connect.
-
- int sock2;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock2 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
- RETURN_ERROR_IF_SYSCALL_FAIL(connect(
- sock2, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)));
- MaybeSave(); // Successful connect.
-
- // Make and close another socketpair to ensure that the duped ends of the
- // first socketpair get closed.
- //
- // The problem is that there is no way to atomically send and close an FD.
- // The closest that we can do is send and then immediately close the FD,
- // which is what we do in the gofer. The gofer won't respond to another
- // request until the reply is sent and the FD is closed, so forcing the
- // gofer to handle another request will ensure that this has happened.
- for (int i = 0; i < 2; i++) {
- int sock;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock = socket(domain, type, protocol));
- RETURN_ERROR_IF_SYSCALL_FAIL(connect(
- sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)));
- RETURN_ERROR_IF_SYSCALL_FAIL(close(sock));
- }
-
- return absl::make_unique<FDSocketPair>(sock1, sock2);
- };
-}
-
-Creator<SocketPair> SocketpairGoferFileSocketPairCreator(int flags) {
- return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> {
- constexpr char kSocketGoferPath[] = "/socket";
-
- int sock1;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock1 =
- open(kSocketGoferPath, O_RDWR | flags));
- MaybeSave(); // Successful socket creation.
-
- int sock2;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock2 =
- open(kSocketGoferPath, O_RDWR | flags));
- MaybeSave(); // Successful socket creation.
-
- return absl::make_unique<FDSocketPair>(sock1, sock2);
- };
-}
-
-Creator<SocketPair> UnboundSocketPairCreator(bool abstract, int domain,
- int type, int protocol) {
- return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> {
- ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un addr1,
- UniqueUnixAddr(abstract, domain));
- ASSIGN_OR_RETURN_ERRNO(struct sockaddr_un addr2,
- UniqueUnixAddr(abstract, domain));
-
- int sock1;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock1 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
- int sock2;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock2 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
- return absl::make_unique<AddrFDSocketPair>(sock1, sock2, addr1, addr2);
- };
-}
-
-Creator<SocketPair> FilesystemUnboundSocketPairCreator(int domain, int type,
- int protocol) {
- return UnboundSocketPairCreator(/* abstract= */ false, domain, type,
- protocol);
-}
-
-Creator<SocketPair> AbstractUnboundSocketPairCreator(int domain, int type,
- int protocol) {
- return UnboundSocketPairCreator(/* abstract= */ true, domain, type, protocol);
-}
-
-void LocalhostAddr(struct sockaddr_in* addr, bool dual_stack) {
- addr->sin_family = AF_INET;
- addr->sin_port = htons(0);
- inet_pton(AF_INET, "127.0.0.1",
- reinterpret_cast<void*>(&addr->sin_addr.s_addr));
-}
-
-void LocalhostAddr(struct sockaddr_in6* addr, bool dual_stack) {
- addr->sin6_family = AF_INET6;
- addr->sin6_port = htons(0);
- if (dual_stack) {
- inet_pton(AF_INET6, "::ffff:127.0.0.1",
- reinterpret_cast<void*>(&addr->sin6_addr.s6_addr));
- } else {
- inet_pton(AF_INET6, "::1",
- reinterpret_cast<void*>(&addr->sin6_addr.s6_addr));
- }
- addr->sin6_scope_id = 0;
-}
-
-template <typename T>
-PosixErrorOr<T> BindIP(int fd, bool dual_stack) {
- T addr = {};
- LocalhostAddr(&addr, dual_stack);
- RETURN_ERROR_IF_SYSCALL_FAIL(
- bind(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)));
- socklen_t addrlen = sizeof(addr);
- RETURN_ERROR_IF_SYSCALL_FAIL(
- getsockname(fd, reinterpret_cast<struct sockaddr*>(&addr), &addrlen));
- return addr;
-}
-
-template <typename T>
-PosixErrorOr<T> TCPBindAndListen(int fd, bool dual_stack) {
- ASSIGN_OR_RETURN_ERRNO(T addr, BindIP<T>(fd, dual_stack));
- RETURN_ERROR_IF_SYSCALL_FAIL(listen(fd, /* backlog = */ 5));
- return addr;
-}
-
-template <typename T>
-PosixErrorOr<std::unique_ptr<AddrFDSocketPair>>
-CreateTCPConnectAcceptSocketPair(int bound, int connected, int type,
- bool dual_stack, T bind_addr) {
- int connect_result = 0;
- RETURN_ERROR_IF_SYSCALL_FAIL(
- (connect_result = RetryEINTR(connect)(
- connected, reinterpret_cast<struct sockaddr*>(&bind_addr),
- sizeof(bind_addr))) == -1 &&
- errno == EINPROGRESS
- ? 0
- : connect_result);
- MaybeSave(); // Successful connect.
-
- if (connect_result == -1) {
- struct pollfd connect_poll = {connected, POLLOUT | POLLERR | POLLHUP, 0};
- RETURN_ERROR_IF_SYSCALL_FAIL(RetryEINTR(poll)(&connect_poll, 1, 0));
- int error = 0;
- socklen_t errorlen = sizeof(error);
- RETURN_ERROR_IF_SYSCALL_FAIL(
- getsockopt(connected, SOL_SOCKET, SO_ERROR, &error, &errorlen));
- errno = error;
- RETURN_ERROR_IF_SYSCALL_FAIL(
- /* connect */ error == 0 ? 0 : -1);
- }
-
- int accepted = -1;
- struct pollfd accept_poll = {bound, POLLIN, 0};
- while (accepted == -1) {
- RETURN_ERROR_IF_SYSCALL_FAIL(RetryEINTR(poll)(&accept_poll, 1, 0));
-
- RETURN_ERROR_IF_SYSCALL_FAIL(
- (accepted = RetryEINTR(accept4)(
- bound, nullptr, nullptr, type & (SOCK_NONBLOCK | SOCK_CLOEXEC))) ==
- -1 &&
- errno == EAGAIN
- ? 0
- : accepted);
- }
- MaybeSave(); // Successful accept.
-
- // FIXME(b/110484944)
- if (connect_result == -1) {
- absl::SleepFor(absl::Seconds(1));
- }
-
- T extra_addr = {};
- LocalhostAddr(&extra_addr, dual_stack);
- return absl::make_unique<AddrFDSocketPair>(connected, accepted, bind_addr,
- extra_addr);
-}
-
-template <typename T>
-PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> CreateTCPAcceptBindSocketPair(
- int bound, int connected, int type, bool dual_stack) {
- ASSIGN_OR_RETURN_ERRNO(T bind_addr, TCPBindAndListen<T>(bound, dual_stack));
-
- auto result = CreateTCPConnectAcceptSocketPair(bound, connected, type,
- dual_stack, bind_addr);
-
- // Cleanup no longer needed resources.
- RETURN_ERROR_IF_SYSCALL_FAIL(close(bound));
- MaybeSave(); // Successful close.
-
- return result;
-}
-
-Creator<SocketPair> TCPAcceptBindSocketPairCreator(int domain, int type,
- int protocol,
- bool dual_stack) {
- return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> {
- int bound;
- RETURN_ERROR_IF_SYSCALL_FAIL(bound = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
-
- int connected;
- RETURN_ERROR_IF_SYSCALL_FAIL(connected = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
-
- if (domain == AF_INET) {
- return CreateTCPAcceptBindSocketPair<sockaddr_in>(bound, connected, type,
- dual_stack);
- }
- return CreateTCPAcceptBindSocketPair<sockaddr_in6>(bound, connected, type,
- dual_stack);
- };
-}
-
-Creator<SocketPair> TCPAcceptBindPersistentListenerSocketPairCreator(
- int domain, int type, int protocol, bool dual_stack) {
- // These are lazily initialized below, on the first call to the returned
- // lambda. These values are private to each returned lambda, but shared across
- // invocations of a specific lambda.
- //
- // The sharing allows pairs created with the same parameters to share a
- // listener. This prevents future connects from failing if the connecting
- // socket selects a port which had previously been used by a listening socket
- // that still has some connections in TIME-WAIT.
- //
- // The lazy initialization is to avoid creating sockets during parameter
- // enumeration. This is important because parameters are enumerated during the
- // build process where networking may not be available.
- auto listener = std::make_shared<absl::optional<int>>(absl::optional<int>());
- auto addr4 = std::make_shared<absl::optional<sockaddr_in>>(
- absl::optional<sockaddr_in>());
- auto addr6 = std::make_shared<absl::optional<sockaddr_in6>>(
- absl::optional<sockaddr_in6>());
-
- return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> {
- int connected;
- RETURN_ERROR_IF_SYSCALL_FAIL(connected = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
-
- // Share the listener across invocations.
- if (!listener->has_value()) {
- int fd = socket(domain, type, protocol);
- if (fd < 0) {
- return PosixError(errno, absl::StrCat("socket(", domain, ", ", type,
- ", ", protocol, ")"));
- }
- listener->emplace(fd);
- MaybeSave(); // Successful socket creation.
- }
-
- // Bind the listener once, but create a new connect/accept pair each
- // time.
- if (domain == AF_INET) {
- if (!addr4->has_value()) {
- addr4->emplace(
- TCPBindAndListen<sockaddr_in>(listener->value(), dual_stack)
- .ValueOrDie());
- }
- return CreateTCPConnectAcceptSocketPair(listener->value(), connected,
- type, dual_stack, addr4->value());
- }
- if (!addr6->has_value()) {
- addr6->emplace(
- TCPBindAndListen<sockaddr_in6>(listener->value(), dual_stack)
- .ValueOrDie());
- }
- return CreateTCPConnectAcceptSocketPair(listener->value(), connected, type,
- dual_stack, addr6->value());
- };
-}
-
-template <typename T>
-PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> CreateUDPBoundSocketPair(
- int sock1, int sock2, int type, bool dual_stack) {
- ASSIGN_OR_RETURN_ERRNO(T addr1, BindIP<T>(sock1, dual_stack));
- ASSIGN_OR_RETURN_ERRNO(T addr2, BindIP<T>(sock2, dual_stack));
-
- return absl::make_unique<AddrFDSocketPair>(sock1, sock2, addr1, addr2);
-}
-
-template <typename T>
-PosixErrorOr<std::unique_ptr<AddrFDSocketPair>>
-CreateUDPBidirectionalBindSocketPair(int sock1, int sock2, int type,
- bool dual_stack) {
- ASSIGN_OR_RETURN_ERRNO(
- auto socks, CreateUDPBoundSocketPair<T>(sock1, sock2, type, dual_stack));
-
- // Connect sock1 to sock2.
- RETURN_ERROR_IF_SYSCALL_FAIL(connect(socks->first_fd(), socks->second_addr(),
- socks->second_addr_size()));
- MaybeSave(); // Successful connection.
-
- // Connect sock2 to sock1.
- RETURN_ERROR_IF_SYSCALL_FAIL(connect(socks->second_fd(), socks->first_addr(),
- socks->first_addr_size()));
- MaybeSave(); // Successful connection.
-
- return socks;
-}
-
-Creator<SocketPair> UDPBidirectionalBindSocketPairCreator(int domain, int type,
- int protocol,
- bool dual_stack) {
- return [=]() -> PosixErrorOr<std::unique_ptr<AddrFDSocketPair>> {
- int sock1;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock1 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
-
- int sock2;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock2 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
-
- if (domain == AF_INET) {
- return CreateUDPBidirectionalBindSocketPair<sockaddr_in>(
- sock1, sock2, type, dual_stack);
- }
- return CreateUDPBidirectionalBindSocketPair<sockaddr_in6>(sock1, sock2,
- type, dual_stack);
- };
-}
-
-Creator<SocketPair> UDPUnboundSocketPairCreator(int domain, int type,
- int protocol, bool dual_stack) {
- return [=]() -> PosixErrorOr<std::unique_ptr<FDSocketPair>> {
- int sock1;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock1 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
-
- int sock2;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock2 = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
-
- return absl::make_unique<FDSocketPair>(sock1, sock2);
- };
-}
-
-SocketPairKind Reversed(SocketPairKind const& base) {
- auto const& creator = base.creator;
- return SocketPairKind{
- absl::StrCat("reversed ", base.description), base.domain, base.type,
- base.protocol,
- [creator]() -> PosixErrorOr<std::unique_ptr<ReversedSocketPair>> {
- ASSIGN_OR_RETURN_ERRNO(auto creator_value, creator());
- return absl::make_unique<ReversedSocketPair>(std::move(creator_value));
- }};
-}
-
-Creator<FileDescriptor> UnboundSocketCreator(int domain, int type,
- int protocol) {
- return [=]() -> PosixErrorOr<std::unique_ptr<FileDescriptor>> {
- int sock;
- RETURN_ERROR_IF_SYSCALL_FAIL(sock = socket(domain, type, protocol));
- MaybeSave(); // Successful socket creation.
-
- return absl::make_unique<FileDescriptor>(sock);
- };
-}
-
-std::vector<SocketPairKind> IncludeReversals(std::vector<SocketPairKind> vec) {
- return ApplyVecToVec<SocketPairKind>(std::vector<Middleware>{NoOp, Reversed},
- vec);
-}
-
-SocketPairKind NoOp(SocketPairKind const& base) { return base; }
-
-void TransferTest(int fd1, int fd2) {
- char buf1[20];
- RandomizeBuffer(buf1, sizeof(buf1));
- ASSERT_THAT(WriteFd(fd1, buf1, sizeof(buf1)),
- SyscallSucceedsWithValue(sizeof(buf1)));
-
- char buf2[20];
- ASSERT_THAT(ReadFd(fd2, buf2, sizeof(buf2)),
- SyscallSucceedsWithValue(sizeof(buf2)));
-
- EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
-
- RandomizeBuffer(buf1, sizeof(buf1));
- ASSERT_THAT(WriteFd(fd2, buf1, sizeof(buf1)),
- SyscallSucceedsWithValue(sizeof(buf1)));
-
- ASSERT_THAT(ReadFd(fd1, buf2, sizeof(buf2)),
- SyscallSucceedsWithValue(sizeof(buf2)));
-
- EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
-}
-
-// Initializes the given buffer with random data.
-void RandomizeBuffer(char* ptr, size_t len) {
- uint32_t seed = time(nullptr);
- for (size_t i = 0; i < len; ++i) {
- ptr[i] = static_cast<char>(rand_r(&seed));
- }
-}
-
-size_t CalculateUnixSockAddrLen(const char* sun_path) {
- // Abstract addresses always return the full length.
- if (sun_path[0] == 0) {
- return sizeof(sockaddr_un);
- }
- // Filesystem addresses use the address length plus the 2 byte sun_family
- // and null terminator.
- return strlen(sun_path) + 3;
-}
-
-struct sockaddr_storage AddrFDSocketPair::to_storage(const sockaddr_un& addr) {
- struct sockaddr_storage addr_storage = {};
- memcpy(&addr_storage, &addr, sizeof(addr));
- return addr_storage;
-}
-
-struct sockaddr_storage AddrFDSocketPair::to_storage(const sockaddr_in& addr) {
- struct sockaddr_storage addr_storage = {};
- memcpy(&addr_storage, &addr, sizeof(addr));
- return addr_storage;
-}
-
-struct sockaddr_storage AddrFDSocketPair::to_storage(const sockaddr_in6& addr) {
- struct sockaddr_storage addr_storage = {};
- memcpy(&addr_storage, &addr, sizeof(addr));
- return addr_storage;
-}
-
-SocketKind SimpleSocket(int fam, int type, int proto) {
- return SocketKind{
- absl::StrCat("Family ", fam, ", type ", type, ", proto ", proto), fam,
- type, proto, SyscallSocketCreator(fam, type, proto)};
-}
-
-ssize_t SendLargeSendMsg(const std::unique_ptr<SocketPair>& sockets,
- size_t size, bool reader) {
- const int rfd = sockets->second_fd();
- ScopedThread t([rfd, size, reader] {
- if (!reader) {
- return;
- }
-
- // Potentially too many syscalls in the loop.
- const DisableSave ds;
-
- std::vector<char> buf(size);
- size_t total = 0;
-
- while (total < size) {
- int ret = read(rfd, buf.data(), buf.size());
- if (ret == -1 && errno == EAGAIN) {
- continue;
- }
- if (ret > 0) {
- total += ret;
- }
-
- // Assert to return on first failure.
- ASSERT_THAT(ret, SyscallSucceeds());
- }
- });
-
- std::vector<char> buf(size);
-
- struct iovec iov = {};
- iov.iov_base = buf.data();
- iov.iov_len = buf.size();
-
- struct msghdr msg = {};
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- return RetryEINTR(sendmsg)(sockets->first_fd(), &msg, 0);
-}
-
-namespace internal {
-PosixErrorOr<int> TryPortAvailable(int port, AddressFamily family,
- SocketType type, bool reuse_addr) {
- if (port < 0) {
- return PosixError(EINVAL, "Invalid port");
- }
-
- // Both Ipv6 and Dualstack are AF_INET6.
- int sock_fam = (family == AddressFamily::kIpv4 ? AF_INET : AF_INET6);
- int sock_type = (type == SocketType::kTcp ? SOCK_STREAM : SOCK_DGRAM);
- ASSIGN_OR_RETURN_ERRNO(auto fd, Socket(sock_fam, sock_type, 0));
-
- if (reuse_addr) {
- int one = 1;
- RETURN_ERROR_IF_SYSCALL_FAIL(
- setsockopt(fd.get(), SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)));
- }
-
- // Try to bind.
- sockaddr_storage storage = {};
- int storage_size = 0;
- if (family == AddressFamily::kIpv4) {
- sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&storage);
- storage_size = sizeof(*addr);
- addr->sin_family = AF_INET;
- addr->sin_port = htons(port);
- addr->sin_addr.s_addr = htonl(INADDR_ANY);
- } else {
- sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(&storage);
- storage_size = sizeof(*addr);
- addr->sin6_family = AF_INET6;
- addr->sin6_port = htons(port);
- if (family == AddressFamily::kDualStack) {
- inet_pton(AF_INET6, "::ffff:0.0.0.0",
- reinterpret_cast<void*>(&addr->sin6_addr.s6_addr));
- } else {
- addr->sin6_addr = in6addr_any;
- }
- }
-
- RETURN_ERROR_IF_SYSCALL_FAIL(
- bind(fd.get(), reinterpret_cast<sockaddr*>(&storage), storage_size));
-
- // If the user specified 0 as the port, we will return the port that the
- // kernel gave us, otherwise we will validate that this socket bound to the
- // requested port.
- sockaddr_storage bound_storage = {};
- socklen_t bound_storage_size = sizeof(bound_storage);
- RETURN_ERROR_IF_SYSCALL_FAIL(
- getsockname(fd.get(), reinterpret_cast<sockaddr*>(&bound_storage),
- &bound_storage_size));
-
- int available_port = -1;
- if (bound_storage.ss_family == AF_INET) {
- sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&bound_storage);
- available_port = ntohs(addr->sin_port);
- } else if (bound_storage.ss_family == AF_INET6) {
- sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(&bound_storage);
- available_port = ntohs(addr->sin6_port);
- } else {
- return PosixError(EPROTOTYPE, "Getsockname returned invalid family");
- }
-
- // If we requested a specific port make sure our bound port is that port.
- if (port != 0 && available_port != port) {
- return PosixError(EINVAL,
- absl::StrCat("Bound port ", available_port,
- " was not equal to requested port ", port));
- }
-
- // If we're trying to do a TCP socket, let's also try to listen.
- if (type == SocketType::kTcp) {
- RETURN_ERROR_IF_SYSCALL_FAIL(listen(fd.get(), 1));
- }
-
- return available_port;
-}
-} // namespace internal
-
-PosixErrorOr<int> SendMsg(int sock, msghdr* msg, char buf[], int buf_size) {
- struct iovec iov;
- iov.iov_base = buf;
- iov.iov_len = buf_size;
- msg->msg_iov = &iov;
- msg->msg_iovlen = 1;
-
- int ret;
- RETURN_ERROR_IF_SYSCALL_FAIL(ret = RetryEINTR(sendmsg)(sock, msg, 0));
- return ret;
-}
-
-void RecvNoData(int sock) {
- char data = 0;
- struct iovec iov;
- iov.iov_base = &data;
- iov.iov_len = 1;
- struct msghdr msg = {};
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- ASSERT_THAT(RetryEINTR(recvmsg)(sock, &msg, MSG_DONTWAIT),
- SyscallFailsWithErrno(EAGAIN));
-}
-
-TestAddress V4Any() {
- TestAddress t("V4Any");
- t.addr.ss_family = AF_INET;
- t.addr_len = sizeof(sockaddr_in);
- reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr = htonl(INADDR_ANY);
- return t;
-}
-
-TestAddress V4Loopback() {
- TestAddress t("V4Loopback");
- t.addr.ss_family = AF_INET;
- t.addr_len = sizeof(sockaddr_in);
- reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr =
- htonl(INADDR_LOOPBACK);
- return t;
-}
-
-TestAddress V4MappedAny() {
- TestAddress t("V4MappedAny");
- t.addr.ss_family = AF_INET6;
- t.addr_len = sizeof(sockaddr_in6);
- inet_pton(AF_INET6, "::ffff:0.0.0.0",
- reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr.s6_addr);
- return t;
-}
-
-TestAddress V4MappedLoopback() {
- TestAddress t("V4MappedLoopback");
- t.addr.ss_family = AF_INET6;
- t.addr_len = sizeof(sockaddr_in6);
- inet_pton(AF_INET6, "::ffff:127.0.0.1",
- reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr.s6_addr);
- return t;
-}
-
-TestAddress V6Any() {
- TestAddress t("V6Any");
- t.addr.ss_family = AF_INET6;
- t.addr_len = sizeof(sockaddr_in6);
- reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr = in6addr_any;
- return t;
-}
-
-TestAddress V6Loopback() {
- TestAddress t("V6Loopback");
- t.addr.ss_family = AF_INET6;
- t.addr_len = sizeof(sockaddr_in6);
- reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr = in6addr_loopback;
- return t;
-}
-
-// Checksum computes the internet checksum of a buffer.
-uint16_t Checksum(uint16_t* buf, ssize_t buf_size) {
- // Add up the 16-bit values in the buffer.
- uint32_t total = 0;
- for (unsigned int i = 0; i < buf_size; i += sizeof(*buf)) {
- total += *buf;
- buf++;
- }
-
- // If buf has an odd size, add the remaining byte.
- if (buf_size % 2) {
- total += *(reinterpret_cast<unsigned char*>(buf) - 1);
- }
-
- // This carries any bits past the lower 16 until everything fits in 16 bits.
- while (total >> 16) {
- uint16_t lower = total & 0xffff;
- uint16_t upper = total >> 16;
- total = lower + upper;
- }
-
- return ~total;
-}
-
-uint16_t IPChecksum(struct iphdr ip) {
- return Checksum(reinterpret_cast<uint16_t*>(&ip), sizeof(ip));
-}
-
-// The pseudo-header defined in RFC 768 for calculating the UDP checksum.
-struct udp_pseudo_hdr {
- uint32_t srcip;
- uint32_t destip;
- char zero;
- char protocol;
- uint16_t udplen;
-};
-
-uint16_t UDPChecksum(struct iphdr iphdr, struct udphdr udphdr,
- const char* payload, ssize_t payload_len) {
- struct udp_pseudo_hdr phdr = {};
- phdr.srcip = iphdr.saddr;
- phdr.destip = iphdr.daddr;
- phdr.zero = 0;
- phdr.protocol = IPPROTO_UDP;
- phdr.udplen = udphdr.len;
-
- ssize_t buf_size = sizeof(phdr) + sizeof(udphdr) + payload_len;
- char* buf = static_cast<char*>(malloc(buf_size));
- memcpy(buf, &phdr, sizeof(phdr));
- memcpy(buf + sizeof(phdr), &udphdr, sizeof(udphdr));
- memcpy(buf + sizeof(phdr) + sizeof(udphdr), payload, payload_len);
-
- uint16_t csum = Checksum(reinterpret_cast<uint16_t*>(buf), buf_size);
- free(buf);
- return csum;
-}
-
-uint16_t ICMPChecksum(struct icmphdr icmphdr, const char* payload,
- ssize_t payload_len) {
- ssize_t buf_size = sizeof(icmphdr) + payload_len;
- char* buf = static_cast<char*>(malloc(buf_size));
- memcpy(buf, &icmphdr, sizeof(icmphdr));
- memcpy(buf + sizeof(icmphdr), payload, payload_len);
-
- uint16_t csum = Checksum(reinterpret_cast<uint16_t*>(buf), buf_size);
- free(buf);
- return csum;
-}
-
-} // namespace testing
-} // namespace gvisor