rupprecht updated this revision to Diff 291956.
rupprecht marked an inline comment as done.
rupprecht added a comment.

- Compare directly against the error code instead of hopping through 
`std::make_error_code()`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87333/new/

https://reviews.llvm.org/D87333

Files:
  lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
  lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
  lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py
  lldb/tools/lldb-server/lldb-gdbserver.cpp
  lldb/unittests/Host/SocketTest.cpp
  lldb/unittests/Host/SocketTestUtilities.cpp

Index: lldb/unittests/Host/SocketTestUtilities.cpp
===================================================================
--- lldb/unittests/Host/SocketTestUtilities.cpp
+++ lldb/unittests/Host/SocketTestUtilities.cpp
@@ -101,13 +101,14 @@
                              "Creating a canary {0} TCP socket failed: {1}.",
                              Proto, Err)
                              .str();
-  bool HasAddrNotAvail = false;
+  bool HasProtocolError = false;
   handleAllErrors(std::move(Err), [&](std::unique_ptr<llvm::ECError> ECErr) {
-    if (ECErr->convertToErrorCode() ==
-        std::make_error_code(std::errc::address_not_available))
-      HasAddrNotAvail = true;
+    std::error_code ec = ECErr->convertToErrorCode();
+    if (ec == std::make_error_code(std::errc::address_family_not_supported) ||
+        ec == std::make_error_code(std::errc::address_not_available))
+      HasProtocolError = true;
   });
