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