1 //===-- SocketTest.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SocketTestUtilities.h" 10 #include "TestingSupport/SubsystemRAII.h" 11 #include "lldb/Host/Config.h" 12 #include "lldb/Utility/UriParser.h" 13 #include "llvm/Testing/Support/Error.h" 14 #include "gtest/gtest.h" 15 16 using namespace lldb_private; 17 18 struct SocketTestParams { 19 bool is_ipv6; 20 std::string localhost_ip; 21 }; 22 23 class SocketTest : public testing::TestWithParam<SocketTestParams> { 24 public: 25 SubsystemRAII<Socket> subsystems; 26 27 protected: 28 bool HostSupportsProtocol() const { 29 if (GetParam().is_ipv6) 30 return HostSupportsIPv6(); 31 return HostSupportsIPv4(); 32 } 33 }; 34 35 TEST_P(SocketTest, DecodeHostAndPort) { 36 std::string host_str; 37 std::string port_str; 38 uint16_t port; 39 40 EXPECT_THAT_ERROR( 41 Socket::DecodeHostAndPort("localhost:1138", host_str, port_str, port), 42 llvm::Succeeded()); 43 EXPECT_STREQ("localhost", host_str.c_str()); 44 EXPECT_STREQ("1138", port_str.c_str()); 45 EXPECT_EQ(1138, port); 46 47 EXPECT_THAT_ERROR( 48 Socket::DecodeHostAndPort("google.com:65536", host_str, port_str, port), 49 llvm::FailedWithMessage( 50 "invalid host:port specification: 'google.com:65536'")); 51 52 EXPECT_THAT_ERROR( 53 Socket::DecodeHostAndPort("google.com:-1138", host_str, port_str, port), 54 llvm::FailedWithMessage( 55 "invalid host:port specification: 'google.com:-1138'")); 56 57 EXPECT_THAT_ERROR( 58 Socket::DecodeHostAndPort("google.com:65536", host_str, port_str, port), 59 llvm::FailedWithMessage( 60 "invalid host:port specification: 'google.com:65536'")); 61 62 EXPECT_THAT_ERROR( 63 Socket::DecodeHostAndPort("12345", host_str, port_str, port), 64 llvm::Succeeded()); 65 EXPECT_STREQ("", host_str.c_str()); 66 EXPECT_STREQ("12345", port_str.c_str()); 67 EXPECT_EQ(12345, port); 68 69 EXPECT_THAT_ERROR(Socket::DecodeHostAndPort("*:0", host_str, port_str, port), 70 llvm::Succeeded()); 71 EXPECT_STREQ("*", host_str.c_str()); 72 EXPECT_STREQ("0", port_str.c_str()); 73 EXPECT_EQ(0, port); 74 75 EXPECT_THAT_ERROR( 76 Socket::DecodeHostAndPort("*:65535", host_str, port_str, port), 77 llvm::Succeeded()); 78 EXPECT_STREQ("*", host_str.c_str()); 79 EXPECT_STREQ("65535", port_str.c_str()); 80 EXPECT_EQ(65535, port); 81 82 EXPECT_THAT_ERROR( 83 Socket::DecodeHostAndPort("[::1]:12345", host_str, port_str, port), 84 llvm::Succeeded()); 85 EXPECT_STREQ("::1", host_str.c_str()); 86 EXPECT_STREQ("12345", port_str.c_str()); 87 EXPECT_EQ(12345, port); 88 89 EXPECT_THAT_ERROR(Socket::DecodeHostAndPort("[abcd:12fg:AF58::1]:12345", 90 host_str, port_str, port), 91 llvm::Succeeded()); 92 EXPECT_STREQ("abcd:12fg:AF58::1", host_str.c_str()); 93 EXPECT_STREQ("12345", port_str.c_str()); 94 EXPECT_EQ(12345, port); 95 } 96 97 #if LLDB_ENABLE_POSIX 98 TEST_P(SocketTest, DomainListenConnectAccept) { 99 llvm::SmallString<64> Path; 100 std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path); 101 ASSERT_FALSE(EC); 102 llvm::sys::path::append(Path, "test"); 103 104 // Skip the test if the $TMPDIR is too long to hold a domain socket. 105 if (Path.size() > 107u) 106 return; 107 108 std::unique_ptr<DomainSocket> socket_a_up; 109 std::unique_ptr<DomainSocket> socket_b_up; 110 CreateDomainConnectedSockets(Path, &socket_a_up, &socket_b_up); 111 } 112 #endif 113 114 TEST_P(SocketTest, TCPListen0ConnectAccept) { 115 if (!HostSupportsProtocol()) 116 return; 117 std::unique_ptr<TCPSocket> socket_a_up; 118 std::unique_ptr<TCPSocket> socket_b_up; 119 CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, 120 &socket_b_up); 121 } 122 123 TEST_P(SocketTest, TCPGetAddress) { 124 std::unique_ptr<TCPSocket> socket_a_up; 125 std::unique_ptr<TCPSocket> socket_b_up; 126 if (!HostSupportsProtocol()) 127 return; 128 CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, 129 &socket_b_up); 130 131 EXPECT_EQ(socket_a_up->GetLocalPortNumber(), 132 socket_b_up->GetRemotePortNumber()); 133 EXPECT_EQ(socket_b_up->GetLocalPortNumber(), 134 socket_a_up->GetRemotePortNumber()); 135 EXPECT_NE(socket_a_up->GetLocalPortNumber(), 136 socket_b_up->GetLocalPortNumber()); 137 EXPECT_STREQ(GetParam().localhost_ip.c_str(), 138 socket_a_up->GetRemoteIPAddress().c_str()); 139 EXPECT_STREQ(GetParam().localhost_ip.c_str(), 140 socket_b_up->GetRemoteIPAddress().c_str()); 141 } 142 143 TEST_P(SocketTest, UDPConnect) { 144 // UDPSocket::Connect() creates sockets with AF_INET (IPv4). 145 if (!HostSupportsIPv4()) 146 return; 147 llvm::Expected<std::unique_ptr<UDPSocket>> socket = 148 UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false); 149 150 ASSERT_THAT_EXPECTED(socket, llvm::Succeeded()); 151 EXPECT_TRUE(socket.get()->IsValid()); 152 } 153 154 TEST_P(SocketTest, TCPListen0GetPort) { 155 if (!HostSupportsIPv4()) 156 return; 157 llvm::Expected<std::unique_ptr<TCPSocket>> sock = 158 Socket::TcpListen("10.10.12.3:0", false); 159 ASSERT_THAT_EXPECTED(sock, llvm::Succeeded()); 160 ASSERT_TRUE(sock.get()->IsValid()); 161 EXPECT_NE(sock.get()->GetLocalPortNumber(), 0); 162 } 163 164 TEST_P(SocketTest, TCPGetConnectURI) { 165 std::unique_ptr<TCPSocket> socket_a_up; 166 std::unique_ptr<TCPSocket> socket_b_up; 167 if (!HostSupportsProtocol()) 168 return; 169 CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, 170 &socket_b_up); 171 172 std::string uri(socket_a_up->GetRemoteConnectionURI()); 173 EXPECT_EQ((URI{"connect", GetParam().localhost_ip, 174 socket_a_up->GetRemotePortNumber(), "/"}), 175 URI::Parse(uri)); 176 } 177 178 TEST_P(SocketTest, UDPGetConnectURI) { 179 // UDPSocket::Connect() creates sockets with AF_INET (IPv4). 180 if (!HostSupportsIPv4()) 181 return; 182 llvm::Expected<std::unique_ptr<UDPSocket>> socket = 183 UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false); 184 ASSERT_THAT_EXPECTED(socket, llvm::Succeeded()); 185 186 std::string uri = socket.get()->GetRemoteConnectionURI(); 187 EXPECT_EQ((URI{"udp", "127.0.0.1", 0, "/"}), URI::Parse(uri)); 188 } 189 190 #if LLDB_ENABLE_POSIX 191 TEST_P(SocketTest, DomainGetConnectURI) { 192 llvm::SmallString<64> domain_path; 193 std::error_code EC = 194 llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", domain_path); 195 ASSERT_FALSE(EC); 196 llvm::sys::path::append(domain_path, "test"); 197 198 // Skip the test if the $TMPDIR is too long to hold a domain socket. 199 if (domain_path.size() > 107u) 200 return; 201 202 std::unique_ptr<DomainSocket> socket_a_up; 203 std::unique_ptr<DomainSocket> socket_b_up; 204 CreateDomainConnectedSockets(domain_path, &socket_a_up, &socket_b_up); 205 206 std::string uri(socket_a_up->GetRemoteConnectionURI()); 207 EXPECT_EQ((URI{"unix-connect", "", llvm::None, domain_path}), 208 URI::Parse(uri)); 209 210 EXPECT_EQ(socket_b_up->GetRemoteConnectionURI(), ""); 211 } 212 #endif 213 214 INSTANTIATE_TEST_SUITE_P( 215 SocketTests, SocketTest, 216 testing::Values(SocketTestParams{/*is_ipv6=*/false, 217 /*localhost_ip=*/"127.0.0.1"}, 218 SocketTestParams{/*is_ipv6=*/true, /*localhost_ip=*/"::1"}), 219 // Prints "SocketTests/SocketTest.DecodeHostAndPort/ipv4" etc. in test logs. 220 [](const testing::TestParamInfo<SocketTestParams> &info) { 221 return info.param.is_ipv6 ? "ipv6" : "ipv4"; 222 }); 223