Skip to content

Commit c3193e4

Browse files
committed
[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
1 parent 8955950 commit c3193e4

File tree

7 files changed

+93
-31
lines changed

7 files changed

+93
-31
lines changed

lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,13 @@ def _verify_socket(self, sock):
318318
raise _ConnectionRefused() # Got EOF, connection dropped.
319319

320320
def create_socket(self):
321-
sock = socket.socket()
321+
try:
322+
sock = socket.socket(family=socket.AF_INET)
323+
except OSError as e:
324+
if e.errno != errno.EAFNOSUPPORT:
325+
raise
326+
sock = socket.socket(family=socket.AF_INET6)
327+
322328
logger = self.logger
323329

324330
triple = self.dbg.GetSelectedPlatform().GetTriple()
@@ -379,7 +385,7 @@ def get_debug_monitor_command_line_args(self, attach_pid=None):
379385
["*:{}".format(self.port)]
380386
else:
381387
commandline_args = self.debug_monitor_extra_args + \
382-
["127.0.0.1:{}".format(self.port)]
388+
["localhost:{}".format(self.port)]
383389

384390
if attach_pid:
385391
commandline_args += ["--attach=%d" % attach_pid]

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
12341234
const int backlog = 5;
12351235
TCPSocket listen_socket(true, child_processes_inherit);
12361236
if (llvm::Error error =
1237-
listen_socket.Listen("127.0.0.1:0", backlog).ToError())
1237+
listen_socket.Listen("localhost:0", backlog).ToError())
12381238
return error;
12391239

12401240
Socket *accept_socket;
@@ -1243,7 +1243,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
12431243

12441244
llvm::SmallString<32> remote_addr;
12451245
llvm::raw_svector_ostream(remote_addr)
1246-
<< "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber();
1246+
<< "connect://localhost:" << listen_socket.GetLocalPortNumber();
12471247

12481248
std::unique_ptr<ConnectionFileDescriptor> conn_up(
12491249
new ConnectionFileDescriptor());

lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import errno
12
import os
23
import os.path
34
import threading
@@ -317,12 +318,20 @@ class MockGDBServer:
317318
def __init__(self, port = 0):
318319
self.responder = MockGDBServerResponder()
319320
self.port = port
320-
self._socket = socket.socket()
321+
try:
322+
self._socket = socket.socket(family=socket.AF_INET)
323+
except OSError as e:
324+
if e.errno != errno.EAFNOSUPPORT:
325+
raise
326+
self._socket = socket.socket(family=socket.AF_INET6)
321327

322328
def start(self):
323329
# Block until the socket is up, so self.port is available immediately.
324330
# Then start a thread that waits for a client connection.
325-
addr = ("127.0.0.1", self.port)
331+
if self._socket.family == socket.AF_INET:
332+
addr = ("127.0.0.1", self.port)
333+
elif self._socket.family == socket.AF_INET6:
334+
addr = ("::1", self.port)
326335
self._socket.bind(addr)
327336
self.port = self._socket.getsockname()[1]
328337
self._socket.listen(1)

lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import print_function
22

3+
import errno
34
import gdbremote_testcase
45
import lldbgdbserverutils
56
import re
@@ -24,11 +25,20 @@ def setUp(self):
2425
self.listener_port = self.listener_socket.getsockname()[1]
2526

2627
def create_listener_socket(self):
27-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
28+
try:
29+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
30+
except OSError as e:
31+
if e.errno != errno.EAFNOSUPPORT:
32+
raise
33+
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
2834
self.assertIsNotNone(sock)
2935

3036
sock.settimeout(self.DEFAULT_TIMEOUT)
31-
sock.bind(("127.0.0.1", 0))
37+
if sock.family == socket.AF_INET:
38+
bind_addr = ("127.0.0.1", 0)
39+
elif sock.family == socket.AF_INET6:
40+
bind_addr = ("::1", 0)
41+
sock.bind(bind_addr)
3242
sock.listen(1)
3343

3444
def tear_down_listener():

