Skip to content

[lldb] For a host socket, add a method to print the listening address. #118330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 3, 2024

Conversation

ashgti
Copy link
Contributor

@ashgti ashgti commented Dec 2, 2024

This is most useful if you are listening on an address like 'localhost:0' and want to know the resolved ip + port of the socket listener.

This is most useful if you are listening on an address like 'localhost:0' and want to know the resolved ip + port of the socket listeniner.
@ashgti ashgti assigned labath and unassigned labath Dec 2, 2024
@ashgti ashgti requested a review from labath December 2, 2024 18:07
@ashgti ashgti marked this pull request as ready for review December 2, 2024 18:08
@ashgti ashgti requested a review from JDevlieghere as a code owner December 2, 2024 18:08
@llvmbot llvmbot added the lldb label Dec 2, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 2, 2024

@llvm/pr-subscribers-lldb

Author: John Harrison (ashgti)

Changes

This is most useful if you are listening on an address like 'localhost:0' and want to know the resolved ip + port of the socket listener.


Full diff: https://github.com/llvm/llvm-project/pull/118330.diff

6 Files Affected:

  • (modified) lldb/include/lldb/Host/Socket.h (+3)
  • (modified) lldb/include/lldb/Host/common/TCPSocket.h (+2)
  • (modified) lldb/include/lldb/Host/posix/DomainSocket.h (+2)
  • (modified) lldb/source/Host/common/TCPSocket.cpp (+19-3)
  • (modified) lldb/source/Host/posix/DomainSocket.cpp (+16-1)
  • (modified) lldb/unittests/Host/SocketTest.cpp (+44-7)
diff --git a/lldb/include/lldb/Host/Socket.h b/lldb/include/lldb/Host/Socket.h
index e98797b36c8a5d..c937e0c02ff19e 100644
--- a/lldb/include/lldb/Host/Socket.h
+++ b/lldb/include/lldb/Host/Socket.h
@@ -151,6 +151,9 @@ class Socket : public IOObject {
   // If this Socket is connected then return the URI used to connect.
   virtual std::string GetRemoteConnectionURI() const { return ""; };
 
+  // If the Socket is listening then return the URI for clients to connect.
+  virtual std::string GetListeningConnectionURI() const { return ""; }
+
 protected:
   Socket(SocketProtocol protocol, bool should_close);
 
diff --git a/lldb/include/lldb/Host/common/TCPSocket.h b/lldb/include/lldb/Host/common/TCPSocket.h
index ca36622691fe9a..ab6bf5ab97cae7 100644
--- a/lldb/include/lldb/Host/common/TCPSocket.h
+++ b/lldb/include/lldb/Host/common/TCPSocket.h
@@ -52,6 +52,8 @@ class TCPSocket : public Socket {
 
   std::string GetRemoteConnectionURI() const override;
 
+  std::string GetListeningConnectionURI() const override;
+
 private:
   TCPSocket(NativeSocket socket, const TCPSocket &listen_socket);
 
diff --git a/lldb/include/lldb/Host/posix/DomainSocket.h b/lldb/include/lldb/Host/posix/DomainSocket.h
index d4e0d43ee169c1..d79564cc76dafd 100644
--- a/lldb/include/lldb/Host/posix/DomainSocket.h
+++ b/lldb/include/lldb/Host/posix/DomainSocket.h
@@ -27,6 +27,8 @@ class DomainSocket : public Socket {
 
   std::string GetRemoteConnectionURI() const override;
 
+  std::string GetListeningConnectionURI() const override;
+
 protected:
   DomainSocket(SocketProtocol protocol);
 
diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp
index 5d863954ee8868..b7bd62ff04855e 100644
--- a/lldb/source/Host/common/TCPSocket.cpp
+++ b/lldb/source/Host/common/TCPSocket.cpp
@@ -81,6 +81,12 @@ std::string TCPSocket::GetLocalIPAddress() const {
     socklen_t sock_addr_len = sock_addr.GetMaxLength();
     if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
       return sock_addr.GetIPAddress();
+  } else if (!m_listen_sockets.empty()) {
+    SocketAddress sock_addr;
+    socklen_t sock_addr_len = sock_addr.GetMaxLength();
+    if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
+                      &sock_addr_len) == 0)
+      return sock_addr.GetIPAddress();
   }
   return "";
 }