-  if (HasAddrNotAvail) {
+  if (HasProtocolError) {
     GTEST_LOG_(WARNING)
         << llvm::formatv(
                "Assuming the host does not support {0}. Skipping test.", Proto)
Index: lldb/unittests/Host/SocketTest.cpp
===================================================================
--- lldb/unittests/Host/SocketTest.cpp
+++ lldb/unittests/Host/SocketTest.cpp
@@ -14,12 +14,24 @@
 
 using namespace lldb_private;
 
-class SocketTest : public testing::Test {
+struct SocketTestParams {
+  bool is_ipv6;
+  std::string localhost_ip;
+};
+
+class SocketTest : public testing::TestWithParam<SocketTestParams> {
 public:
   SubsystemRAII<Socket> subsystems;
+
+protected:
+  bool HostSupportsProtocol() const {
+    if (GetParam().is_ipv6)
+      return HostSupportsIPv6();
+    return HostSupportsIPv4();
+  }
 };
 
-TEST_F(SocketTest, DecodeHostAndPort) {
+TEST_P(SocketTest, DecodeHostAndPort) {
   std::string host_str;
   std::string port_str;
   int32_t port;
@@ -86,7 +98,7 @@
 }
 
 #if LLDB_ENABLE_POSIX
-TEST_F(SocketTest, DomainListenConnectAccept) {
+TEST_P(SocketTest, DomainListenConnectAccept) {
   llvm::SmallString<64> Path;
   std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
   ASSERT_FALSE(EC);
@@ -102,18 +114,22 @@
 }
 #endif
 
-TEST_F(SocketTest, TCPListen0ConnectAccept) {
+TEST_P(SocketTest, TCPListen0ConnectAccept) {
+  if (!HostSupportsProtocol())
+    return;
   std::unique_ptr<TCPSocket> socket_a_up;
   std::unique_ptr<TCPSocket> socket_b_up;
-  CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up);
+  CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
+                            &socket_b_up);
 }
 
-TEST_F(SocketTest, TCPGetAddress) {
+TEST_P(SocketTest, TCPGetAddress) {
   std::unique_ptr<TCPSocket> socket_a_up;
   std::unique_ptr<TCPSocket> socket_b_up;
-  if (!HostSupportsIPv4())
+  if (!HostSupportsProtocol())
     return;
-  CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up);
+  CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
+                            &socket_b_up);
 
   EXPECT_EQ(socket_a_up->GetLocalPortNumber(),
             socket_b_up->GetRemotePortNumber());
@@ -121,11 +137,16 @@
             socket_a_up->GetRemotePortNumber());
   EXPECT_NE(socket_a_up->GetLocalPortNumber(),
             socket_b_up->GetLocalPortNumber());
-  EXPECT_STREQ("127.0.0.1", socket_a_up->GetRemoteIPAddress().c_str());
-  EXPECT_STREQ("127.0.0.1", socket_b_up->GetRemoteIPAddress().c_str());
+  EXPECT_STREQ(GetParam().localhost_ip.c_str(),
+               socket_a_up->GetRemoteIPAddress().c_str());
+  EXPECT_STREQ(GetParam().localhost_ip.c_str(),
+               socket_b_up->GetRemoteIPAddress().c_str());
 }
 
-TEST_F(SocketTest, UDPConnect) {
+TEST_P(SocketTest, UDPConnect) {
+  // UDPSocket::Connect() creates sockets with AF_INET (IPv4).
+  if (!HostSupportsIPv4())
+    return;
   llvm::Expected<std::unique_ptr<UDPSocket>> socket =
       UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false);
 
@@ -133,7 +154,9 @@
   EXPECT_TRUE(socket.get()->IsValid());
 }
 
-TEST_F(SocketTest, TCPListen0GetPort) {
+TEST_P(SocketTest, TCPListen0GetPort) {
+  if (!HostSupportsIPv4())
+    return;
   Predicate<uint16_t> port_predicate;
   port_predicate.SetValue(0, eBroadcastNever);
   llvm::Expected<std::unique_ptr<TCPSocket>> sock =
@@ -143,12 +166,13 @@
   EXPECT_NE(sock.get()->GetLocalPortNumber(), 0);
 }
 
-TEST_F(SocketTest, TCPGetConnectURI) {
+TEST_P(SocketTest, TCPGetConnectURI) {
   std::unique_ptr<TCPSocket> socket_a_up;
   std::unique_ptr<TCPSocket> socket_b_up;
-  if (!HostSupportsIPv4())
+  if (!HostSupportsProtocol())
     return;
-  CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up);
+  CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
+                            &socket_b_up);
 
   llvm::StringRef scheme;
   llvm::StringRef hostname;
@@ -160,7 +184,8 @@
   EXPECT_EQ(port, socket_a_up->GetRemotePortNumber());
 }
 
-TEST_F(SocketTest, UDPGetConnectURI) {
+TEST_P(SocketTest, UDPGetConnectURI) {
+  // UDPSocket::Connect() creates sockets with AF_INET (IPv4).
   if (!HostSupportsIPv4())
     return;
   llvm::Expected<std::unique_ptr<UDPSocket>> socket =
@@ -177,7 +202,7 @@
 }
 
 #if LLDB_ENABLE_POSIX
-TEST_F(SocketTest, DomainGetConnectURI) {
+TEST_P(SocketTest, DomainGetConnectURI) {
   llvm::SmallString<64> domain_path;
   std::error_code EC =
       llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", domain_path);
@@ -202,3 +227,13 @@
   EXPECT_EQ(path, domain_path);
 }
 #endif
+
+INSTANTIATE_TEST_CASE_P(
+    SocketTests, SocketTest,
+    testing::Values(SocketTestParams{/*is_ipv6=*/false,
+                                     /*localhost_ip=*/"127.0.0.1"},
+                    SocketTestParams{/*is_ipv6=*/true, /*localhost_ip=*/"::1"}),
+    // Prints "SocketTests/SocketTest.DecodeHostAndPort/ipv4" etc. in test logs.
+    [](const testing::TestParamInfo<SocketTestParams> &info) {
+      return info.param.is_ipv6 ? "ipv6" : "ipv4";
+    });
Index: lldb/tools/lldb-server/lldb-gdbserver.cpp
===================================================================
--- lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -267,7 +267,8 @@
       final_host_and_port.append("localhost");
     final_host_and_port.append(host_and_port);
 
-    const std::string::size_type colon_pos = final_host_and_port.find(':');
+    // Note: use rfind, because the host/port may look like "[::1]:12345".
+    const std::string::size_type colon_pos = final_host_and_port.rfind(':');
     if (colon_pos != std::string::npos) {
       connection_host = final_host_and_port.substr(0, colon_pos);
       connection_port = final_host_and_port.substr(colon_pos + 1);
Index: lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py
===================================================================
--- lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py
+++ lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py
@@ -1,5 +1,6 @@
 from __future__ import print_function
 
+import errno
 import gdbremote_testcase
 import lldbgdbserverutils
 import re
@@ -24,11 +25,20 @@
         self.listener_port = self.listener_socket.getsockname()[1]
 
     def create_listener_socket(self):
-        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        try:
+            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        except OSError as e:
+            if e.errno != errno.EAFNOSUPPORT:
+                raise
+            sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
         self.assertIsNotNone(sock)
 
         sock.settimeout(self.DEFAULT_TIMEOUT)
-        sock.bind(("127.0.0.1", 0))
+        if sock.family == socket.AF_INET:
+            bind_addr = ("127.0.0.1", 0)
+        elif sock.family == socket.AF_INET6:
+            bind_addr = ("::1", 0)
+        sock.bind(bind_addr)
         sock.listen(1)
 
         def tear_down_listener():
Index: lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
===================================================================
--- lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
+++ lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
@@ -1,3 +1,4 @@
+import errno
 import os
 import os.path
 import threading
@@ -317,12 +318,20 @@
     def __init__(self, port = 0):
         self.responder = MockGDBServerResponder()
         self.port = port
-        self._socket = socket.socket()
+        try:
+            self._socket = socket.socket(family=socket.AF_INET)
+        except OSError as e:
+            if e.errno != errno.EAFNOSUPPORT:
+                raise
+            self._socket = socket.socket(family=socket.AF_INET6)
 
     def start(self):
         # Block until the socket is up, so self.port is available immediately.
         # Then start a thread that waits for a client connection.
-        addr = ("127.0.0.1", self.port)
+        if self._socket.family == socket.AF_INET:
+            addr = ("127.0.0.1", self.port)
+        elif self._socket.family == socket.AF_INET6:
+            addr = ("::1", self.port)
         self._socket.bind(addr)
         self.port = self._socket.getsockname()[1]
         self._socket.listen(1)
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -1233,17 +1233,31 @@
   const bool child_processes_inherit = false;
   const int backlog = 5;
   TCPSocket listen_socket(true, child_processes_inherit);
+  std::string listen_addr = "127.0.0.1";
   if (llvm::Error error =
-          listen_socket.Listen("127.0.0.1:0", backlog).ToError())
-    return error;
+          listen_socket.Listen(listen_addr + ":0", backlog).ToError()) {
+    // Retry with ipv6 if the error appears to be that ipv4 is unavailable.
+    error = llvm::handleErrors(
+        std::move(error), [&](std::unique_ptr<llvm::ECError> e) -> llvm::Error {
+          std::error_code ec = e->convertToErrorCode();
+          if (ec == std::errc::address_family_not_supported ||
+              ec == std::errc::address_not_available) {
+            listen_addr = "[::1]";
+            return listen_socket.Listen(listen_addr + ":0", backlog).ToError();
+          }
+          return llvm::Error(std::move(e));
+        });
+    if (error)
+      return error;
+  }
 
   Socket *accept_socket;
   std::future<Status> accept_status = std::async(
       std::launch::async, [&] { return listen_socket.Accept(accept_socket); });
 
   llvm::SmallString<32> remote_addr;
-  llvm::raw_svector_ostream(remote_addr)
-      << "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber();
+  llvm::raw_svector_ostream(remote_addr) << "connect://" << listen_addr << ":"
+                                         << listen_socket.GetLocalPortNumber();
 
   std::unique_ptr<ConnectionFileDescriptor> conn_up(
       new ConnectionFileDescriptor());
Index: lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -82,6 +82,20 @@
         return any(("gdb-remote" in channel)
                    for channel in lldbtest_config.channels)
 
+    def detect_ip_support(self):
+        try:
+            sock = socket.socket(family=socket.AF_INET)
+            supported = (socket.AF_INET, '127.0.0.1')
+        except OSError as e:
+            if e.errno != errno.EAFNOSUPPORT:
+                raise
+            sock = socket.socket(family=socket.AF_INET6)
+            supported = (socket.AF_INET6, '[::1]')
+        # Note: automatically closing sockets with a context manager is not
+        # supported until python3.
+        sock.close()
+        return supported
+
     def setUp(self):
         TestBase.setUp(self)
 
@@ -104,6 +118,7 @@
         self.named_pipe = None
         self.named_pipe_fd = None
         self.stub_sends_two_stop_notifications_on_kill = False
+        self.supported_ip_protocol = self.detect_ip_support()
         if configuration.lldb_platform_url:
             if configuration.lldb_platform_url.startswith('unix-'):
                 url_pattern = '(.+)://\[?(.+?)\]?/.*'
@@ -318,7 +333,7 @@
             raise _ConnectionRefused()  # Got EOF, connection dropped.
 
     def create_socket(self):
-        sock = socket.socket()
+        sock = socket.socket(family=self.supported_ip_protocol[0])
         logger = self.logger
 
         triple = self.dbg.GetSelectedPlatform().GetTriple()
@@ -379,7 +394,7 @@
                 ["*:{}".format(self.port)]
         else:
             commandline_args = self.debug_monitor_extra_args + \
-                ["127.0.0.1:{}".format(self.port)]
+                ["{}:{}".format(self.supported_ip_protocol[1], self.port)]
 
         if attach_pid:
             commandline_args += ["--attach=%d" % attach_pid]
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to