summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/udp_bind.cc
diff options
context:
space:
mode:
authorBrian Geffon <bgeffon@google.com>2018-12-10 14:41:40 -0800
committerShentubot <shentubot@google.com>2018-12-10 14:42:34 -0800
commitd3bc79bc8438206ac6a14fde4eaa288fc07eee82 (patch)
treee820398591bfd1503456e877fa0c2bdd0f994959 /test/syscalls/linux/udp_bind.cc
parent833edbd10b49db1f934dcb2495dcb41c1310eea4 (diff)
Open source system call tests.
PiperOrigin-RevId: 224886231 Change-Id: I0fccb4d994601739d8b16b1d4e6b31f40297fb22
Diffstat (limited to 'test/syscalls/linux/udp_bind.cc')
-rw-r--r--test/syscalls/linux/udp_bind.cc316
1 files changed, 316 insertions, 0 deletions
diff --git a/test/syscalls/linux/udp_bind.cc b/test/syscalls/linux/udp_bind.cc
new file mode 100644
index 000000000..419aaac76
--- /dev/null
+++ b/test/syscalls/linux/udp_bind.cc
@@ -0,0 +1,316 @@
+// Copyright 2018 Google LLC
+//
+// 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 <sys/socket.h>
+#include <sys/types.h>
+
+#include "gtest/gtest.h"
+#include "test/syscalls/linux/socket_test_util.h"
+#include "test/util/file_descriptor.h"
+#include "test/util/test_util.h"
+
+namespace gvisor {
+namespace testing {
+
+namespace {
+
+struct sockaddr_in_common {
+ sa_family_t sin_family;
+ in_port_t sin_port;
+};
+
+struct SendtoTestParam {
+ // Human readable description of test parameter.
+ std::string description;
+
+ // Test is broken in gVisor, skip.
+ bool skip_on_gvisor;
+
+ // Domain for the socket that will do the sending.
+ int send_domain;
+
+ // Address to bind for the socket that will do the sending.
+ struct sockaddr_storage send_addr;
+ socklen_t send_addr_len; // 0 for unbound.
+
+ // Address to connect to for the socket that will do the sending.
+ struct sockaddr_storage connect_addr;
+ socklen_t connect_addr_len; // 0 for no connection.
+
+ // Domain for the socket that will do the receiving.
+ int recv_domain;
+
+ // Address to bind for the socket that will do the receiving.
+ struct sockaddr_storage recv_addr;
+ socklen_t recv_addr_len;
+
+ // Address to send to.
+ struct sockaddr_storage sendto_addr;
+ socklen_t sendto_addr_len;
+
+ // Expected errno for the sendto call.
+ std::vector<int> sendto_errnos; // empty on success.
+};
+
+class SendtoTest : public ::testing::TestWithParam<SendtoTestParam> {
+ protected:
+ SendtoTest() {
+ // gUnit uses printf, so so will we.
+ printf("Testing with %s\n", GetParam().description.c_str());
+ }
+};
+
+TEST_P(SendtoTest, Sendto) {
+ auto param = GetParam();
+
+ SKIP_IF(param.skip_on_gvisor && IsRunningOnGvisor());
+
+ const FileDescriptor s1 =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(param.send_domain, SOCK_DGRAM, 0));
+ const FileDescriptor s2 =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(param.recv_domain, SOCK_DGRAM, 0));
+
+ if (param.send_addr_len > 0) {
+ ASSERT_THAT(bind(s1.get(), reinterpret_cast<sockaddr*>(&param.send_addr),
+ param.send_addr_len),
+ SyscallSucceeds());
+ }
+
+ if (param.connect_addr_len > 0) {
+ ASSERT_THAT(
+ connect(s1.get(), reinterpret_cast<sockaddr*>(&param.connect_addr),
+ param.connect_addr_len),
+ SyscallSucceeds());
+ }
+
+ ASSERT_THAT(bind(s2.get(), reinterpret_cast<sockaddr*>(&param.recv_addr),
+ param.recv_addr_len),
+ SyscallSucceeds());
+
+ struct sockaddr_storage real_recv_addr = {};
+ socklen_t real_recv_addr_len = param.recv_addr_len;
+ ASSERT_THAT(
+ getsockname(s2.get(), reinterpret_cast<sockaddr*>(&real_recv_addr),
+ &real_recv_addr_len),
+ SyscallSucceeds());
+
+ ASSERT_EQ(real_recv_addr_len, param.recv_addr_len);
+
+ int recv_port =
+ reinterpret_cast<sockaddr_in_common*>(&real_recv_addr)->sin_port;
+
+ struct sockaddr_storage sendto_addr = param.sendto_addr;
+ reinterpret_cast<sockaddr_in_common*>(&sendto_addr)->sin_port = recv_port;
+
+ char buf[20] = {};
+ if (!param.sendto_errnos.empty()) {
+ ASSERT_THAT(RetryEINTR(sendto)(s1.get(), buf, sizeof(buf), 0,
+ reinterpret_cast<sockaddr*>(&sendto_addr),
+ param.sendto_addr_len),
+ SyscallFailsWithErrno(ElementOf(param.sendto_errnos)));
+ return;
+ }
+
+ ASSERT_THAT(RetryEINTR(sendto)(s1.get(), buf, sizeof(buf), 0,
+ reinterpret_cast<sockaddr*>(&sendto_addr),
+ param.sendto_addr_len),
+ SyscallSucceedsWithValue(sizeof(buf)));
+
+ struct sockaddr_storage got_addr = {};
+ socklen_t got_addr_len = sizeof(sockaddr_storage);
+ ASSERT_THAT(RetryEINTR(recvfrom)(s2.get(), buf, sizeof(buf), 0,
+ reinterpret_cast<sockaddr*>(&got_addr),
+ &got_addr_len),
+ SyscallSucceedsWithValue(sizeof(buf)));
+
+ ASSERT_GT(got_addr_len, sizeof(sockaddr_in_common));
+ int got_port = reinterpret_cast<sockaddr_in_common*>(&got_addr)->sin_port;
+
+ struct sockaddr_storage sender_addr = {};
+ socklen_t sender_addr_len = sizeof(sockaddr_storage);
+ ASSERT_THAT(getsockname(s1.get(), reinterpret_cast<sockaddr*>(&sender_addr),
+ &sender_addr_len),
+ SyscallSucceeds());
+
+ ASSERT_GT(sender_addr_len, sizeof(sockaddr_in_common));
+ int sender_port =
+ reinterpret_cast<sockaddr_in_common*>(&sender_addr)->sin_port;
+
+ EXPECT_EQ(got_port, sender_port);
+}
+
+socklen_t Ipv4Addr(sockaddr_storage* addr, int port = 0) {
+ auto addr4 = reinterpret_cast<sockaddr_in*>(addr);
+ addr4->sin_family = AF_INET;
+ addr4->sin_port = port;
+ inet_pton(AF_INET, "127.0.0.1", &addr4->sin_addr.s_addr);
+ return sizeof(struct sockaddr_in);
+}
+
+socklen_t Ipv6Addr(sockaddr_storage* addr, int port = 0) {
+ auto addr6 = reinterpret_cast<sockaddr_in6*>(addr);
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_port = port;
+ inet_pton(AF_INET6, "::1", &addr6->sin6_addr.s6_addr);
+ return sizeof(struct sockaddr_in6);
+}
+
+socklen_t Ipv4MappedIpv6Addr(sockaddr_storage* addr, int port = 0) {
+ auto addr6 = reinterpret_cast<sockaddr_in6*>(addr);
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_port = port;
+ inet_pton(AF_INET6, "::ffff:127.0.0.1", &addr6->sin6_addr.s6_addr);
+ return sizeof(struct sockaddr_in6);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ UdpBindTest, SendtoTest,
+ ::testing::Values(
+ []() {
+ SendtoTestParam param = {};
+ param.description = "IPv4 mapped IPv6 sendto IPv4 mapped IPv6";
+ param.send_domain = AF_INET6;
+ param.send_addr_len = Ipv4MappedIpv6Addr(&param.send_addr);
+ param.recv_domain = AF_INET6;
+ param.recv_addr_len = Ipv4MappedIpv6Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4MappedIpv6Addr(&param.sendto_addr);
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "IPv6 sendto IPv6";
+ param.send_domain = AF_INET6;
+ param.send_addr_len = Ipv6Addr(&param.send_addr);
+ param.recv_domain = AF_INET6;
+ param.recv_addr_len = Ipv6Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv6Addr(&param.sendto_addr);
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "IPv4 sendto IPv4";
+ param.send_domain = AF_INET;
+ param.send_addr_len = Ipv4Addr(&param.send_addr);
+ param.recv_domain = AF_INET;
+ param.recv_addr_len = Ipv4Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4Addr(&param.sendto_addr);
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "IPv4 mapped IPv6 sendto IPv4";
+ param.send_domain = AF_INET6;
+ param.send_addr_len = Ipv4MappedIpv6Addr(&param.send_addr);
+ param.recv_domain = AF_INET;
+ param.recv_addr_len = Ipv4Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4MappedIpv6Addr(&param.sendto_addr);
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "IPv4 sendto IPv4 mapped IPv6";
+ param.send_domain = AF_INET;
+ param.send_addr_len = Ipv4Addr(&param.send_addr);
+ param.recv_domain = AF_INET6;
+ param.recv_addr_len = Ipv4MappedIpv6Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4Addr(&param.sendto_addr);
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "unbound IPv6 sendto IPv4 mapped IPv6";
+ param.send_domain = AF_INET6;
+ param.recv_domain = AF_INET6;
+ param.recv_addr_len = Ipv4MappedIpv6Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4MappedIpv6Addr(&param.sendto_addr);
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "unbound IPv6 sendto IPv4";
+ param.send_domain = AF_INET6;
+ param.recv_domain = AF_INET;
+ param.recv_addr_len = Ipv4Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4MappedIpv6Addr(&param.sendto_addr);
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "IPv6 sendto IPv4";
+ param.send_domain = AF_INET6;
+ param.send_addr_len = Ipv6Addr(&param.send_addr);
+ param.recv_domain = AF_INET;
+ param.recv_addr_len = Ipv4Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4MappedIpv6Addr(&param.sendto_addr);
+ param.sendto_errnos = {ENETUNREACH};
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "IPv4 mapped IPv6 sendto IPv6";
+ param.send_domain = AF_INET6;
+ param.send_addr_len = Ipv4MappedIpv6Addr(&param.send_addr);
+ param.recv_domain = AF_INET6;
+ param.recv_addr_len = Ipv6Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv6Addr(&param.sendto_addr);
+ param.sendto_errnos = {EAFNOSUPPORT};
+ // The errno returned changed in Linux commit c8e6ad0829a723.
+ param.sendto_errnos = {EINVAL, EAFNOSUPPORT};
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "connected IPv4 mapped IPv6 sendto IPv6";
+ param.send_domain = AF_INET6;
+ param.connect_addr_len =
+ Ipv4MappedIpv6Addr(&param.connect_addr, 5000);
+ param.recv_domain = AF_INET6;
+ param.recv_addr_len = Ipv6Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv6Addr(&param.sendto_addr);
+ // The errno returned changed in Linux commit c8e6ad0829a723.
+ param.sendto_errnos = {EINVAL, EAFNOSUPPORT};
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "connected IPv6 sendto IPv4 mapped IPv6";
+ // TODO: Determine if this inconsistent behavior is worth
+ // implementing.
+ param.skip_on_gvisor = true;
+ param.send_domain = AF_INET6;
+ param.connect_addr_len = Ipv6Addr(&param.connect_addr, 5000);
+ param.recv_domain = AF_INET6;
+ param.recv_addr_len = Ipv4MappedIpv6Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4MappedIpv6Addr(&param.sendto_addr);
+ return param;
+ }(),
+ []() {
+ SendtoTestParam param = {};
+ param.description = "connected IPv6 sendto IPv4";
+ // TODO: Determine if this inconsistent behavior is worth
+ // implementing.
+ param.skip_on_gvisor = true;
+ param.send_domain = AF_INET6;
+ param.connect_addr_len = Ipv6Addr(&param.connect_addr, 5000);
+ param.recv_domain = AF_INET;
+ param.recv_addr_len = Ipv4Addr(&param.recv_addr);
+ param.sendto_addr_len = Ipv4MappedIpv6Addr(&param.sendto_addr);
+ return param;
+ }()));
+
+} // namespace
+
+} // namespace testing
+} // namespace gvisor