summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux')
-rw-r--r--test/syscalls/linux/BUILD5
-rw-r--r--test/syscalls/linux/ip_socket_test_util.cc16
-rw-r--r--test/syscalls/linux/ip_socket_test_util.h16
-rw-r--r--test/syscalls/linux/ping_socket.cc221
-rw-r--r--test/syscalls/linux/pipe.cc1
-rw-r--r--test/syscalls/linux/rename.cc56
-rw-r--r--test/syscalls/linux/semaphore.cc7
-rw-r--r--test/syscalls/linux/socket_inet_loopback.cc72
-rw-r--r--test/syscalls/linux/socket_test_util.cc109
-rw-r--r--test/syscalls/linux/socket_test_util.h30
-rw-r--r--test/syscalls/linux/udp_socket.cc4
11 files changed, 470 insertions, 67 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 9a912dba8..d8b562e9d 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -1572,10 +1572,13 @@ cc_binary(
srcs = ["ping_socket.cc"],
linkstatic = 1,
deps = [
+ ":ip_socket_test_util",
":socket_test_util",
"//test/util:file_descriptor",
+ "@com_google_absl//absl/algorithm:container",
+ "@com_google_absl//absl/strings",
+ "@com_google_absl//absl/types:optional",
gtest,
- "//test/util:save_util",
"//test/util:test_main",
"//test/util:test_util",
],
diff --git a/test/syscalls/linux/ip_socket_test_util.cc b/test/syscalls/linux/ip_socket_test_util.cc
index 95082a0f2..e90a7e411 100644
--- a/test/syscalls/linux/ip_socket_test_util.cc
+++ b/test/syscalls/linux/ip_socket_test_util.cc
@@ -140,6 +140,22 @@ SocketPairKind IPv4UDPUnboundSocketPair(int type) {
/* dual_stack = */ false)};
}
+SocketKind ICMPUnboundSocket(int type) {
+ std::string description =
+ absl::StrCat(DescribeSocketType(type), "ICMP socket");
+ return SocketKind{
+ description, AF_INET, type | SOCK_DGRAM, IPPROTO_ICMP,
+ UnboundSocketCreator(AF_INET, type | SOCK_DGRAM, IPPROTO_ICMP)};
+}
+
+SocketKind ICMPv6UnboundSocket(int type) {
+ std::string description =
+ absl::StrCat(DescribeSocketType(type), "ICMPv6 socket");
+ return SocketKind{
+ description, AF_INET6, type | SOCK_DGRAM, IPPROTO_ICMPV6,
+ UnboundSocketCreator(AF_INET6, type | SOCK_DGRAM, IPPROTO_ICMPV6)};
+}
+
SocketKind IPv4UDPUnboundSocket(int type) {
std::string description =
absl::StrCat(DescribeSocketType(type), "IPv4 UDP socket");
diff --git a/test/syscalls/linux/ip_socket_test_util.h b/test/syscalls/linux/ip_socket_test_util.h
index 9c3859fcd..bde481f7e 100644
--- a/test/syscalls/linux/ip_socket_test_util.h
+++ b/test/syscalls/linux/ip_socket_test_util.h
@@ -84,20 +84,28 @@ SocketPairKind DualStackUDPBidirectionalBindSocketPair(int type);
// SocketPairs created with AF_INET and the given type.
SocketPairKind IPv4UDPUnboundSocketPair(int type);
+// ICMPUnboundSocket returns a SocketKind that represents a SimpleSocket created
+// with AF_INET, SOCK_DGRAM, IPPROTO_ICMP, and the given type.
+SocketKind ICMPUnboundSocket(int type);
+
+// ICMPv6UnboundSocket returns a SocketKind that represents a SimpleSocket
+// created with AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6, and the given type.
+SocketKind ICMPv6UnboundSocket(int type);
+
// IPv4UDPUnboundSocket returns a SocketKind that represents a SimpleSocket
-// created with AF_INET, SOCK_DGRAM, and the given type.
+// created with AF_INET, SOCK_DGRAM, IPPROTO_UDP, and the given type.
SocketKind IPv4UDPUnboundSocket(int type);
// IPv6UDPUnboundSocket returns a SocketKind that represents a SimpleSocket
-// created with AF_INET6, SOCK_DGRAM, and the given type.
+// created with AF_INET6, SOCK_DGRAM, IPPROTO_UDP, and the given type.
SocketKind IPv6UDPUnboundSocket(int type);
// IPv4TCPUnboundSocket returns a SocketKind that represents a SimpleSocket
-// created with AF_INET, SOCK_STREAM and the given type.
+// created with AF_INET, SOCK_STREAM, IPPROTO_TCP and the given type.
SocketKind IPv4TCPUnboundSocket(int type);
// IPv6TCPUnboundSocket returns a SocketKind that represents a SimpleSocket
-// created with AF_INET6, SOCK_STREAM and the given type.
+// created with AF_INET6, SOCK_STREAM, IPPROTO_TCP and the given type.
SocketKind IPv6TCPUnboundSocket(int type);
// IfAddrHelper is a helper class that determines the local interfaces present
diff --git a/test/syscalls/linux/ping_socket.cc b/test/syscalls/linux/ping_socket.cc
index 8b78e4b16..8268e91da 100644
--- a/test/syscalls/linux/ping_socket.cc
+++ b/test/syscalls/linux/ping_socket.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
@@ -19,14 +20,22 @@
#include <sys/types.h>
#include <unistd.h>
+#include <cctype>
+#include <cstring>
#include <vector>
#include "gtest/gtest.h"
+#include "absl/algorithm/container.h"
+#include "absl/strings/str_join.h"
+#include "absl/types/optional.h"
+#include "test/syscalls/linux/ip_socket_test_util.h"
#include "test/syscalls/linux/socket_test_util.h"
#include "test/util/file_descriptor.h"
-#include "test/util/save_util.h"
#include "test/util/test_util.h"
+// Note: These tests require /proc/sys/net/ipv4/ping_group_range to be
+// configured to allow the tester to create ping sockets (see icmp(7)).
+
namespace gvisor {
namespace testing {
namespace {
@@ -42,7 +51,8 @@ TEST(PingSocket, ICMPPortExhaustion) {
auto s = Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (!s.ok()) {
ASSERT_EQ(s.error().errno_value(), EACCES);
- GTEST_SKIP();
+ GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow "
+ "creation of ICMP or ICMPv6 sockets";
}
}
@@ -70,7 +80,212 @@ TEST(PingSocket, ICMPPortExhaustion) {
}
}
-} // namespace
+struct BindTestCase {
+ TestAddress bind_to;
+ int want = 0;
+ absl::optional<int> want_gvisor;
+};
+
+// Test fixture for socket binding.
+class Fixture
+ : public ::testing::TestWithParam<std::tuple<SocketKind, BindTestCase>> {};
+
+TEST_P(Fixture, Bind) {
+ auto [socket_factory, test_case] = GetParam();
+ auto socket = socket_factory.Create();
+ if (!socket.ok()) {
+ ASSERT_EQ(socket.error().errno_value(), EACCES);
+ GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow "
+ "creation of ICMP or ICMPv6 sockets";
+ }
+ auto socket_fd = std::move(socket).ValueOrDie();
+
+ const int want = test_case.want_gvisor.has_value() && IsRunningOnGvisor()
+ ? *test_case.want_gvisor
+ : test_case.want;
+ if (want == 0) {
+ EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr),
+ test_case.bind_to.addr_len),
+ SyscallSucceeds());
+ } else {
+ EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr),
+ test_case.bind_to.addr_len),
+ SyscallFailsWithErrno(want));
+ }
+}
+
+std::vector<std::tuple<SocketKind, BindTestCase>> ICMPTestCases() {
+ return ApplyVec<std::tuple<SocketKind, BindTestCase>>(
+ [](const BindTestCase& test_case) {
+ return std::make_tuple(ICMPUnboundSocket(0), test_case);
+ },
+ std::vector<BindTestCase>{
+ {
+ .bind_to = V4Any(),
+ .want = 0,
+ .want_gvisor = 0,
+ },
+ {
+ .bind_to = V4Broadcast(),
+ .want = EADDRNOTAVAIL,
+ // TODO(gvisor.dev/issue/5711): Remove want_gvisor once ICMP
+ // sockets are no longer allowed to bind to broadcast addresses.
+ .want_gvisor = 0,
+ },
+ {
+ .bind_to = V4Loopback(),
+ .want = 0,
+ },
+ {
+ .bind_to = V4LoopbackSubnetBroadcast(),
+ .want = EADDRNOTAVAIL,
+ // TODO(gvisor.dev/issue/5711): Remove want_gvisor once ICMP
+ // sockets are no longer allowed to bind to broadcast addresses.
+ .want_gvisor = 0,
+ },
+ {
+ .bind_to = V4Multicast(),
+ .want = EADDRNOTAVAIL,
+ },
+ {
+ .bind_to = V4MulticastAllHosts(),
+ .want = EADDRNOTAVAIL,
+ },
+ {
+ .bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"),
+ .want = EADDRNOTAVAIL,
+ },
+ // TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the test
+ // cases below once ICMP sockets return EAFNOSUPPORT when binding to
+ // IPv6 addresses.
+ {
+ .bind_to = V6Any(),
+ .want = EAFNOSUPPORT,
+ .want_gvisor = EINVAL,
+ },
+ {
+ .bind_to = V6Loopback(),
+ .want = EAFNOSUPPORT,
+ .want_gvisor = EINVAL,
+ },
+ {
+ .bind_to = V6Multicast(),
+ .want = EAFNOSUPPORT,
+ .want_gvisor = EINVAL,
+ },
+ {
+ .bind_to = V6MulticastInterfaceLocalAllNodes(),
+ .want = EAFNOSUPPORT,
+ .want_gvisor = EINVAL,
+ },
+ {
+ .bind_to = V6MulticastLinkLocalAllNodes(),
+ .want = EAFNOSUPPORT,
+ .want_gvisor = EINVAL,
+ },
+ {
+ .bind_to = V6MulticastLinkLocalAllRouters(),
+ .want = EAFNOSUPPORT,
+ .want_gvisor = EINVAL,
+ },
+ {
+ .bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"),
+ .want = EAFNOSUPPORT,
+ .want_gvisor = EINVAL,
+ },
+ });
+}
+std::vector<std::tuple<SocketKind, BindTestCase>> ICMPv6TestCases() {
+ return ApplyVec<std::tuple<SocketKind, BindTestCase>>(
+ [](const BindTestCase& test_case) {
+ return std::make_tuple(ICMPv6UnboundSocket(0), test_case);
+ },
+ std::vector<BindTestCase>{
+ {
+ .bind_to = V4Any(),
+ .want = EINVAL,
+ },
+ {
+ .bind_to = V4Broadcast(),
+ .want = EINVAL,
+ },
+ {
+ .bind_to = V4Loopback(),
+ .want = EINVAL,
+ },
+ {
+ .bind_to = V4LoopbackSubnetBroadcast(),
+ .want = EINVAL,
+ },
+ {
+ .bind_to = V4Multicast(),
+ .want = EINVAL,
+ },
+ {
+ .bind_to = V4MulticastAllHosts(),
+ .want = EINVAL,
+ },
+ {
+ .bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"),
+ .want = EINVAL,
+ },
+ {
+ .bind_to = V6Any(),
+ .want = 0,
+ },
+ {
+ .bind_to = V6Loopback(),
+ .want = 0,
+ },
+ // TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the
+ // multicast test cases below once ICMPv6 sockets return EINVAL when
+ // binding to IPv6 multicast addresses.
+ {
+ .bind_to = V6Multicast(),
+ .want = EINVAL,
+ .want_gvisor = EADDRNOTAVAIL,
+ },
+ {
+ .bind_to = V6MulticastInterfaceLocalAllNodes(),
+ .want = EINVAL,
+ .want_gvisor = EADDRNOTAVAIL,
+ },
+ {
+ .bind_to = V6MulticastLinkLocalAllNodes(),
+ .want = EINVAL,
+ .want_gvisor = EADDRNOTAVAIL,
+ },
+ {
+ .bind_to = V6MulticastLinkLocalAllRouters(),
+ .want = EINVAL,
+ .want_gvisor = EADDRNOTAVAIL,
+ },
+ {
+ .bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"),
+ .want = EADDRNOTAVAIL,
+ },
+ });
+}
+
+std::vector<std::tuple<SocketKind, BindTestCase>> AllTestCases() {
+ return VecCat<std::tuple<SocketKind, BindTestCase>>(ICMPTestCases(),
+ ICMPv6TestCases());
+}
+
+std::string TestDescription(
+ const ::testing::TestParamInfo<Fixture::ParamType>& info) {
+ auto [socket_factory, test_case] = info.param;
+ std::string name = absl::StrJoin(
+ {socket_factory.description, test_case.bind_to.description}, "_");
+ absl::c_replace_if(
+ name, [](char c) { return !std::isalnum(c); }, '_');
+ return name;
+}
+
+INSTANTIATE_TEST_SUITE_P(PingSockets, Fixture,
+ ::testing::ValuesIn(AllTestCases()), TestDescription);
+
+} // namespace
} // namespace testing
} // namespace gvisor
diff --git a/test/syscalls/linux/pipe.cc b/test/syscalls/linux/pipe.cc
index 294a72468..0bba86846 100644
--- a/test/syscalls/linux/pipe.cc
+++ b/test/syscalls/linux/pipe.cc
@@ -53,6 +53,7 @@ void SigRecordingHandler(int signum, siginfo_t* siginfo,
}
PosixErrorOr<Cleanup> RegisterSignalHandler(int signum) {
+ global_num_signals_received = 0;
struct sigaction handler;
handler.sa_sigaction = SigRecordingHandler;
sigemptyset(&handler.sa_mask);
diff --git a/test/syscalls/linux/rename.cc b/test/syscalls/linux/rename.cc
index 76a8da65f..561eed99f 100644
--- a/test/syscalls/linux/rename.cc
+++ b/test/syscalls/linux/rename.cc
@@ -26,6 +26,8 @@
#include "test/util/temp_path.h"
#include "test/util/test_util.h"
+using ::testing::AnyOf;
+
namespace gvisor {
namespace testing {
@@ -438,6 +440,60 @@ TEST(RenameTest, SysfsDirectoryToSelf) {
EXPECT_THAT(rename(path.c_str(), path.c_str()), SyscallSucceeds());
}
+#ifndef SYS_renameat2
+#if defined(__x86_64__)
+#define SYS_renameat2 316
+#elif defined(__aarch64__)
+#define SYS_renameat2 276
+#else
+#error "Unknown architecture"
+#endif
+#endif // SYS_renameat2
+
+#ifndef RENAME_NOREPLACE
+#define RENAME_NOREPLACE (1 << 0)
+#endif // RENAME_NOREPLACE
+
+int renameat2(int olddirfd, const char* oldpath, int newdirfd,
+ const char* newpath, unsigned int flags) {
+ return syscall(SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags);
+}
+
+TEST(Renameat2Test, NoReplaceSuccess) {
+ auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
+ std::string const newpath = NewTempAbsPath();
+ // renameat2 may fail with ENOSYS (if the syscall is unsupported) or EINVAL
+ // (if flags are unsupported), or succeed (if RENAME_NOREPLACE is operating
+ // correctly).
+ EXPECT_THAT(
+ renameat2(AT_FDCWD, f.path().c_str(), AT_FDCWD, newpath.c_str(),
+ RENAME_NOREPLACE),
+ AnyOf(SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL)), SyscallSucceeds()));
+}
+
+TEST(Renameat2Test, NoReplaceExisting) {
+ auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
+ auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
+ // renameat2 may fail with ENOSYS (if the syscall is unsupported), EINVAL (if
+ // flags are unsupported), or EEXIST (if RENAME_NOREPLACE is operating
+ // correctly).
+ EXPECT_THAT(renameat2(AT_FDCWD, f1.path().c_str(), AT_FDCWD,
+ f2.path().c_str(), RENAME_NOREPLACE),
+ SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL, EEXIST)));
+}
+
+TEST(Renameat2Test, NoReplaceDot) {
+ auto d1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ auto d2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ // renameat2 may fail with ENOSYS (if the syscall is unsupported), EINVAL (if
+ // flags are unsupported), or EEXIST (if RENAME_NOREPLACE is operating
+ // correctly).
+ EXPECT_THAT(
+ renameat2(AT_FDCWD, d1.path().c_str(), AT_FDCWD,
+ absl::StrCat(d2.path(), "/.").c_str(), RENAME_NOREPLACE),
+ SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL, EEXIST)));
+}
+
} // namespace
} // namespace testing
diff --git a/test/syscalls/linux/semaphore.cc b/test/syscalls/linux/semaphore.cc
index 54cbda19d..f72957f89 100644
--- a/test/syscalls/linux/semaphore.cc
+++ b/test/syscalls/linux/semaphore.cc
@@ -22,12 +22,12 @@
#include <ctime>
#include <set>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
#include "absl/base/macros.h"
#include "absl/memory/memory.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
#include "test/util/capability_util.h"
#include "test/util/test_util.h"
#include "test/util/thread_util.h"
@@ -106,6 +106,9 @@ TEST(SemaphoreTest, SemGet) {
// Tests system-wide limits for semget.
TEST(SemaphoreTest, SemGetSystemLimits) {
+ // Disable save so that we don't trigger save/restore too many times.
+ const DisableSave ds;
+
// Exceed number of semaphores per set.
EXPECT_THAT(semget(IPC_PRIVATE, kSemMsl + 1, 0),
SyscallFailsWithErrno(EINVAL));
diff --git a/test/syscalls/linux/socket_inet_loopback.cc b/test/syscalls/linux/socket_inet_loopback.cc
index 2fc160cdd..a3bdada86 100644
--- a/test/syscalls/linux/socket_inet_loopback.cc
+++ b/test/syscalls/linux/socket_inet_loopback.cc
@@ -692,6 +692,78 @@ TEST_P(SocketInetLoopbackTest, TCPListenShutdownConnectingRead) {
});
}
+// Test close of a non-blocking connecting socket.
+TEST_P(SocketInetLoopbackTest, TCPNonBlockingConnectClose) {
+ TestParam const& param = GetParam();
+ TestAddress const& listener = param.listener;
+ TestAddress const& connector = param.connector;
+
+ // Create the listening socket.
+ FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Socket(listener.family(), SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP));
+ sockaddr_storage listen_addr = listener.addr;
+ ASSERT_THAT(
+ bind(listen_fd.get(), AsSockAddr(&listen_addr), listener.addr_len),
+ SyscallSucceeds());
+ ASSERT_THAT(listen(listen_fd.get(), 0), SyscallSucceeds());
+
+ // Get the port bound by the listening socket.
+ socklen_t addrlen = listener.addr_len;
+ ASSERT_THAT(getsockname(listen_fd.get(), AsSockAddr(&listen_addr), &addrlen),
+ SyscallSucceeds());
+ ASSERT_EQ(addrlen, listener.addr_len);
+ uint16_t const port =
+ ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr));
+
+ sockaddr_storage conn_addr = connector.addr;
+ ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port));
+
+ // Try many iterations to catch a race with socket close and handshake
+ // completion.
+ for (int i = 0; i < 1000; ++i) {
+ FileDescriptor client = ASSERT_NO_ERRNO_AND_VALUE(
+ Socket(connector.family(), SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP));
+ ASSERT_THAT(
+ connect(client.get(), AsSockAddr(&conn_addr), connector.addr_len),
+ SyscallFailsWithErrno(EINPROGRESS));
+ ASSERT_THAT(close(client.release()), SyscallSucceeds());
+
+ // Accept any connections and check if they were closed from the peer. Not
+ // all client connects would result in an acceptable connection as the
+ // client handshake might never complete if the socket close was processed
+ // sooner than the non-blocking connect OR the accept queue is full. We are
+ // only interested in the case where we do have an acceptable completed
+ // connection. The accept is non-blocking here, which means that at the time
+ // of listener close (after the loop ends), we could still have a completed
+ // connection (from connect of any previous iteration) in the accept queue.
+ // The listener close would clean up the accept queue.
+ int accepted_fd;
+ ASSERT_THAT(accepted_fd = accept(listen_fd.get(), nullptr, nullptr),
+ AnyOf(SyscallSucceeds(), SyscallFailsWithErrno(EWOULDBLOCK)));
+ if (accepted_fd < 0) {
+ continue;
+ }
+ FileDescriptor accepted(accepted_fd);
+ struct pollfd pfd = {
+ .fd = accepted.get(),
+ .events = POLLIN | POLLRDHUP,
+ };
+ // Use a large timeout to accomodate for retransmitted FINs.
+ constexpr int kTimeout = 30000;
+ int n = poll(&pfd, 1, kTimeout);
+ ASSERT_GE(n, 0) << strerror(errno);
+ ASSERT_EQ(n, 1);
+
+ if (IsRunningOnGvisor() && GvisorPlatform() != Platform::kFuchsia) {
+ // TODO(gvisor.dev/issue/6015): Notify POLLRDHUP on incoming FIN.
+ ASSERT_EQ(pfd.revents, POLLIN);
+ } else {
+ ASSERT_EQ(pfd.revents, POLLIN | POLLRDHUP);
+ }
+ ASSERT_THAT(close(accepted.release()), SyscallSucceeds());
+ }
+}
+
// TODO(b/157236388): Remove once bug is fixed. Test fails w/
// random save as established connections which can't be delivered to the accept
// queue because the queue is full are not correctly delivered after restore
diff --git a/test/syscalls/linux/socket_test_util.cc b/test/syscalls/linux/socket_test_util.cc
index 9e3a129cf..6039b2a67 100644
--- a/test/syscalls/linux/socket_test_util.cc
+++ b/test/syscalls/linux/socket_test_util.cc
@@ -15,6 +15,7 @@
#include "test/syscalls/linux/socket_test_util.h"
#include <arpa/inet.h>
+#include <netinet/in.h>
#include <poll.h>
#include <sys/socket.h>
@@ -798,84 +799,82 @@ TestAddress TestAddress::WithPort(uint16_t port) const {
return addr;
}
-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;
-}
+namespace {
-TestAddress V4Loopback() {
- TestAddress t("V4Loopback");
+TestAddress V4Addr(std::string description, in_addr_t addr) {
+ TestAddress t(std::move(description));
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);
+ reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr = addr;
return t;
}
-TestAddress V4MappedAny() {
- TestAddress t("V4MappedAny");
+TestAddress V6Addr(std::string description, const in6_addr& addr) {
+ TestAddress t(std::move(description));
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);
+ reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr = addr;
return t;
}
+} // namespace
+
+TestAddress V4AddrStr(std::string description, const char* addr) {
+ in_addr_t s_addr;
+ inet_pton(AF_INET, addr, &s_addr);
+ return V4Addr(description, s_addr);
+}
+
+TestAddress V6AddrStr(std::string description, const char* addr) {
+ struct in6_addr s_addr;
+ inet_pton(AF_INET6, addr, &s_addr);
+ return V6Addr(description, s_addr);
+}
+
+TestAddress V4Any() { return V4Addr("V4Any", htonl(INADDR_ANY)); }
+
+TestAddress V4Broadcast() {
+ return V4Addr("V4Broadcast", htonl(INADDR_BROADCAST));
+}
+
+TestAddress V4Loopback() {
+ return V4Addr("V4Loopback", htonl(INADDR_LOOPBACK));
+}
+
+TestAddress V4LoopbackSubnetBroadcast() {
+ return V4AddrStr("V4LoopbackSubnetBroadcast", "127.255.255.255");
+}
+
+TestAddress V4MappedAny() { return V6AddrStr("V4MappedAny", "::ffff:0.0.0.0"); }
+
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;
+ return V6AddrStr("V4MappedLoopback", "::ffff:127.0.0.1");
}
TestAddress V4Multicast() {
- TestAddress t("V4Multicast");
- t.addr.ss_family = AF_INET;
- t.addr_len = sizeof(sockaddr_in);
- reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr =
- inet_addr(kMulticastAddress);
- return t;
+ return V4Addr("V4Multicast", inet_addr(kMulticastAddress));
}
-TestAddress V4Broadcast() {
- TestAddress t("V4Broadcast");
- t.addr.ss_family = AF_INET;
- t.addr_len = sizeof(sockaddr_in);
- reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr =
- htonl(INADDR_BROADCAST);
- return t;
+TestAddress V4MulticastAllHosts() {
+ return V4Addr("V4MulticastAllHosts", htonl(INADDR_ALLHOSTS_GROUP));
}
-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 V6Any() { return V6Addr("V6Any", in6addr_any); }
+
+TestAddress V6Loopback() { return V6Addr("V6Loopback", in6addr_loopback); }
+
+TestAddress V6Multicast() { return V6AddrStr("V6Multicast", "ff05::1234"); }
+
+TestAddress V6MulticastInterfaceLocalAllNodes() {
+ return V6AddrStr("V6MulticastInterfaceLocalAllNodes", "ff01::1");
}
-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;
+TestAddress V6MulticastLinkLocalAllNodes() {
+ return V6AddrStr("V6MulticastLinkLocalAllNodes", "ff02::1");
}
-TestAddress V6Multicast() {
- TestAddress t("V6Multicast");
- t.addr.ss_family = AF_INET6;
- t.addr_len = sizeof(sockaddr_in6);
- EXPECT_EQ(
- 1,
- inet_pton(AF_INET6, "ff05::1234",
- reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr.s6_addr));
- return t;
+TestAddress V6MulticastLinkLocalAllRouters() {
+ return V6AddrStr("V6MulticastLinkLocalAllRouters", "ff02::2");
}
// Checksum computes the internet checksum of a buffer.
diff --git a/test/syscalls/linux/socket_test_util.h b/test/syscalls/linux/socket_test_util.h
index f7ba90130..76dc090e0 100644
--- a/test/syscalls/linux/socket_test_util.h
+++ b/test/syscalls/linux/socket_test_util.h
@@ -499,15 +499,45 @@ struct TestAddress {
constexpr char kMulticastAddress[] = "224.0.2.1";
constexpr char kBroadcastAddress[] = "255.255.255.255";
+// Returns a TestAddress with `addr` parsed as an IPv4 address described by
+// `description`.
+TestAddress V4AddrStr(std::string description, const char* addr);
+// Returns a TestAddress with `addr` parsed as an IPv6 address described by
+// `description`.
+TestAddress V6AddrStr(std::string description, const char* addr);
+
+// Returns a TestAddress for the IPv4 any address.
TestAddress V4Any();
+// Returns a TestAddress for the IPv4 limited broadcast address.
TestAddress V4Broadcast();
+// Returns a TestAddress for the IPv4 loopback address.
TestAddress V4Loopback();
+// Returns a TestAddress for the subnet broadcast of the IPv4 loopback address.
+TestAddress V4LoopbackSubnetBroadcast();
+// Returns a TestAddress for the IPv4-mapped IPv6 any address.
TestAddress V4MappedAny();
+// Returns a TestAddress for the IPv4-mapped IPv6 loopback address.
TestAddress V4MappedLoopback();
+// Returns a TestAddress for a IPv4 multicast address.
TestAddress V4Multicast();
+// Returns a TestAddress for the IPv4 all-hosts multicast group address.
+TestAddress V4MulticastAllHosts();
+
+// Returns a TestAddress for the IPv6 any address.
TestAddress V6Any();
+// Returns a TestAddress for the IPv6 loopback address.
TestAddress V6Loopback();
+// Returns a TestAddress for a IPv6 multicast address.
TestAddress V6Multicast();
+// Returns a TestAddress for the IPv6 interface-local all-nodes multicast group
+// address.
+TestAddress V6MulticastInterfaceLocalAllNodes();
+// Returns a TestAddress for the IPv6 link-local all-nodes multicast group
+// address.
+TestAddress V6MulticastLinkLocalAllNodes();
+// Returns a TestAddress for the IPv6 link-local all-routers multicast group
+// address.
+TestAddress V6MulticastLinkLocalAllRouters();
// Compute the internet checksum of an IP header.
uint16_t IPChecksum(struct iphdr ip);
diff --git a/test/syscalls/linux/udp_socket.cc b/test/syscalls/linux/udp_socket.cc
index 29e174f71..2b687c198 100644
--- a/test/syscalls/linux/udp_socket.cc
+++ b/test/syscalls/linux/udp_socket.cc
@@ -791,14 +791,14 @@ TEST_P(UdpSocketTest, RecvErrorConnRefused) {
iov.iov_len = kBufLen;
size_t control_buf_len = CMSG_SPACE(sizeof(sock_extended_err) + addrlen_);
- char* control_buf = static_cast<char*>(calloc(1, control_buf_len));
+ std::vector<char> control_buf(control_buf_len);
struct sockaddr_storage remote;
memset(&remote, 0, sizeof(remote));
struct msghdr msg = {};
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
- msg.msg_control = control_buf;
+ msg.msg_control = control_buf.data();
msg.msg_controllen = control_buf_len;
msg.msg_name = reinterpret_cast<void*>(&remote);
msg.msg_namelen = addrlen_;