[Lldb-commits] [lldb] c3193e4 - [lldb/ipv6] Support running lldb tests in an ipv6-only environment.

Jordan Rupprecht via lldb-commits lldb-commits at lists.llvm.org
Wed Sep 30 11:11:13 PDT 2020


Author: Jordan Rupprecht
Date: 2020-09-30T11:08:41-07:00
New Revision: c3193e464cbd5e8b7cade103032c222bf8bc0e27

URL: https://github.com/llvm/llvm-project/commit/c3193e464cbd5e8b7cade103032c222bf8bc0e27
DIFF: https://github.com/llvm/llvm-project/commit/c3193e464cbd5e8b7cade103032c222bf8bc0e27.diff

LOG: [lldb/ipv6] Support running lldb tests in an ipv6-only environment.

When running in an ipv6-only environment where `AF_INET` sockets are not available, many lldb tests (mostly gdb remote tests) fail because things like `127.0.0.1` don't work there.

Use `localhost` instead of `127.0.0.1` whenever possible, or include a fallback of creating `AF_INET6` sockets when `AF_INET` fails.

Reviewed By: labath

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

Added: 
    

Modified: 
    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

Removed: 
    


################################################################################
diff  --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
index 253fd35d461e..7d7b61c8610d 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -318,7 +318,13 @@ def _verify_socket(self, sock):
             raise _ConnectionRefused()  # Got EOF, connection dropped.
 
     def create_socket(self):
-        sock = socket.socket()
+        try:
+            sock = socket.socket(family=socket.AF_INET)
+        except OSError as e:
+            if e.errno != errno.EAFNOSUPPORT:
+                raise
+            sock = socket.socket(family=socket.AF_INET6)
+
         logger = self.logger
 
         triple = self.dbg.GetSelectedPlatform().GetTriple()
@@ -379,7 +385,7 @@ def get_debug_monitor_command_line_args(self, attach_pid=None):
                 ["*:{}".format(self.port)]
         else:
             commandline_args = self.debug_monitor_extra_args + \
-                ["127.0.0.1:{}".format(self.port)]
+                ["localhost:{}".format(self.port)]
 
         if attach_pid:
             commandline_args += ["--attach=%d" % attach_pid]

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 832760f7f0dc..4981345d6a18 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -1234,7 +1234,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
   const int backlog = 5;
   TCPSocket listen_socket(true, child_processes_inherit);
   if (llvm::Error error =
-          listen_socket.Listen("127.0.0.1:0", backlog).ToError())
+          listen_socket.Listen("localhost:0", backlog).ToError())
     return error;
 
   Socket *accept_socket;
@@ -1243,7 +1243,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
 
   llvm::SmallString<32> remote_addr;
   llvm::raw_svector_ostream(remote_addr)
-      << "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber();
+      << "connect://localhost:" << listen_socket.GetLocalPortNumber();
 
   std::unique_ptr<ConnectionFileDescriptor> conn_up(
       new ConnectionFileDescriptor());

diff  --git a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
index eb789e861d9c..dabe9423434d 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
+++ b/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 @@ class MockGDBServer:
     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)

diff  --git a/lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py b/lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py
index a3250ab4f1bf..4306f8dcc22d 100644
--- a/lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py
+++ b/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 @@ def setUp(self):
         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():

diff  --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp
index 5f06503d6424..7f53756424c6 100644
--- a/lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -267,7 +267,8 @@ void ConnectToRemote(MainLoop &mainloop,
       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);

diff  --git a/lldb/unittests/Host/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp
index c53d2660f0c8..901f878d2e46 100644
--- a/lldb/unittests/Host/SocketTest.cpp
+++ b/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 @@ TEST_F(SocketTest, DecodeHostAndPort) {
 }
 
 #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 @@ TEST_F(SocketTest, DomainListenConnectAccept) {
 }
 #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 @@ TEST_F(SocketTest, TCPGetAddress) {
             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 @@ TEST_F(SocketTest, UDPConnect) {
   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 @@ TEST_F(SocketTest, TCPListen0GetPort) {
   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 @@ TEST_F(SocketTest, TCPGetConnectURI) {
   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 @@ TEST_F(SocketTest, UDPGetConnectURI) {
 }
 
 #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 @@ TEST_F(SocketTest, DomainGetConnectURI) {
   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";
+    });

diff  --git a/lldb/unittests/Host/SocketTestUtilities.cpp b/lldb/unittests/Host/SocketTestUtilities.cpp
index e2006b85115d..3b52a66a09eb 100644
--- a/lldb/unittests/Host/SocketTestUtilities.cpp
+++ b/lldb/unittests/Host/SocketTestUtilities.cpp
@@ -101,13 +101,14 @@ static bool CheckIPSupport(llvm::StringRef Proto, llvm::StringRef Addr) {
                              "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)


        


More information about the lldb-commits mailing list