@@ -115,6 +121,15 @@ std::string TCPSocket::GetRemoteConnectionURI() const {
   return "";
 }
 
+std::string TCPSocket::GetListeningConnectionURI() const {
+  if (!m_listen_sockets.empty()) {
+    return std::string(llvm::formatv(
+        "connection://[{0}]:{1}", GetLocalIPAddress(), GetLocalPortNumber()));
+  }
+
+  return "";
+}
+
 Status TCPSocket::CreateSocket(int domain) {
   Status error;
   if (IsValid())
@@ -176,8 +191,9 @@ Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
 
   if (host_port->hostname == "*")
     host_port->hostname = "0.0.0.0";
-  std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
-      host_port->hostname.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
+  std::vector<SocketAddress> addresses =
+      SocketAddress::GetAddressInfo(host_port->hostname.c_str(), nullptr,
+                                    AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
   for (SocketAddress &address : addresses) {
     int fd =
         Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, error);
@@ -191,7 +207,7 @@ Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
     }
 
     SocketAddress listen_address = address;
-    if(!listen_address.IsLocalhost())
+    if (!listen_address.IsLocalhost())
       listen_address.SetToAnyAddress(address.GetFamily(), host_port->port);
     else
       listen_address.SetPort(host_port->port);
diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp
index 0451834630d33f..beec3c225ecc62 100644
--- a/lldb/source/Host/posix/DomainSocket.cpp
+++ b/lldb/source/Host/posix/DomainSocket.cpp
@@ -86,7 +86,8 @@ Status DomainSocket::Connect(llvm::StringRef name) {
   if (error.Fail())
     return error;
   if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
-        (struct sockaddr *)&saddr_un, saddr_un_len) < 0)
+                                  (struct sockaddr *)&saddr_un,
+                                  saddr_un_len) < 0)
     SetLastError(error);
 
   return error;
@@ -175,3 +176,17 @@ std::string DomainSocket::GetRemoteConnectionURI() const {
       "{0}://{1}",
       GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);
 }
