gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/connect_external.cc (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <errno.h>
    16  #include <stdlib.h>
    17  #include <sys/socket.h>
    18  #include <sys/un.h>
    19  
    20  #include <cstring>
    21  #include <string>
    22  #include <tuple>
    23  
    24  #include "gmock/gmock.h"
    25  #include "gtest/gtest.h"
    26  #include "test/util/file_descriptor.h"
    27  #include "test/util/fs_util.h"
    28  #include "test/util/socket_util.h"
    29  #include "test/util/test_util.h"
    30  
    31  // This file contains tests specific to connecting to host UDS managed outside
    32  // the sandbox / test.
    33  //
    34  // A set of ultity sockets will be created externally in $TEST_UDS_TREE and
    35  // $TEST_UDS_ATTACH_TREE for these tests to interact with.
    36  
    37  namespace gvisor {
    38  namespace testing {
    39  
    40  namespace {
    41  
    42  struct ProtocolSocket {
    43    int protocol;
    44    std::string name;
    45  };
    46  
    47  // Parameter is (socket root dir, ProtocolSocket).
    48  using GoferStreamSeqpacketTest =
    49      ::testing::TestWithParam<std::tuple<std::string, ProtocolSocket>>;
    50  
    51  // Connect to a socket and verify that write/read work.
    52  //
    53  // An "echo" socket doesn't work for dgram sockets because our socket is
    54  // unnamed. The server thus has no way to reply to us.
    55  TEST_P(GoferStreamSeqpacketTest, Echo) {
    56    std::string env;
    57    ProtocolSocket proto;
    58    std::tie(env, proto) = GetParam();
    59  
    60    char* val = getenv(env.c_str());
    61    ASSERT_NE(val, nullptr);
    62    std::string root(val);
    63  
    64    FileDescriptor sock =
    65        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, proto.protocol, 0));
    66  
    67    std::string socket_path = JoinPath(root, proto.name, "echo");
    68  
    69    struct sockaddr_un addr = {};
    70    addr.sun_family = AF_UNIX;
    71    memcpy(addr.sun_path, socket_path.c_str(), socket_path.length());
    72  
    73    ASSERT_THAT(connect(sock.get(), reinterpret_cast<struct sockaddr*>(&addr),
    74                        sizeof(addr)),
    75                SyscallSucceeds());
    76  
    77    constexpr int kBufferSize = 64;
    78    char send_buffer[kBufferSize];
    79    memset(send_buffer, 'a', sizeof(send_buffer));
    80  
    81    ASSERT_THAT(WriteFd(sock.get(), send_buffer, sizeof(send_buffer)),
    82                SyscallSucceedsWithValue(sizeof(send_buffer)));
    83  
    84    char recv_buffer[kBufferSize];
    85    ASSERT_THAT(ReadFd(sock.get(), recv_buffer, sizeof(recv_buffer)),
    86                SyscallSucceedsWithValue(sizeof(recv_buffer)));
    87    ASSERT_EQ(0, memcmp(send_buffer, recv_buffer, sizeof(send_buffer)));
    88  }
    89  
    90  // It is not possible to connect to a bound but non-listening socket.
    91  TEST_P(GoferStreamSeqpacketTest, NonListening) {
    92    std::string env;
    93    ProtocolSocket proto;
    94    std::tie(env, proto) = GetParam();
    95  
    96    char* val = getenv(env.c_str());
    97    ASSERT_NE(val, nullptr);
    98    std::string root(val);
    99  
   100    FileDescriptor sock =
   101        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, proto.protocol, 0));
   102  
   103    std::string socket_path = JoinPath(root, proto.name, "nonlistening");
   104  
   105    struct sockaddr_un addr = {};
   106    addr.sun_family = AF_UNIX;
   107    memcpy(addr.sun_path, socket_path.c_str(), socket_path.length());
   108  
   109    ASSERT_THAT(connect(sock.get(), reinterpret_cast<struct sockaddr*>(&addr),
   110                        sizeof(addr)),
   111                SyscallFailsWithErrno(ECONNREFUSED));
   112  }
   113  
   114  INSTANTIATE_TEST_SUITE_P(
   115      StreamSeqpacket, GoferStreamSeqpacketTest,
   116      ::testing::Combine(
   117          // Test access via standard path and attach point.
   118          ::testing::Values("TEST_UDS_TREE", "TEST_UDS_ATTACH_TREE"),
   119          ::testing::Values(ProtocolSocket{SOCK_STREAM, "stream"},
   120                            ProtocolSocket{SOCK_SEQPACKET, "seqpacket"})));
   121  
   122  // Parameter is socket root dir.
   123  using GoferDgramTest = ::testing::TestWithParam<std::string>;
   124  
   125  // Connect to a socket and verify that write works.
   126  //
   127  // An "echo" socket doesn't work for dgram sockets because our socket is
   128  // unnamed. The server thus has no way to reply to us.
   129  TEST_P(GoferDgramTest, Null) {
   130    std::string env = GetParam();
   131    char* val = getenv(env.c_str());
   132    ASSERT_NE(val, nullptr);
   133    std::string root(val);
   134  
   135    FileDescriptor sock =
   136        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, SOCK_DGRAM, 0));
   137  
   138    std::string socket_path = JoinPath(root, "dgram/null");
   139  
   140    struct sockaddr_un addr = {};
   141    addr.sun_family = AF_UNIX;
   142    memcpy(addr.sun_path, socket_path.c_str(), socket_path.length());
   143  
   144    ASSERT_THAT(connect(sock.get(), reinterpret_cast<struct sockaddr*>(&addr),
   145                        sizeof(addr)),
   146                SyscallSucceeds());
   147  
   148    constexpr int kBufferSize = 64;
   149    char send_buffer[kBufferSize];
   150    memset(send_buffer, 'a', sizeof(send_buffer));
   151  
   152    ASSERT_THAT(WriteFd(sock.get(), send_buffer, sizeof(send_buffer)),
   153                SyscallSucceedsWithValue(sizeof(send_buffer)));
   154  }
   155  
   156  INSTANTIATE_TEST_SUITE_P(Dgram, GoferDgramTest,
   157                           // Test access via standard path and attach point.
   158                           ::testing::Values("TEST_UDS_TREE",
   159                                             "TEST_UDS_ATTACH_TREE"));
   160  
   161  }  // namespace
   162  
   163  }  // namespace testing
   164  }  // namespace gvisor