diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -764,7 +764,7 @@ m_write_sp.reset(socket); m_read_sp = m_write_sp; StreamString strm; - strm.Printf("connect://%s:%u", tcp_socket->GetRemoteIPAddress().c_str(), + strm.Printf("connect://[%s]:%u", tcp_socket->GetRemoteIPAddress().c_str(), tcp_socket->GetRemotePortNumber()); m_uri = strm.GetString(); } diff --git a/lldb/unittests/Host/CMakeLists.txt b/lldb/unittests/Host/CMakeLists.txt --- a/lldb/unittests/Host/CMakeLists.txt +++ b/lldb/unittests/Host/CMakeLists.txt @@ -9,6 +9,8 @@ SocketAddressTest.cpp SocketTest.cpp TaskPoolTest.cpp + SocketBasedTest.cpp + ConnectionFileDescriptorTest.cpp ) if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android") diff --git a/lldb/unittests/Host/ConnectionFileDescriptorTest.cpp b/lldb/unittests/Host/ConnectionFileDescriptorTest.cpp new file mode 100644 --- /dev/null +++ b/lldb/unittests/Host/ConnectionFileDescriptorTest.cpp @@ -0,0 +1,51 @@ +//===-- ConnectionFileDescriptorTest.cpp ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SocketBasedTest.h" +#include "gtest/gtest.h" + +#include "lldb/Utility/UriParser.h" +#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" + +using namespace lldb_private; + +class ConnectionFileDescriptorTest : public SocketBasedTest { +public: + void SetUp() override { + ASSERT_THAT_ERROR(Socket::Initialize(), llvm::Succeeded()); + } + + void TearDown() override { Socket::Terminate(); } + + void TestGetURI(std::string ip) { + std::unique_ptr socket_a_up; + std::unique_ptr socket_b_up; + if (!CreateTCPConnectedSockets(ip, &socket_a_up, &socket_b_up)) { + // Skip this test if the host doesn't support this interface. + return; + } + auto socket = socket_a_up.release(); + ConnectionFileDescriptor connection_file_descriptor(socket); + + llvm::StringRef scheme; + llvm::StringRef hostname; + int port; + llvm::StringRef path; + EXPECT_TRUE(UriParser::Parse(connection_file_descriptor.GetURI(), scheme, hostname, port, path)); + EXPECT_STREQ(ip.c_str(), hostname.str().c_str()); + EXPECT_EQ(socket->GetRemotePortNumber(), port); + } +}; + +TEST_F(ConnectionFileDescriptorTest, TCPGetURIv4) { + TestGetURI("127.0.0.1"); +} + +TEST_F(ConnectionFileDescriptorTest, TCPGetURIv6) { + TestGetURI("::1"); +} \ No newline at end of file diff --git a/lldb/unittests/Host/SocketBasedTest.h b/lldb/unittests/Host/SocketBasedTest.h new file mode 100644 --- /dev/null +++ b/lldb/unittests/Host/SocketBasedTest.h @@ -0,0 +1,56 @@ +//===--------------------- SocketBasedTest.h --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_UNITTESTS_HOST_SOCKETTESTUTILITIES_H +#define LLDB_UNITTESTS_HOST_SOCKETTESTUTILITIES_H + +#include +#include +#include + +#include "lldb/Host/Config.h" +#include "lldb/Host/Socket.h" +#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/common/UDPSocket.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Testing/Support/Error.h" + +#ifndef LLDB_DISABLE_POSIX +#include "lldb/Host/posix/DomainSocket.h" +#endif + +using namespace lldb_private; + +class SocketBasedTest : public testing::Test { +public: + void SetUp() override { + ASSERT_THAT_ERROR(Socket::Initialize(), llvm::Succeeded()); + } + + void TearDown() override { Socket::Terminate(); } + + static void AcceptThread(Socket *listen_socket, bool child_processes_inherit, + Socket **accept_socket, Status *error); + + template + void CreateConnectedSockets( + llvm::StringRef listen_remote_address, + const std::function &get_connect_addr, + std::unique_ptr *a_up, std::unique_ptr *b_up); + bool CreateTCPConnectedSockets(std::string listen_remote_ip, + std::unique_ptr *a_up, + std::unique_ptr *b_up); +#ifndef LLDB_DISABLE_POSIX + void CreateDomainConnectedSockets(llvm::StringRef path, + std::unique_ptr *a_up, + std::unique_ptr *b_up); +#endif +}; + +#endif \ No newline at end of file diff --git a/lldb/unittests/Host/SocketBasedTest.cpp b/lldb/unittests/Host/SocketBasedTest.cpp new file mode 100644 --- /dev/null +++ b/lldb/unittests/Host/SocketBasedTest.cpp @@ -0,0 +1,92 @@ +//===--------------------- SocketBasedTest.cpp ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SocketBasedTest.h" +#include "lldb/Utility/StreamString.h" + +void SocketBasedTest::AcceptThread(Socket *listen_socket, + bool child_processes_inherit, + Socket **accept_socket, Status *error) { + *error = listen_socket->Accept(*accept_socket); +} + +template +void SocketBasedTest::CreateConnectedSockets( + llvm::StringRef listen_remote_address, + const std::function &get_connect_addr, + std::unique_ptr *a_up, std::unique_ptr *b_up) { + bool child_processes_inherit = false; + Status error; + std::unique_ptr listen_socket_up( + new SocketType(true, child_processes_inherit)); + EXPECT_FALSE(error.Fail()); + error = listen_socket_up->Listen(listen_remote_address, 5); + EXPECT_FALSE(error.Fail()); + EXPECT_TRUE(listen_socket_up->IsValid()); + + Status accept_error; + Socket *accept_socket; + std::thread accept_thread(AcceptThread, listen_socket_up.get(), + child_processes_inherit, &accept_socket, + &accept_error); + + std::string connect_remote_address = get_connect_addr(*listen_socket_up); + std::unique_ptr connect_socket_up( + new SocketType(true, child_processes_inherit)); + EXPECT_FALSE(error.Fail()); + error = connect_socket_up->Connect(connect_remote_address); + EXPECT_FALSE(error.Fail()); + EXPECT_TRUE(connect_socket_up->IsValid()); + + a_up->swap(connect_socket_up); + EXPECT_TRUE(error.Success()); + EXPECT_NE(nullptr, a_up->get()); + EXPECT_TRUE((*a_up)->IsValid()); + + accept_thread.join(); + b_up->reset(static_cast(accept_socket)); + EXPECT_TRUE(accept_error.Success()); + EXPECT_NE(nullptr, b_up->get()); + EXPECT_TRUE((*b_up)->IsValid()); + + listen_socket_up.reset(); +} + +bool SocketBasedTest::CreateTCPConnectedSockets( + std::string listen_remote_ip, std::unique_ptr *socket_a_up, + std::unique_ptr *socket_b_up) { + // Return false if the host doesn't support this interface. + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + listen_remote_ip.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + if (addresses.size() == 0) { + return false; + } + + StreamString strm; + strm.Printf("[%s]:0", listen_remote_ip.c_str()); + CreateConnectedSockets( + strm.GetString(), + [=](const TCPSocket &s) { + char connect_remote_address[64]; + snprintf(connect_remote_address, sizeof(connect_remote_address), + "[%s]:%u", listen_remote_ip.c_str(), s.GetLocalPortNumber()); + return std::string(connect_remote_address); + }, + socket_a_up, socket_b_up); + return true; +} + +#ifndef LLDB_DISABLE_POSIX +void SocketBasedTest::CreateDomainConnectedSockets( + llvm::StringRef path, std::unique_ptr *socket_a_up, + std::unique_ptr *socket_b_up) { + return CreateConnectedSockets( + path, [=](const DomainSocket &) { return path.str(); }, socket_a_up, + socket_b_up); +} +#endif diff --git a/lldb/unittests/Host/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp --- a/lldb/unittests/Host/SocketTest.cpp +++ b/lldb/unittests/Host/SocketTest.cpp @@ -6,82 +6,18 @@ // //===----------------------------------------------------------------------===// -#include -#include -#include - +#include "SocketBasedTest.h" #include "gtest/gtest.h" -#include "lldb/Host/Config.h" -#include "lldb/Host/Socket.h" -#include "lldb/Host/common/TCPSocket.h" -#include "lldb/Host/common/UDPSocket.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Testing/Support/Error.h" - -#ifndef LLDB_DISABLE_POSIX -#include "lldb/Host/posix/DomainSocket.h" -#endif - using namespace lldb_private; -class SocketTest : public testing::Test { +class SocketTest : public SocketBasedTest { public: void SetUp() override { ASSERT_THAT_ERROR(Socket::Initialize(), llvm::Succeeded()); } void TearDown() override { Socket::Terminate(); } - -protected: - static void AcceptThread(Socket *listen_socket, - bool child_processes_inherit, Socket **accept_socket, - Status *error) { - *error = listen_socket->Accept(*accept_socket); - } - - template - void CreateConnectedSockets( - llvm::StringRef listen_remote_address, - const std::function &get_connect_addr, - std::unique_ptr *a_up, std::unique_ptr *b_up) { - bool child_processes_inherit = false; - Status error; - std::unique_ptr listen_socket_up( - new SocketType(true, child_processes_inherit)); - EXPECT_FALSE(error.Fail()); - error = listen_socket_up->Listen(listen_remote_address, 5); - EXPECT_FALSE(error.Fail()); - EXPECT_TRUE(listen_socket_up->IsValid()); - - Status accept_error; - Socket *accept_socket; - std::thread accept_thread(AcceptThread, listen_socket_up.get(), - child_processes_inherit, &accept_socket, - &accept_error); - - std::string connect_remote_address = get_connect_addr(*listen_socket_up); - std::unique_ptr connect_socket_up( - new SocketType(true, child_processes_inherit)); - EXPECT_FALSE(error.Fail()); - error = connect_socket_up->Connect(connect_remote_address); - EXPECT_FALSE(error.Fail()); - EXPECT_TRUE(connect_socket_up->IsValid()); - - a_up->swap(connect_socket_up); - EXPECT_TRUE(error.Success()); - EXPECT_NE(nullptr, a_up->get()); - EXPECT_TRUE((*a_up)->IsValid()); - - accept_thread.join(); - b_up->reset(static_cast(accept_socket)); - EXPECT_TRUE(accept_error.Success()); - EXPECT_NE(nullptr, b_up->get()); - EXPECT_TRUE((*b_up)->IsValid()); - - listen_socket_up.reset(); - } }; TEST_F(SocketTest, DecodeHostAndPort) { @@ -159,38 +95,23 @@ std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - CreateConnectedSockets( - Path, [=](const DomainSocket &) { return Path.str().str(); }, - &socket_a_up, &socket_b_up); + CreateDomainConnectedSockets(Path, &socket_a_up, &socket_b_up); } #endif TEST_F(SocketTest, TCPListen0ConnectAccept) { std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - CreateConnectedSockets( - "127.0.0.1:0", - [=](const TCPSocket &s) { - char connect_remote_address[64]; - snprintf(connect_remote_address, sizeof(connect_remote_address), - "127.0.0.1:%u", s.GetLocalPortNumber()); - return std::string(connect_remote_address); - }, - &socket_a_up, &socket_b_up); + CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); } TEST_F(SocketTest, TCPGetAddress) { std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - CreateConnectedSockets( - "127.0.0.1:0", - [=](const TCPSocket &s) { - char connect_remote_address[64]; - snprintf(connect_remote_address, sizeof(connect_remote_address), - "127.0.0.1:%u", s.GetLocalPortNumber()); - return std::string(connect_remote_address); - }, - &socket_a_up, &socket_b_up); + if (!CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up)) { + // Skip this test if the host doesn't support this interface + return; + } EXPECT_EQ(socket_a_up->GetLocalPortNumber(), socket_b_up->GetRemotePortNumber());