+
+std::string DomainSocket::GetListeningConnectionURI() const {
+  if (m_socket == kInvalidSocketValue)
+    return "";
+
+  struct sockaddr_un addr;
+  bzero(&addr, sizeof(struct sockaddr_un));
+  addr.sun_family = AF_UNIX;
+  socklen_t addr_len = sizeof(struct sockaddr_un);
+  if (::getsockname(m_socket, (struct sockaddr *)&addr, &addr_len) != 0)
+    return "";
+
+  return llvm::formatv("unix-connect://{0}", addr.sun_path);
+}
diff --git a/lldb/unittests/Host/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp
index b20cfe54640285..b69e8874ca01dc 100644
--- a/lldb/unittests/Host/SocketTest.cpp
+++ b/lldb/unittests/Host/SocketTest.cpp
@@ -63,9 +63,8 @@ TEST_P(SocketTest, DecodeHostAndPort) {
   EXPECT_THAT_EXPECTED(Socket::DecodeHostAndPort("*:65535"),
                        llvm::HasValue(Socket::HostAndPort{"*", 65535}));
 
-  EXPECT_THAT_EXPECTED(
-      Socket::DecodeHostAndPort("[::1]:12345"),
-      llvm::HasValue(Socket::HostAndPort{"::1", 12345}));
+  EXPECT_THAT_EXPECTED(Socket::DecodeHostAndPort("[::1]:12345"),
+                       llvm::HasValue(Socket::HostAndPort{"::1", 12345}));
 
   EXPECT_THAT_EXPECTED(
       Socket::DecodeHostAndPort("[abcd:12fg:AF58::1]:12345"),
@@ -75,7 +74,8 @@ TEST_P(SocketTest, DecodeHostAndPort) {
 #if LLDB_ENABLE_POSIX
 TEST_P(SocketTest, DomainListenConnectAccept) {
   llvm::SmallString<64> Path;
-  std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
+  std::error_code EC =
+      llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
   ASSERT_FALSE(EC);
   llvm::sys::path::append(Path, "test");
 
@@ -88,6 +88,27 @@ TEST_P(SocketTest, DomainListenConnectAccept) {
   CreateDomainConnectedSockets(Path, &socket_a_up, &socket_b_up);
 }
 
+TEST_P(SocketTest, DomainListenGetListeningConnectionURI) {
+  llvm::SmallString<64> Path;
+  std::error_code EC =
+      llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
+  ASSERT_FALSE(EC);
+  llvm::sys::path::append(Path, "test");
+
+  // Skip the test if the $TMPDIR is too long to hold a domain socket.
+  if (Path.size() > 107u)
+    return;
+
+  auto listen_socket_up = std::make_unique<DomainSocket>(
+      /*should_close=*/true);
+  Status error = listen_socket_up->Listen(Path, 5);
+  ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
+  ASSERT_TRUE(listen_socket_up->IsValid());
+
+  ASSERT_EQ(listen_socket_up->GetListeningConnectionURI(),
+            llvm::formatv("unix-connect://{0}", Path).str());
+}
+
 TEST_P(SocketTest, DomainMainLoopAccept) {
   llvm::SmallString<64> Path;
   std::error_code EC =
@@ -225,12 +246,28 @@ TEST_P(SocketTest, TCPListen0GetPort) {
   if (!HostSupportsIPv4())
     return;
   llvm::Expected<std::unique_ptr<TCPSocket>> sock =
-      Socket::TcpListen("10.10.12.3:0", false);
+      Socket::TcpListen("10.10.12.3:0", 5);
   ASSERT_THAT_EXPECTED(sock, llvm::Succeeded());
   ASSERT_TRUE(sock.get()->IsValid());
   EXPECT_NE(sock.get()->GetLocalPortNumber(), 0);
 }
 
+TEST_P(SocketTest, TCPListen0GetListeningConnectionURI) {
+  std::string addr = llvm::formatv("[{0}]:0", GetParam().localhost_ip).str();
+  llvm::Expected<std::unique_ptr<TCPSocket>> sock = Socket::TcpListen(addr);
+  ASSERT_THAT_EXPECTED(sock, llvm::Succeeded());
+  ASSERT_TRUE(sock.get()->IsValid());
+  std::string uri = sock.get()->GetListeningConnectionURI();
+
+  // Ensure the URI is not "".
+  EXPECT_FALSE(uri.empty());
+  EXPECT_NE(uri, addr);
+  EXPECT_EQ(uri,
+            llvm::formatv("connection://[{0}]:{1}", GetParam().localhost_ip,
+                          sock->get()->GetLocalPortNumber())
+                .str());
+}
+
 TEST_P(SocketTest, TCPGetConnectURI) {
   std::unique_ptr<TCPSocket> socket_a_up;
   std::unique_ptr<TCPSocket> socket_b_up;
@@ -260,8 +297,8 @@ TEST_P(SocketTest, UDPGetConnectURI) {
 #if LLDB_ENABLE_POSIX
 TEST_P(SocketTest, DomainGetConnectURI) {
   llvm::SmallString<64> domain_path;
-  std::error_code EC =
-      llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", domain_path);
+  std::error_code EC = llvm::sys::fs::createUniqueDirectory(
+      "DomainListenConnectAccept", domain_path);
   ASSERT_FALSE(EC);
   llvm::sys::path::append(domain_path, "test");
 

Copy link

github-actions bot commented Dec 3, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Collaborator

@labath labath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Thanks.

@ashgti ashgti merged commit 3845624 into llvm:main Dec 3, 2024
7 checks passed
@ashgti ashgti deleted the lldb-hosts branch December 3, 2024 19:18
qiaojbao pushed a commit to GPUOpen-Drivers/llvm-project that referenced this pull request Dec 23, 2024
Local branch amd-gfx 401ed9d Merged main:95a4d30b0d64 into amd-gfx:e579a32bca2b
Remote branch main 3845624 [lldb] For a host socket, add a method to print the listening address. (llvm#118330)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants