diff --git a/lldb/include/lldb/Host/Socket.h b/lldb/include/lldb/Host/Socket.h --- a/lldb/include/lldb/Host/Socket.h +++ b/lldb/include/lldb/Host/Socket.h @@ -102,6 +102,9 @@ std::string &host_str, std::string &port_str, int32_t &port, Status *error_ptr); + // If this Socket is connected then return the URI used to connect. + virtual std::string GetRemoteConnectionURI() const { return ""; }; + protected: Socket(SocketProtocol protocol, bool should_close, bool m_child_process_inherit); diff --git a/lldb/include/lldb/Host/common/TCPSocket.h b/lldb/include/lldb/Host/common/TCPSocket.h --- a/lldb/include/lldb/Host/common/TCPSocket.h +++ b/lldb/include/lldb/Host/common/TCPSocket.h @@ -46,6 +46,8 @@ bool IsValid() const override; + std::string GetRemoteConnectionURI() const override; + private: TCPSocket(NativeSocket socket, const TCPSocket &listen_socket); diff --git a/lldb/include/lldb/Host/common/UDPSocket.h b/lldb/include/lldb/Host/common/UDPSocket.h --- a/lldb/include/lldb/Host/common/UDPSocket.h +++ b/lldb/include/lldb/Host/common/UDPSocket.h @@ -19,6 +19,8 @@ static Status Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket); + std::string GetRemoteConnectionURI() const override; + private: UDPSocket(NativeSocket socket); diff --git a/lldb/include/lldb/Host/posix/DomainSocket.h b/lldb/include/lldb/Host/posix/DomainSocket.h --- a/lldb/include/lldb/Host/posix/DomainSocket.h +++ b/lldb/include/lldb/Host/posix/DomainSocket.h @@ -20,11 +20,14 @@ Status Listen(llvm::StringRef name, int backlog) override; Status Accept(Socket *&socket) override; + std::string GetRemoteConnectionURI() const override; + protected: DomainSocket(SocketProtocol protocol, bool child_processes_inherit); virtual size_t GetNameOffset() const; virtual void DeleteSocketFile(llvm::StringRef name); + std::string GetSocketName() const; private: DomainSocket(NativeSocket socket, const DomainSocket &listen_socket); diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp --- a/lldb/source/Host/common/TCPSocket.cpp +++ b/lldb/source/Host/common/TCPSocket.cpp @@ -118,6 +118,14 @@ return ""; } +std::string TCPSocket::GetRemoteConnectionURI() const { + if (m_socket != kInvalidSocketValue) { + return llvm::formatv("connect://[{0}]:{1}", GetRemoteIPAddress(), + GetRemotePortNumber()); + } + return ""; +}; + Status TCPSocket::CreateSocket(int domain) { Status error; if (IsValid()) diff --git a/lldb/source/Host/common/UDPSocket.cpp b/lldb/source/Host/common/UDPSocket.cpp --- a/lldb/source/Host/common/UDPSocket.cpp +++ b/lldb/source/Host/common/UDPSocket.cpp @@ -134,3 +134,11 @@ error.Clear(); return error; } + +std::string UDPSocket::GetRemoteConnectionURI() const { + if (m_socket != kInvalidSocketValue) { + return llvm::formatv("udp://[{0}]:{1}", m_sockaddr.GetIPAddress(), + m_sockaddr.GetPort()); + } + return ""; +} 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 @@ -758,13 +758,7 @@ } void ConnectionFileDescriptor::InitializeSocket(Socket *socket) { - assert(socket->GetSocketProtocol() == Socket::ProtocolTcp); - TCPSocket *tcp_socket = static_cast(socket); - m_write_sp.reset(socket); m_read_sp = m_write_sp; - StreamString strm; - strm.Printf("connect://%s:%u", tcp_socket->GetRemoteIPAddress().c_str(), - tcp_socket->GetRemotePortNumber()); - m_uri = strm.GetString(); + m_uri = socket->GetRemoteConnectionURI(); } diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp.rej b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp.rej new file mode 100644 --- /dev/null +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp.rej @@ -0,0 +1,23 @@ +*************** +*** 758,770 **** + } + + void ConnectionFileDescriptor::InitializeSocket(Socket *socket) { +- assert(socket->GetSocketProtocol() == Socket::ProtocolTcp); +- TCPSocket *tcp_socket = static_cast(socket); +- + m_write_sp.reset(socket); + m_read_sp = m_write_sp; +- StreamString strm; +- strm.Printf("connect://[%s]:%u", tcp_socket->GetRemoteIPAddress().c_str(), +- tcp_socket->GetRemotePortNumber()); +- m_uri = strm.GetString(); + } +--- 758,764 ---- + } + + void ConnectionFileDescriptor::InitializeSocket(Socket *socket) { + m_write_sp.reset(socket); + m_read_sp = m_write_sp; ++ m_uri = socket->GetConnectURI(); + } diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -125,3 +125,28 @@ void DomainSocket::DeleteSocketFile(llvm::StringRef name) { llvm::sys::fs::remove(name); } + +std::string DomainSocket::GetSocketName() const { + if (m_socket != kInvalidSocketValue) { + struct sockaddr_un saddr_un; + saddr_un.sun_family = AF_UNIX; + socklen_t sock_addr_len = sizeof(struct sockaddr_un); + if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) == + 0) + return std::string(saddr_un.sun_path + GetNameOffset(), + sock_addr_len - + offsetof(struct sockaddr_un, sun_path) - + GetNameOffset()); + } + return ""; +} + +std::string DomainSocket::GetRemoteConnectionURI() const { + if (m_socket != kInvalidSocketValue) { + return llvm::formatv("{0}://{1}", + GetNameOffset() == 0 ? "unix-connect" + : "unix-abstract-connect", + GetSocketName()); + } + return ""; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -115,25 +115,24 @@ this, std::placeholders::_1), false); - llvm::StringRef platform_scheme; - llvm::StringRef platform_ip; - int platform_port; - llvm::StringRef platform_path; - std::string platform_uri = GetConnection()->GetURI(); - bool ok = UriParser::Parse(platform_uri, platform_scheme, platform_ip, - platform_port, platform_path); - UNUSED_IF_ASSERT_DISABLED(ok); - assert(ok); - std::ostringstream url; // debugserver does not accept the URL scheme prefix. #if !defined(__APPLE__) url << m_socket_scheme << "://"; #endif uint16_t *port_ptr = &port; - if (m_socket_protocol == Socket::ProtocolTcp) + if (m_socket_protocol == Socket::ProtocolTcp) { + llvm::StringRef platform_scheme; + llvm::StringRef platform_ip; + int platform_port; + llvm::StringRef platform_path; + std::string platform_uri = GetConnection()->GetURI(); + bool ok = UriParser::Parse(platform_uri, platform_scheme, platform_ip, + platform_port, platform_path); + UNUSED_IF_ASSERT_DISABLED(ok); + assert(ok); url << platform_ip.str() << ":" << port; - else { + } else { socket_name = GetDomainSocketPath("gdbserver").GetPath(); url << socket_name; port_ptr = nullptr; 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 + SocketTestUtilities.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,49 @@ +//===-- 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 "SocketTestUtilities.h" +#include "gtest/gtest.h" + +#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" +#include "lldb/Utility/UriParser.h" + +using namespace lldb_private; + +class ConnectionFileDescriptorTest : public testing::Test { +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 (!IsAddressFamilySupported(ip)) { + GTEST_LOG_(WARNING) << "Skipping test due to missing IPv" + << (IsIPv4(ip) ? "4" : "6") << " support."; + return; + } + CreateTCPConnectedSockets(ip, &socket_a_up, &socket_b_up); + auto socket = socket_a_up.release(); + ConnectionFileDescriptor connection_file_descriptor(socket); + + llvm::StringRef scheme; + llvm::StringRef hostname; + int port; + llvm::StringRef path; + std::string uri(connection_file_descriptor.GetURI()); + EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path)); + EXPECT_EQ(ip, hostname); + 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/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp --- a/lldb/unittests/Host/SocketTest.cpp +++ b/lldb/unittests/Host/SocketTest.cpp @@ -6,24 +6,10 @@ // //===----------------------------------------------------------------------===// -#include -#include -#include - +#include "SocketTestUtilities.h" +#include "lldb/Utility/UriParser.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 { @@ -33,55 +19,6 @@ } 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 +96,24 @@ 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 (!IsAddressFamilySupported("127.0.0.1")) { + GTEST_LOG_(WARNING) << "Skipping test due to missing IPv4 support."; + return; + } + CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); EXPECT_EQ(socket_a_up->GetLocalPortNumber(), socket_b_up->GetRemotePortNumber()); @@ -225,3 +148,67 @@ EXPECT_TRUE(socket_up->IsValid()); EXPECT_NE(socket_up->GetLocalPortNumber(), 0); } + +TEST_F(SocketTest, TCPGetRemoteConnectionURI) { + std::unique_ptr socket_a_up; + std::unique_ptr socket_b_up; + if (!IsAddressFamilySupported("127.0.0.1")) { + GTEST_LOG_(WARNING) << "Skipping test due to missing IPv4 support."; + return; + } + CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); + + llvm::StringRef scheme; + llvm::StringRef hostname; + int port; + llvm::StringRef path; + std::string uri(socket_a_up->GetRemoteConnectionURI()); + EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path)); + EXPECT_EQ(scheme, "connect"); + EXPECT_EQ(port, socket_a_up->GetRemotePortNumber()); +} + +TEST_F(SocketTest, UDPGetRemoteConnectionURI) { + std::unique_ptr socket_a_up; + std::unique_ptr socket_b_up; + if (!IsAddressFamilySupported("127.0.0.1")) { + GTEST_LOG_(WARNING) << "Skipping test due to missing IPv4 support."; + return; + } + Socket *socket; + + bool child_processes_inherit = false; + auto error = + UDPSocket::Connect("127.0.0.1:0", child_processes_inherit, socket); + + llvm::StringRef scheme; + llvm::StringRef hostname; + int port; + llvm::StringRef path; + std::string uri(socket->GetRemoteConnectionURI()); + EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path)); + EXPECT_EQ(scheme, "udp"); +} + +#ifndef LLDB_DISABLE_POSIX +TEST_F(SocketTest, DomainGetRemoteConnectionURI) { + llvm::SmallString<64> domain_path; + std::error_code EC = llvm::sys::fs::createUniqueDirectory( + "DomainListenConnectAccept", domain_path); + ASSERT_FALSE(EC); + llvm::sys::path::append(domain_path, "test"); + + std::unique_ptr socket_a_up; + std::unique_ptr socket_b_up; + CreateDomainConnectedSockets(domain_path, &socket_a_up, &socket_b_up); + + llvm::StringRef scheme; + llvm::StringRef hostname; + int port; + llvm::StringRef path; + std::string uri(socket_a_up->GetRemoteConnectionURI()); + EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path)); + EXPECT_EQ(scheme, "unix-connect"); + EXPECT_EQ(path, domain_path); +} +#endif \ No newline at end of file diff --git a/lldb/unittests/Host/SocketTest.cpp.rej b/lldb/unittests/Host/SocketTest.cpp.rej new file mode 100644 --- /dev/null +++ b/lldb/unittests/Host/SocketTest.cpp.rej @@ -0,0 +1,16 @@ +*************** +*** 7,12 **** + //===----------------------------------------------------------------------===// + + #include "SocketTestUtilities.h" + #include "gtest/gtest.h" + + using namespace lldb_private; +--- 7,13 ---- + //===----------------------------------------------------------------------===// + + #include "SocketTestUtilities.h" ++ #include "lldb/Utility/UriParser.h" + #include "gtest/gtest.h" + + using namespace lldb_private; diff --git a/lldb/unittests/Host/SocketTestUtilities.h b/lldb/unittests/Host/SocketTestUtilities.h new file mode 100644 --- /dev/null +++ b/lldb/unittests/Host/SocketTestUtilities.h @@ -0,0 +1,47 @@ +//===--------------------- SocketTestUtilities.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 + +namespace lldb_private { +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 + +bool IsAddressFamilySupported(std::string ip); +bool IsIPv4(std::string ip); +} // namespace lldb_private + +#endif \ No newline at end of file diff --git a/lldb/unittests/Host/SocketTestUtilities.cpp b/lldb/unittests/Host/SocketTestUtilities.cpp new file mode 100644 --- /dev/null +++ b/lldb/unittests/Host/SocketTestUtilities.cpp @@ -0,0 +1,104 @@ +//===----------------- SocketTestUtilities.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 "SocketTestUtilities.h" +#include "lldb/Utility/StreamString.h" + +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +using namespace lldb_private; + +static void AcceptThread(Socket *listen_socket, bool child_processes_inherit, + Socket **accept_socket, Status *error) { + *error = listen_socket->Accept(*accept_socket); +} + +template +void lldb_private::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 lldb_private::CreateTCPConnectedSockets( + std::string listen_remote_ip, std::unique_ptr *socket_a_up, + std::unique_ptr *socket_b_up) { + 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 lldb_private::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 + +bool lldb_private::IsAddressFamilySupported(std::string ip) { + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + ip.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + return addresses.size() > 0; +} + +bool lldb_private::IsIPv4(std::string ip) { + struct sockaddr_in sock_addr; + return inet_pton(AF_INET, ip.c_str(), &(sock_addr.sin_addr)) != 0; +}