Make ConnectionFileDescription work with all sockets

Summary:
My main goal here is to make lldb-server work with Android Studio.

This is currently not the case because lldb-server is started in platform mode listening on a domain socket. When Android Studio connects to it lldb-server crashes because even though it's listening on a domain socket as soon as it gets a connection it asserts that it's a TCP connection, which will obviously fails for any non-tcp connection.

To do this I came up with a new method called GetConnectURI() in Socket that returns the URI needed to connect to the connected portion of the socket.

Reviewers: labath, clayborg, xiaobai

Reviewed By: labath

Subscribers: mgorny, jfb, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D62089

llvm-svn: 362173
This commit is contained in:
Antonio Afonso 2019-05-30 23:30:35 +00:00
parent 375dec5e45
commit d556095135
10 changed files with 125 additions and 19 deletions

View File

@ -102,6 +102,9 @@ public:
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);

View File

@ -46,6 +46,8 @@ public:
bool IsValid() const override;
std::string GetRemoteConnectionURI() const override;
private:
TCPSocket(NativeSocket socket, const TCPSocket &listen_socket);

View File

@ -19,6 +19,8 @@ public:
static Status Connect(llvm::StringRef name, bool child_processes_inherit,
Socket *&socket);
std::string GetRemoteConnectionURI() const override;
private:
UDPSocket(NativeSocket socket);

View File

@ -20,11 +20,14 @@ public:
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);

View File

@ -118,6 +118,14 @@ std::string TCPSocket::GetRemoteIPAddress() const {
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())

View File

@ -134,3 +134,11 @@ Status UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit,
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 "";
}

View File

@ -758,13 +758,7 @@ void ConnectionFileDescriptor::SetChildProcessesInherit(
}
void ConnectionFileDescriptor::InitializeSocket(Socket *socket) {
assert(socket->GetSocketProtocol() == Socket::ProtocolTcp);
TCPSocket *tcp_socket = static_cast<TCPSocket *>(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();
}

View File

@ -125,3 +125,28 @@ size_t DomainSocket::GetNameOffset() const { return 0; }
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 "";
}

View File

@ -115,25 +115,24 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
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;

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "SocketTestUtilities.h"
#include "lldb/Utility/UriParser.h"
#include "gtest/gtest.h"
using namespace lldb_private;
@ -147,3 +148,64 @@ TEST_F(SocketTest, TCPListen0GetPort) {
EXPECT_TRUE(socket_up->IsValid());
EXPECT_NE(socket_up->GetLocalPortNumber(), 0);
}
TEST_F(SocketTest, TCPGetConnectURI) {
std::unique_ptr<TCPSocket> socket_a_up;
std::unique_ptr<TCPSocket> 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, UDPGetConnectURI) {
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, DomainGetConnectURI) {
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<DomainSocket> socket_a_up;
std::unique_ptr<DomainSocket> 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