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 Predicate<uint16_t> port_predicate; 158 port_predicate.SetValue(0, eBroadcastNever); 159 llvm::Expected<std::unique_ptr<TCPSocket>> sock = 160 Socket::TcpListen("10.10.12.3:0", false, &port_predicate); 161 ASSERT_THAT_EXPECTED(sock, llvm::Succeeded()); 162 ASSERT_TRUE(sock.get()->IsValid()); 163 EXPECT_NE(sock.get()->GetLocalPortNumber(), 0); 164 } 165 166 TEST_P(SocketTest, TCPGetConnectURI) { 167 std::unique_ptr<TCPSocket> socket_a_up; 168 std::unique_ptr<TCPSocket> socket_b_up; 169 if (!HostSupportsProtocol()) 170 return; 171 CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, 172 &socket_b_up); 173 174 llvm::StringRef scheme; 175 llvm::StringRef hostname; 176 int port; 177 llvm::StringRef path; 178 std::string uri(socket_a_up->GetRemoteConnectionURI()); 179 EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path)); 180 EXPECT_EQ(scheme, "connect"); 181 EXPECT_EQ(port, socket_a_up->GetRemotePortNumber()); 182 } 183 184 TEST_P(SocketTest, UDPGetConnectURI) { 185 // UDPSocket::Connect() creates sockets with AF_INET (IPv4). 186 if (!HostSupportsIPv4()) 187 return; 188 llvm::Expected<std::unique_ptr<UDPSocket>> socket = 189 UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false); 190 ASSERT_THAT_EXPECTED(socket, llvm::Succeeded()); 191 192 llvm::StringRef scheme; 193 llvm::StringRef hostname; 194 int port; 195 llvm::StringRef path; 196 std::string uri = socket.get()->GetRemoteConnectionURI(); 197 EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path)); 198 EXPECT_EQ(scheme, "udp"); 199 } 200 201 #if LLDB_ENABLE_POSIX 202 TEST_P(SocketTest, DomainGetConnectURI) { 203 llvm::SmallString<64> domain_path; 204 std::error_code EC = 205 llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", domain_path); 206 ASSERT_FALSE(EC); 207 llvm::sys::path::append(domain_path, "test"); 208 209 // Skip the test if the $TMPDIR is too long to hold a domain socket. 210 if (domain_path.size() > 107u) 211 return; 212 213 std::unique_ptr<DomainSocket> socket_a_up; 214 std::unique_ptr<DomainSocket> socket_b_up; 215 CreateDomainConnectedSockets(domain_path, &socket_a_up, &socket_b_up); 216 217 llvm::StringRef scheme; 218 llvm::StringRef hostname; 219 int port; 220 llvm::StringRef path; 221 std::string uri(socket_a_up->GetRemoteConnectionURI()); 222 EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path)); 223 EXPECT_EQ(scheme, "unix-connect"); 224 EXPECT_EQ(path, domain_path); 225 226 EXPECT_EQ(socket_b_up->GetRemoteConnectionURI(), ""); 227 } 228 #endif 229 230 INSTANTIATE_TEST_SUITE_P( 231 SocketTests, SocketTest, 232 testing::Values(SocketTestParams{/*is_ipv6=*/false, 233 /*localhost_ip=*/"127.0.0.1"}, 234 SocketTestParams{/*is_ipv6=*/true, /*localhost_ip=*/"::1"}), 235 // Prints "SocketTests/SocketTest.DecodeHostAndPort/ipv4" etc. in test logs. 236 [](const testing::TestParamInfo<SocketTestParams> &info) { 237 return info.param.is_ipv6 ? "ipv6" : "ipv4"; 238 }); 239