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 "TestingSupport/Host/SocketTestUtilities.h" 10 #include "TestingSupport/SubsystemRAII.h" 11 #include "lldb/Host/Config.h" 12 #include "lldb/Host/MainLoop.h" 13 #include "lldb/Utility/UriParser.h" 14 #include "llvm/Testing/Support/Error.h" 15 #include "gmock/gmock.h" 16 #include "gtest/gtest.h" 17 #include <chrono> 18 19 using namespace lldb_private; 20 21 struct SocketTestParams { 22 bool is_ipv6; 23 std::string localhost_ip; 24 }; 25 26 class SocketTest : public testing::TestWithParam<SocketTestParams> { 27 public: 28 SubsystemRAII<Socket> subsystems; 29 30 protected: 31 bool HostSupportsProtocol() const { 32 if (GetParam().is_ipv6) 33 return HostSupportsIPv6(); 34 return HostSupportsIPv4(); 35 } 36 }; 37 38 TEST_F(SocketTest, DecodeHostAndPort) { 39 EXPECT_THAT_EXPECTED(Socket::DecodeHostAndPort("localhost:1138"), 40 llvm::HasValue(Socket::HostAndPort{"localhost", 1138})); 41 42 EXPECT_THAT_EXPECTED( 43 Socket::DecodeHostAndPort("google.com:65536"), 44 llvm::FailedWithMessage( 45 "invalid host:port specification: 'google.com:65536'")); 46 47 EXPECT_THAT_EXPECTED( 48 Socket::DecodeHostAndPort("google.com:-1138"), 49 llvm::FailedWithMessage( 50 "invalid host:port specification: 'google.com:-1138'")); 51 52 EXPECT_THAT_EXPECTED( 53 Socket::DecodeHostAndPort("google.com:65536"), 54 llvm::FailedWithMessage( 55 "invalid host:port specification: 'google.com:65536'")); 56 57 EXPECT_THAT_EXPECTED(Socket::DecodeHostAndPort("12345"), 58 llvm::HasValue(Socket::HostAndPort{"", 12345})); 59 60 EXPECT_THAT_EXPECTED(Socket::DecodeHostAndPort("*:0"), 61 llvm::HasValue(Socket::HostAndPort{"*", 0})); 62 63 EXPECT_THAT_EXPECTED(Socket::DecodeHostAndPort("*:65535"), 64 llvm::HasValue(Socket::HostAndPort{"*", 65535})); 65 66 EXPECT_THAT_EXPECTED(Socket::DecodeHostAndPort("[::1]:12345"), 67 llvm::HasValue(Socket::HostAndPort{"::1", 12345})); 68 69 EXPECT_THAT_EXPECTED( 70 Socket::DecodeHostAndPort("[abcd:12fg:AF58::1]:12345"), 71 llvm::HasValue(Socket::HostAndPort{"abcd:12fg:AF58::1", 12345})); 72 } 73 74 #if LLDB_ENABLE_POSIX 75 TEST_F(SocketTest, DomainListenConnectAccept) { 76 llvm::SmallString<64> Path; 77 std::error_code EC = 78 llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path); 79 ASSERT_FALSE(EC); 80 llvm::sys::path::append(Path, "test"); 81 82 // Skip the test if the $TMPDIR is too long to hold a domain socket. 83 if (Path.size() > 107u) 84 return; 85 86 std::unique_ptr<DomainSocket> socket_a_up; 87 std::unique_ptr<DomainSocket> socket_b_up; 88 CreateDomainConnectedSockets(Path, &socket_a_up, &socket_b_up); 89 } 90 91 TEST_F(SocketTest, DomainListenGetListeningConnectionURI) { 92 llvm::SmallString<64> Path; 93 std::error_code EC = 94 llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path); 95 ASSERT_FALSE(EC); 96 llvm::sys::path::append(Path, "test"); 97 98 // Skip the test if the $TMPDIR is too long to hold a domain socket. 99 if (Path.size() > 107u) 100 return; 101 102 auto listen_socket_up = std::make_unique<DomainSocket>( 103 /*should_close=*/true); 104 Status error = listen_socket_up->Listen(Path, 5); 105 ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded()); 106 ASSERT_TRUE(listen_socket_up->IsValid()); 107 108 ASSERT_THAT( 109 listen_socket_up->GetListeningConnectionURI(), 110 testing::ElementsAre(llvm::formatv("unix-connect://{0}", Path).str())); 111 } 112 113 TEST_F(SocketTest, DomainMainLoopAccept) { 114 llvm::SmallString<64> Path; 115 std::error_code EC = 116 llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path); 117 ASSERT_FALSE(EC); 118 llvm::sys::path::append(Path, "test"); 119 120 // Skip the test if the $TMPDIR is too long to hold a domain socket. 121 if (Path.size() > 107u) 122 return; 123 124 auto listen_socket_up = std::make_unique<DomainSocket>( 125 /*should_close=*/true); 126 Status error = listen_socket_up->Listen(Path, 5); 127 ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded()); 128 ASSERT_TRUE(listen_socket_up->IsValid()); 129 130 MainLoop loop; 131 std::unique_ptr<Socket> accepted_socket_up; 132 auto expected_handles = listen_socket_up->Accept( 133 loop, [&accepted_socket_up, &loop](std::unique_ptr<Socket> sock_up) { 134 accepted_socket_up = std::move(sock_up); 135 loop.RequestTermination(); 136 }); 137 ASSERT_THAT_EXPECTED(expected_handles, llvm::Succeeded()); 138 139 auto connect_socket_up = std::make_unique<DomainSocket>( 140 /*should_close=*/true); 141 ASSERT_THAT_ERROR(connect_socket_up->Connect(Path).ToError(), 142 llvm::Succeeded()); 143 ASSERT_TRUE(connect_socket_up->IsValid()); 144 145 loop.Run(); 146 ASSERT_TRUE(accepted_socket_up); 147 ASSERT_TRUE(accepted_socket_up->IsValid()); 148 } 149 #endif 150 151 TEST_P(SocketTest, TCPListen0ConnectAccept) { 152 if (!HostSupportsProtocol()) 153 return; 154 std::unique_ptr<TCPSocket> socket_a_up; 155 std::unique_ptr<TCPSocket> socket_b_up; 156 CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, 157 &socket_b_up); 158 } 159 160 TEST_P(SocketTest, TCPAcceptTimeout) { 161 if (!HostSupportsProtocol()) 162 return; 163 164 const bool child_processes_inherit = false; 165 auto listen_socket_up = 166 std::make_unique<TCPSocket>(true, child_processes_inherit); 167 Status error = listen_socket_up->Listen( 168 llvm::formatv("[{0}]:0", GetParam().localhost_ip).str(), 5); 169 ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded()); 170 ASSERT_TRUE(listen_socket_up->IsValid()); 171 172 Socket *socket; 173 ASSERT_THAT_ERROR( 174 listen_socket_up->Accept(std::chrono::milliseconds(10), socket) 175 .takeError(), 176 llvm::Failed<llvm::ErrorInfoBase>( 177 testing::Property(&llvm::ErrorInfoBase::convertToErrorCode, 178 std::make_error_code(std::errc::timed_out)))); 179 } 180 181 TEST_P(SocketTest, TCPMainLoopAccept) { 182 if (!HostSupportsProtocol()) 183 return; 184 185 auto listen_socket_up = std::make_unique<TCPSocket>(true); 186 Status error = listen_socket_up->Listen( 187 llvm::formatv("[{0}]:0", GetParam().localhost_ip).str(), 5); 188 ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded()); 189 ASSERT_TRUE(listen_socket_up->IsValid()); 190 191 MainLoop loop; 192 std::unique_ptr<Socket> accepted_socket_up; 193 auto expected_handles = listen_socket_up->Accept( 194 loop, [&accepted_socket_up, &loop](std::unique_ptr<Socket> sock_up) { 195 accepted_socket_up = std::move(sock_up); 196 loop.RequestTermination(); 197 }); 198 ASSERT_THAT_EXPECTED(expected_handles, llvm::Succeeded()); 199 200 auto connect_socket_up = std::make_unique<TCPSocket>(true); 201 ASSERT_THAT_ERROR( 202 connect_socket_up 203 ->Connect(llvm::formatv("[{0}]:{1}", GetParam().localhost_ip, 204 listen_socket_up->GetLocalPortNumber()) 205 .str()) 206 .ToError(), 207 llvm::Succeeded()); 208 ASSERT_TRUE(connect_socket_up->IsValid()); 209 210 loop.Run(); 211 ASSERT_TRUE(accepted_socket_up); 212 ASSERT_TRUE(accepted_socket_up->IsValid()); 213 } 214 215 TEST_P(SocketTest, TCPGetAddress) { 216 std::unique_ptr<TCPSocket> socket_a_up; 217 std::unique_ptr<TCPSocket> socket_b_up; 218 if (!HostSupportsProtocol()) 219 return; 220 CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, 221 &socket_b_up); 222 223 EXPECT_EQ(socket_a_up->GetLocalPortNumber(), 224 socket_b_up->GetRemotePortNumber()); 225 EXPECT_EQ(socket_b_up->GetLocalPortNumber(), 226 socket_a_up->GetRemotePortNumber()); 227 EXPECT_NE(socket_a_up->GetLocalPortNumber(), 228 socket_b_up->GetLocalPortNumber()); 229 EXPECT_STREQ(GetParam().localhost_ip.c_str(), 230 socket_a_up->GetRemoteIPAddress().c_str()); 231 EXPECT_STREQ(GetParam().localhost_ip.c_str(), 232 socket_b_up->GetRemoteIPAddress().c_str()); 233 } 234 235 TEST_P(SocketTest, UDPConnect) { 236 // UDPSocket::Connect() creates sockets with AF_INET (IPv4). 237 if (!HostSupportsIPv4()) 238 return; 239 llvm::Expected<std::unique_ptr<UDPSocket>> socket = 240 UDPSocket::CreateConnected("127.0.0.1:0"); 241 242 ASSERT_THAT_EXPECTED(socket, llvm::Succeeded()); 243 EXPECT_TRUE(socket.get()->IsValid()); 244 } 245 246 TEST_P(SocketTest, TCPListen0GetPort) { 247 if (!HostSupportsIPv4()) 248 return; 249 llvm::Expected<std::unique_ptr<TCPSocket>> sock = 250 Socket::TcpListen("10.10.12.3:0", 5); 251 ASSERT_THAT_EXPECTED(sock, llvm::Succeeded()); 252 ASSERT_TRUE(sock.get()->IsValid()); 253 EXPECT_NE(sock.get()->GetLocalPortNumber(), 0); 254 } 255 256 TEST_P(SocketTest, TCPListen0GetListeningConnectionURI) { 257 if (!HostSupportsProtocol()) 258 return; 259 260 std::string addr = llvm::formatv("[{0}]:0", GetParam().localhost_ip).str(); 261 llvm::Expected<std::unique_ptr<TCPSocket>> sock = Socket::TcpListen(addr); 262 ASSERT_THAT_EXPECTED(sock, llvm::Succeeded()); 263 ASSERT_TRUE(sock.get()->IsValid()); 264 265 EXPECT_THAT( 266 sock.get()->GetListeningConnectionURI(), 267 testing::ElementsAre(llvm::formatv("connection://[{0}]:{1}", 268 GetParam().localhost_ip, 269 sock->get()->GetLocalPortNumber()) 270 .str())); 271 } 272 273 TEST_F(SocketTest, TCPListen0MultiListenerGetListeningConnectionURI) { 274 if (!HostSupportsLocalhostToIPv4() || !HostSupportsLocalhostToIPv6()) 275 return; 276 277 llvm::Expected<std::unique_ptr<TCPSocket>> sock = 278 Socket::TcpListen("localhost:0", 5); 279 ASSERT_THAT_EXPECTED(sock, llvm::Succeeded()); 280 ASSERT_TRUE(sock.get()->IsValid()); 281 282 EXPECT_THAT(sock.get()->GetListeningConnectionURI(), 283 testing::UnorderedElementsAre( 284 llvm::formatv("connection://[::1]:{0}", 285 sock->get()->GetLocalPortNumber()) 286 .str(), 287 llvm::formatv("connection://[127.0.0.1]:{0}", 288 sock->get()->GetLocalPortNumber()) 289 .str())); 290 } 291 292 TEST_P(SocketTest, TCPGetConnectURI) { 293 std::unique_ptr<TCPSocket> socket_a_up; 294 std::unique_ptr<TCPSocket> socket_b_up; 295 if (!HostSupportsProtocol()) 296 return; 297 CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, 298 &socket_b_up); 299 300 std::string uri(socket_a_up->GetRemoteConnectionURI()); 301 EXPECT_EQ((URI{"connect", GetParam().localhost_ip, 302 socket_a_up->GetRemotePortNumber(), "/"}), 303 URI::Parse(uri)); 304 } 305 306 TEST_P(SocketTest, UDPGetConnectURI) { 307 // UDPSocket::Connect() creates sockets with AF_INET (IPv4). 308 if (!HostSupportsIPv4()) 309 return; 310 llvm::Expected<std::unique_ptr<UDPSocket>> socket = 311 UDPSocket::CreateConnected("127.0.0.1:0"); 312 ASSERT_THAT_EXPECTED(socket, llvm::Succeeded()); 313 314 std::string uri = socket.get()->GetRemoteConnectionURI(); 315 EXPECT_EQ((URI{"udp", "127.0.0.1", 0, "/"}), URI::Parse(uri)); 316 } 317 318 #if LLDB_ENABLE_POSIX 319 TEST_F(SocketTest, DomainGetConnectURI) { 320 llvm::SmallString<64> domain_path; 321 std::error_code EC = llvm::sys::fs::createUniqueDirectory( 322 "DomainListenConnectAccept", domain_path); 323 ASSERT_FALSE(EC); 324 llvm::sys::path::append(domain_path, "test"); 325 326 // Skip the test if the $TMPDIR is too long to hold a domain socket. 327 if (domain_path.size() > 107u) 328 return; 329 330 std::unique_ptr<DomainSocket> socket_a_up; 331 std::unique_ptr<DomainSocket> socket_b_up; 332 CreateDomainConnectedSockets(domain_path, &socket_a_up, &socket_b_up); 333 334 std::string uri(socket_a_up->GetRemoteConnectionURI()); 335 EXPECT_EQ((URI{"unix-connect", "", std::nullopt, domain_path}), 336 URI::Parse(uri)); 337 338 EXPECT_EQ(socket_b_up->GetRemoteConnectionURI(), ""); 339 } 340 #endif 341 342 INSTANTIATE_TEST_SUITE_P( 343 SocketTests, SocketTest, 344 testing::Values(SocketTestParams{/*is_ipv6=*/false, 345 /*localhost_ip=*/"127.0.0.1"}, 346 SocketTestParams{/*is_ipv6=*/true, /*localhost_ip=*/"::1"}), 347 // Prints "SocketTests/SocketTest.TCPGetAddress/ipv4" etc. in test logs. 348 [](const testing::TestParamInfo<SocketTestParams> &info) { 349 return info.param.is_ipv6 ? "ipv6" : "ipv4"; 350 }); 351