xref: /llvm-project/lldb/unittests/TestingSupport/Host/SocketTestUtilities.cpp (revision 117cfa66ea6b1e307db0e8da43a6e9306cdaaca0)
1 //===-- SocketTestUtilities.cpp -------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "TestingSupport/Host/SocketTestUtilities.h"
10 #include "lldb/Host/Config.h"
11 #include "lldb/Utility/StreamString.h"
12 
13 #ifdef _WIN32
14 #include <winsock2.h>
15 #include <ws2tcpip.h>
16 #else
17 #include <arpa/inet.h>
18 #endif
19 
20 using namespace lldb_private;
21 
22 template <typename SocketType>
23 void lldb_private::CreateConnectedSockets(
24     llvm::StringRef listen_remote_address,
25     const std::function<std::string(const SocketType &)> &get_connect_addr,
26     std::unique_ptr<SocketType> *a_up, std::unique_ptr<SocketType> *b_up) {
27   Status error;
28   auto listen_socket_up = std::make_unique<SocketType>(true);
29   ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
30   error = listen_socket_up->Listen(listen_remote_address, 5);
31   ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
32   ASSERT_TRUE(listen_socket_up->IsValid());
33 
34   std::string connect_remote_address = get_connect_addr(*listen_socket_up);
35   auto connect_socket_up = std::make_unique<SocketType>(true);
36   ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
37   error = connect_socket_up->Connect(connect_remote_address);
38   ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
39   ASSERT_TRUE(connect_socket_up->IsValid());
40 
41   a_up->swap(connect_socket_up);
42   ASSERT_TRUE((*a_up)->IsValid());
43 
44   Socket *accept_socket;
45   ASSERT_THAT_ERROR(
46       listen_socket_up->Accept(std::chrono::seconds(1), accept_socket)
47           .takeError(),
48       llvm::Succeeded());
49 
50   b_up->reset(static_cast<SocketType *>(accept_socket));
51   ASSERT_NE(nullptr, b_up->get());
52   ASSERT_TRUE((*b_up)->IsValid());
53 
54   listen_socket_up.reset();
55 }
56 
57 bool lldb_private::CreateTCPConnectedSockets(
58     std::string listen_remote_ip, std::unique_ptr<TCPSocket> *socket_a_up,
59     std::unique_ptr<TCPSocket> *socket_b_up) {
60   StreamString strm;
61   strm.Printf("[%s]:0", listen_remote_ip.c_str());
62   CreateConnectedSockets<TCPSocket>(
63       strm.GetString(),
64       [=](const TCPSocket &s) {
65         char connect_remote_address[64];
66         snprintf(connect_remote_address, sizeof(connect_remote_address),
67                  "[%s]:%u", listen_remote_ip.c_str(), s.GetLocalPortNumber());
68         return std::string(connect_remote_address);
69       },
70       socket_a_up, socket_b_up);
71   return true;
72 }
73 
74 #if LLDB_ENABLE_POSIX
75 void lldb_private::CreateDomainConnectedSockets(
76     llvm::StringRef path, std::unique_ptr<DomainSocket> *socket_a_up,
77     std::unique_ptr<DomainSocket> *socket_b_up) {
78   return CreateConnectedSockets<DomainSocket>(
79       path, [=](const DomainSocket &) { return path.str(); }, socket_a_up,
80       socket_b_up);
81 }
82 #endif
83 
84 static bool CheckIPSupport(llvm::StringRef Proto, llvm::StringRef Addr) {
85   llvm::Expected<std::unique_ptr<TCPSocket>> Sock = Socket::TcpListen(Addr);
86   if (Sock)
87     return true;
88   llvm::Error Err = Sock.takeError();
89   GTEST_LOG_(WARNING) << llvm::formatv(
90                              "Creating a canary {0} TCP socket failed: {1}.",
91                              Proto, Err)
92                              .str();
93   bool HasProtocolError = false;
94   handleAllErrors(std::move(Err), [&](std::unique_ptr<llvm::ECError> ECErr) {
95     std::error_code ec = ECErr->convertToErrorCode();
96     if (ec == std::make_error_code(std::errc::address_family_not_supported) ||
97         ec == std::make_error_code(std::errc::address_not_available))
98       HasProtocolError = true;
99   });
100   if (HasProtocolError) {
101     GTEST_LOG_(WARNING)
102         << llvm::formatv(
103                "Assuming the host does not support {0}. Skipping test.", Proto)
104                .str();
105     return false;
106   }
107   GTEST_LOG_(WARNING) << "Continuing anyway. The test will probably fail.";
108   return true;
109 }
110 
111 bool lldb_private::HostSupportsIPv4() {
112   return CheckIPSupport("IPv4", "127.0.0.1:0");
113 }
114 
115 bool lldb_private::HostSupportsIPv6() {
116   return CheckIPSupport("IPv6", "[::1]:0");
117 }
118 
119 bool lldb_private::HostSupportsLocalhostToIPv4() {
120   if (!HostSupportsIPv4())
121     return false;
122 
123   auto addresses = SocketAddress::GetAddressInfo(
124       "localhost", nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
125   return llvm::any_of(addresses, [](const SocketAddress &addr) {
126     return addr.GetFamily() == AF_INET;
127   });
128 }
129 
130 bool lldb_private::HostSupportsLocalhostToIPv6() {
131   if (!HostSupportsIPv6())
132     return false;
133 
134   auto addresses = SocketAddress::GetAddressInfo(
135       "localhost", nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
136   return llvm::any_of(addresses, [](const SocketAddress &addr) {
137     return addr.GetFamily() == AF_INET6;
138   });
139 }
140 
141 llvm::Expected<std::string> lldb_private::GetLocalhostIP() {
142   if (HostSupportsIPv4())
143     return "127.0.0.1";
144   if (HostSupportsIPv6())
145     return "[::1]";
146   return llvm::make_error<llvm::StringError>(
147       "Neither IPv4 nor IPv6 appear to be supported",
148       llvm::inconvertibleErrorCode());
149 }
150