1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
//===-- SocketTestUtilities.cpp -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "TestingSupport/Host/SocketTestUtilities.h"
#include "lldb/Host/Config.h"
#include "lldb/Utility/StreamString.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#endif
using namespace lldb_private;
static void AcceptThread(Socket *listen_socket, bool child_processes_inherit,
Socket **accept_socket, Status *error) {
*error = listen_socket->Accept(*accept_socket);
}
template <typename SocketType>
void lldb_private::CreateConnectedSockets(
llvm::StringRef listen_remote_address,
const std::function<std::string(const SocketType &)> &get_connect_addr,
std::unique_ptr<SocketType> *a_up, std::unique_ptr<SocketType> *b_up) {
bool child_processes_inherit = false;
Status error;
std::unique_ptr<SocketType> listen_socket_up(
new SocketType(true, child_processes_inherit));
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
error = listen_socket_up->Listen(listen_remote_address, 5);
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
ASSERT_TRUE(listen_socket_up->IsValid());
Status accept_error;
Socket *accept_socket;
std::thread accept_thread(AcceptThread, listen_socket_up.get(),
child_processes_inherit, &accept_socket,
&accept_error);
std::string connect_remote_address = get_connect_addr(*listen_socket_up);
std::unique_ptr<SocketType> connect_socket_up(
new SocketType(true, child_processes_inherit));
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
error = connect_socket_up->Connect(connect_remote_address);
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
ASSERT_TRUE(connect_socket_up->IsValid());
a_up->swap(connect_socket_up);
ASSERT_TRUE((*a_up)->IsValid());
accept_thread.join();
b_up->reset(static_cast<SocketType *>(accept_socket));
ASSERT_THAT_ERROR(accept_error.ToError(), llvm::Succeeded());
ASSERT_NE(nullptr, b_up->get());
ASSERT_TRUE((*b_up)->IsValid());
listen_socket_up.reset();
}
bool lldb_private::CreateTCPConnectedSockets(
std::string listen_remote_ip, std::unique_ptr<TCPSocket> *socket_a_up,
std::unique_ptr<TCPSocket> *socket_b_up) {
StreamString strm;
strm.Printf("[%s]:0", listen_remote_ip.c_str());
CreateConnectedSockets<TCPSocket>(
strm.GetString(),
[=](const TCPSocket &s) {
char connect_remote_address[64];
snprintf(connect_remote_address, sizeof(connect_remote_address),
"[%s]:%u", listen_remote_ip.c_str(), s.GetLocalPortNumber());
return std::string(connect_remote_address);
},
socket_a_up, socket_b_up);
return true;
}
#if LLDB_ENABLE_POSIX
void lldb_private::CreateDomainConnectedSockets(
llvm::StringRef path, std::unique_ptr<DomainSocket> *socket_a_up,
std::unique_ptr<DomainSocket> *socket_b_up) {
return CreateConnectedSockets<DomainSocket>(
path, [=](const DomainSocket &) { return path.str(); }, socket_a_up,
socket_b_up);
}
#endif
static bool CheckIPSupport(llvm::StringRef Proto, llvm::StringRef Addr) {
llvm::Expected<std::unique_ptr<TCPSocket>> Sock = Socket::TcpListen(
Addr, /*child_processes_inherit=*/false);
if (Sock)
return true;
llvm::Error Err = Sock.takeError();
GTEST_LOG_(WARNING) << llvm::formatv(
"Creating a canary {0} TCP socket failed: {1}.",
Proto, Err)
.str();
bool HasProtocolError = false;
handleAllErrors(std::move(Err), [&](std::unique_ptr<llvm::ECError> ECErr) {
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 (HasProtocolError) {
GTEST_LOG_(WARNING)
<< llvm::formatv(
"Assuming the host does not support {0}. Skipping test.", Proto)
.str();
return false;
}
GTEST_LOG_(WARNING) << "Continuing anyway. The test will probably fail.";
return true;
}
bool lldb_private::HostSupportsIPv4() {
return CheckIPSupport("IPv4", "127.0.0.1:0");
}
bool lldb_private::HostSupportsIPv6() {
return CheckIPSupport("IPv6", "[::1]:0");
}
llvm::Expected<std::string> lldb_private::GetLocalhostIP() {
if (HostSupportsIPv4())
return "127.0.0.1";
if (HostSupportsIPv6())
return "[::1]";
return llvm::make_error<llvm::StringError>(
"Neither IPv4 nor IPv6 appear to be supported",
llvm::inconvertibleErrorCode());
}
|