lldb/tools/lldb-server/lldb-gdbserver.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,8 @@ void ConnectToRemote(MainLoop &mainloop,
267267
final_host_and_port.append("localhost");
268268
final_host_and_port.append(host_and_port);
269269

270-
const std::string::size_type colon_pos = final_host_and_port.find(':');
270+
// Note: use rfind, because the host/port may look like "[::1]:12345".
271+
const std::string::size_type colon_pos = final_host_and_port.rfind(':');
271272
if (colon_pos != std::string::npos) {
272273
connection_host = final_host_and_port.substr(0, colon_pos);
273274
connection_port = final_host_and_port.substr(colon_pos + 1);

lldb/unittests/Host/SocketTest.cpp

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,24 @@
1414

1515
using namespace lldb_private;
1616

17-
class SocketTest : public testing::Test {
17+
struct SocketTestParams {
18+
bool is_ipv6;
19+
std::string localhost_ip;
20+
};
21+
22+
class SocketTest : public testing::TestWithParam<SocketTestParams> {
1823
public:
1924
SubsystemRAII<Socket> subsystems;
25+
26+
protected:
27+
bool HostSupportsProtocol() const {
28+
if (GetParam().is_ipv6)
29+
return HostSupportsIPv6();
30+
return HostSupportsIPv4();
31+
}
2032
};
2133

22-
TEST_F(SocketTest, DecodeHostAndPort) {
34+
TEST_P(SocketTest, DecodeHostAndPort) {
2335
std::string host_str;
2436
std::string port_str;
2537
int32_t port;
@@ -86,7 +98,7 @@ TEST_F(SocketTest, DecodeHostAndPort) {
8698
}
8799

88100
#if LLDB_ENABLE_POSIX
89-
TEST_F(SocketTest, DomainListenConnectAccept) {
101+
TEST_P(SocketTest, DomainListenConnectAccept) {
90102
llvm::SmallString<64> Path;
91103
std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
92104
ASSERT_FALSE(EC);
@@ -102,38 +114,49 @@ TEST_F(SocketTest, DomainListenConnectAccept) {
102114
}
103115
#endif
104116

105-
TEST_F(SocketTest, TCPListen0ConnectAccept) {
117+
TEST_P(SocketTest, TCPListen0ConnectAccept) {
118+
if (!HostSupportsProtocol())
119+
return;
106120
std::unique_ptr<TCPSocket> socket_a_up;
107121
std::unique_ptr<TCPSocket> socket_b_up;
108-
CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up);
122+
CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
123+
&socket_b_up);
109124
}
110125

111-
TEST_F(SocketTest, TCPGetAddress) {
126+
TEST_P(SocketTest, TCPGetAddress) {
112127
std::unique_ptr<TCPSocket> socket_a_up;
113128
std::unique_ptr<TCPSocket> socket_b_up;
114-
if (!HostSupportsIPv4())
129+
if (!HostSupportsProtocol())
115130
return;
116-
CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up);
131+
CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
132+
&socket_b_up);
117133

118134
EXPECT_EQ(socket_a_up->GetLocalPortNumber(),
119135
socket_b_up->GetRemotePortNumber());
120136
EXPECT_EQ(socket_b_up->GetLocalPortNumber(),
121137
socket_a_up->GetRemotePortNumber());
122138
EXPECT_NE(socket_a_up->GetLocalPortNumber(),
123139
socket_b_up->GetLocalPortNumber());
124-
EXPECT_STREQ("127.0.0.1", socket_a_up->GetRemoteIPAddress().c_str());
125-
EXPECT_STREQ("127.0.0.1", socket_b_up->GetRemoteIPAddress().c_str());
140+
EXPECT_STREQ(GetParam().localhost_ip.c_str(),
141+
socket_a_up->GetRemoteIPAddress().c_str());
142+
EXPECT_STREQ(GetParam().localhost_ip.c_str(),
143+
socket_b_up->GetRemoteIPAddress().c_str());
126144
}
127145

128-
TEST_F(SocketTest, UDPConnect) {
146+
TEST_P(SocketTest, UDPConnect) {
147+
// UDPSocket::Connect() creates sockets with AF_INET (IPv4).
148+
if (!HostSupportsIPv4())
149+
return;
129150
llvm::Expected<std::unique_ptr<UDPSocket>> socket =
130151
UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false);
131152

132153
ASSERT_THAT_EXPECTED(socket, llvm::Succeeded());
133154
EXPECT_TRUE(socket.get()->IsValid());
134155
}
135156

136-
TEST_F(SocketTest, TCPListen0GetPort) {
157+
TEST_P(SocketTest, TCPListen0GetPort) {
158+
if (!HostSupportsIPv4())
159+
return;
137160
Predicate<uint16_t> port_predicate;
138161
port_predicate.SetValue(0, eBroadcastNever);
139162
llvm::Expected<std::unique_ptr<TCPSocket>> sock =
@@ -143,12 +166,13 @@ TEST_F(SocketTest, TCPListen0GetPort) {
143166
EXPECT_NE(sock.get()->GetLocalPortNumber(), 0);
144167
}
145168

146-
TEST_F(SocketTest, TCPGetConnectURI) {
169+
TEST_P(SocketTest, TCPGetConnectURI) {
147170
std::unique_ptr<TCPSocket> socket_a_up;
148171
std::unique_ptr<TCPSocket> socket_b_up;
149-
if (!HostSupportsIPv4())
172+
if (!HostSupportsProtocol())
150173
return;
151-
CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up);
174+
CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
175+
&socket_b_up);
152176

153177
llvm::StringRef scheme;
154178
llvm::StringRef hostname;
@@ -160,7 +184,8 @@ TEST_F(SocketTest, TCPGetConnectURI) {
160184
EXPECT_EQ(port, socket_a_up->GetRemotePortNumber());
161185
}
162186

163-
TEST_F(SocketTest, UDPGetConnectURI) {
187+
TEST_P(SocketTest, UDPGetConnectURI) {
188+
// UDPSocket::Connect() creates sockets with AF_INET (IPv4).
164189
if (!HostSupportsIPv4())
165190
return;
166191
llvm::Expected<std::unique_ptr<UDPSocket>> socket =
@@ -177,7 +202,7 @@ TEST_F(SocketTest, UDPGetConnectURI) {
177202
}
178203

179204
#if LLDB_ENABLE_POSIX
180-
TEST_F(SocketTest, DomainGetConnectURI) {
205+
TEST_P(SocketTest, DomainGetConnectURI) {
181206
llvm::SmallString<64> domain_path;
182207
std::error_code EC =
183208
llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", domain_path);
@@ -202,3 +227,13 @@ TEST_F(SocketTest, DomainGetConnectURI) {
202227
EXPECT_EQ(path, domain_path);
203228
}
204229
#endif
230+
231+
INSTANTIATE_TEST_CASE_P(
232+
SocketTests, SocketTest,
233+
testing::Values(SocketTestParams{/*is_ipv6=*/false,
234+
/*localhost_ip=*/"127.0.0.1"},
235+
SocketTestParams{/*is_ipv6=*/true, /*localhost_ip=*/"::1"}),
236+
// Prints "SocketTests/SocketTest.DecodeHostAndPort/ipv4" etc. in test logs.
237+
[](const testing::TestParamInfo<SocketTestParams> &info) {
238+
return info.param.is_ipv6 ? "ipv6" : "ipv4";
239+
});

lldb/unittests/Host/SocketTestUtilities.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,14 @@ static bool CheckIPSupport(llvm::StringRef Proto, llvm::StringRef Addr) {
101101
"Creating a canary {0} TCP socket failed: {1}.",
102102
Proto, Err)
103103
.str();
104-
bool HasAddrNotAvail = false;
104+
bool HasProtocolError = false;
105105
handleAllErrors(std::move(Err), [&](std::unique_ptr<llvm::ECError> ECErr) {
106-
if (ECErr->convertToErrorCode() ==
107-
std::make_error_code(std::errc::address_not_available))
108-
HasAddrNotAvail = true;
106+
std::error_code ec = ECErr->convertToErrorCode();
107+
if (ec == std::make_error_code(std::errc::address_family_not_supported) ||
108+
ec == std::make_error_code(std::errc::address_not_available))
109+
HasProtocolError = true;
109110
});
110-
if (HasAddrNotAvail) {
111+
if (HasProtocolError) {
111112
GTEST_LOG_(WARNING)
112113
<< llvm::formatv(
113114
"Assuming the host does not support {0}. Skipping test.", Proto)

0 commit comments

Comments
 (0)