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 "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 static void AcceptThread(Socket *listen_socket, bool child_processes_inherit, 23 Socket **accept_socket, Status *error) { 24 *error = listen_socket->Accept(*accept_socket); 25 } 26 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; 33 Status error; 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()); 40 41 Status accept_error; 42 Socket *accept_socket; 43 std::thread accept_thread(AcceptThread, listen_socket_up.get(), 44 child_processes_inherit, &accept_socket, 45 &accept_error); 46 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()); 54 55 a_up->swap(connect_socket_up); 56 ASSERT_TRUE((*a_up)->IsValid()); 57 58 accept_thread.join(); 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()); 63 64 listen_socket_up.reset(); 65 } 66 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) { 70 StreamString strm; 71 strm.Printf("[%s]:0", listen_remote_ip.c_str()); 72 CreateConnectedSockets<TCPSocket>( 73 strm.GetString(), 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); 79 }, 80 socket_a_up, socket_b_up); 81 return true; 82 } 83 84 #if LLDB_ENABLE_POSIX 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, 90 socket_b_up); 91 } 92 #endif 93 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); 97 if (Sock) 98 return true; 99 llvm::Error Err = Sock.takeError(); 100 GTEST_LOG_(WARNING) << llvm::formatv( 101 "Creating a canary {0} TCP socket failed: {1}.", 102 Proto, Err) 103 .str(); 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; 110 }); 111 if (HasProtocolError) { 112 GTEST_LOG_(WARNING) 113 << llvm::formatv( 114 "Assuming the host does not support {0}. Skipping test.", Proto) 115 .str(); 116 return false; 117 } 118 GTEST_LOG_(WARNING) << "Continuing anyway. The test will probably fail."; 119 return true; 120 } 121 122 bool lldb_private::HostSupportsIPv4() { 123 return CheckIPSupport("IPv4", "127.0.0.1:0"); 124 } 125 126 bool lldb_private::HostSupportsIPv6() { 127 return CheckIPSupport("IPv6", "[::1]:0"); 128 } 129