1 //===-- SocketTestUtilities.cpp -------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "TestingSupport/Host/SocketTestUtilities.h"
10 #include "lldb/Host/Config.h"
11 #include "lldb/Utility/StreamString.h"
17 #include <arpa/inet.h>
20 using namespace lldb_private
;
22 static void AcceptThread(Socket
*listen_socket
, bool child_processes_inherit
,
23 Socket
**accept_socket
, Status
*error
) {
24 *error
= listen_socket
->Accept(*accept_socket
);
27 template <typename SocketType
>
28 void lldb_private::CreateConnectedSockets(
29 llvm::StringRef listen_remote_address
,
30 const std::function
<std::string(const SocketType
&)> &get_connect_addr
,
31 std::unique_ptr
<SocketType
> *a_up
, std::unique_ptr
<SocketType
> *b_up
) {
32 bool child_processes_inherit
= false;
34 std::unique_ptr
<SocketType
> listen_socket_up(
35 new SocketType(true, child_processes_inherit
));
36 ASSERT_THAT_ERROR(error
.ToError(), llvm::Succeeded());
37 error
= listen_socket_up
->Listen(listen_remote_address
, 5);
38 ASSERT_THAT_ERROR(error
.ToError(), llvm::Succeeded());
39 ASSERT_TRUE(listen_socket_up
->IsValid());
42 Socket
*accept_socket
;
43 std::thread
accept_thread(AcceptThread
, listen_socket_up
.get(),
44 child_processes_inherit
, &accept_socket
,
47 std::string connect_remote_address
= get_connect_addr(*listen_socket_up
);
48 std::unique_ptr
<SocketType
> connect_socket_up(
49 new SocketType(true, child_processes_inherit
));
50 ASSERT_THAT_ERROR(error
.ToError(), llvm::Succeeded());
51 error
= connect_socket_up
->Connect(connect_remote_address
);
52 ASSERT_THAT_ERROR(error
.ToError(), llvm::Succeeded());
53 ASSERT_TRUE(connect_socket_up
->IsValid());
55 a_up
->swap(connect_socket_up
);
56 ASSERT_TRUE((*a_up
)->IsValid());
59 b_up
->reset(static_cast<SocketType
*>(accept_socket
));
60 ASSERT_THAT_ERROR(accept_error
.ToError(), llvm::Succeeded());
61 ASSERT_NE(nullptr, b_up
->get());
62 ASSERT_TRUE((*b_up
)->IsValid());
64 listen_socket_up
.reset();
67 bool lldb_private::CreateTCPConnectedSockets(
68 std::string listen_remote_ip
, std::unique_ptr
<TCPSocket
> *socket_a_up
,
69 std::unique_ptr
<TCPSocket
> *socket_b_up
) {
71 strm
.Printf("[%s]:0", listen_remote_ip
.c_str());
72 CreateConnectedSockets
<TCPSocket
>(
74 [=](const TCPSocket
&s
) {
75 char connect_remote_address
[64];
76 snprintf(connect_remote_address
, sizeof(connect_remote_address
),
77 "[%s]:%u", listen_remote_ip
.c_str(), s
.GetLocalPortNumber());
78 return std::string(connect_remote_address
);
80 socket_a_up
, socket_b_up
);
85 void lldb_private::CreateDomainConnectedSockets(
86 llvm::StringRef path
, std::unique_ptr
<DomainSocket
> *socket_a_up
,
87 std::unique_ptr
<DomainSocket
> *socket_b_up
) {
88 return CreateConnectedSockets
<DomainSocket
>(
89 path
, [=](const DomainSocket
&) { return path
.str(); }, socket_a_up
,
94 static bool CheckIPSupport(llvm::StringRef Proto
, llvm::StringRef Addr
) {
95 llvm::Expected
<std::unique_ptr
<TCPSocket
>> Sock
= Socket::TcpListen(
96 Addr
, /*child_processes_inherit=*/false);
99 llvm::Error Err
= Sock
.takeError();
100 GTEST_LOG_(WARNING
) << llvm::formatv(
101 "Creating a canary {0} TCP socket failed: {1}.",
104 bool HasProtocolError
= false;
105 handleAllErrors(std::move(Err
), [&](std::unique_ptr
<llvm::ECError
> ECErr
) {
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;
111 if (HasProtocolError
) {
114 "Assuming the host does not support {0}. Skipping test.", Proto
)
118 GTEST_LOG_(WARNING
) << "Continuing anyway. The test will probably fail.";
122 bool lldb_private::HostSupportsIPv4() {
123 return CheckIPSupport("IPv4", "127.0.0.1:0");
126 bool lldb_private::HostSupportsIPv6() {
127 return CheckIPSupport("IPv6", "[::1]:0");
130 llvm::Expected
<std::string
> lldb_private::GetLocalhostIP() {
131 if (HostSupportsIPv4())
133 if (HostSupportsIPv6())
135 return llvm::make_error
<llvm::StringError
>(
136 "Neither IPv4 nor IPv6 appear to be supported",
137 llvm::inconvertibleErrorCode());