summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/source/Host/common/TCPSocket.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
commit061da546b983eb767bad15e67af1174fb0bcf31c (patch)
tree83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Host/common/TCPSocket.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz
wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Host/common/TCPSocket.cpp')
-rw-r--r--gnu/llvm/lldb/source/Host/common/TCPSocket.cpp308
1 files changed, 308 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Host/common/TCPSocket.cpp b/gnu/llvm/lldb/source/Host/common/TCPSocket.cpp
new file mode 100644
index 00000000000..b716935db6e
--- /dev/null
+++ b/gnu/llvm/lldb/source/Host/common/TCPSocket.cpp
@@ -0,0 +1,308 @@
+//===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER)
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
+#endif
+
+#include "lldb/Host/common/TCPSocket.h"
+
+#include "lldb/Host/Config.h"
+#include "lldb/Host/MainLoop.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/raw_ostream.h"
+
+#if LLDB_ENABLE_POSIX
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#endif
+
+#if defined(_WIN32)
+#include <winsock2.h>
+#endif
+
+#ifdef _WIN32
+#define CLOSE_SOCKET closesocket
+typedef const char *set_socket_option_arg_type;
+#else
+#include <unistd.h>
+#define CLOSE_SOCKET ::close
+typedef const void *set_socket_option_arg_type;
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+const int kType = SOCK_STREAM;
+}
+
+TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)
+ : Socket(ProtocolTcp, should_close, child_processes_inherit) {}
+
+TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket)
+ : Socket(ProtocolTcp, listen_socket.m_should_close_fd,
+ listen_socket.m_child_processes_inherit) {
+ m_socket = socket;
+}
+
+TCPSocket::TCPSocket(NativeSocket socket, bool should_close,
+ bool child_processes_inherit)
+ : Socket(ProtocolTcp, should_close, child_processes_inherit) {
+ m_socket = socket;
+}
+
+TCPSocket::~TCPSocket() { CloseListenSockets(); }
+
+bool TCPSocket::IsValid() const {
+ return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
+}
+
+// Return the port number that is being used by the socket.
+uint16_t TCPSocket::GetLocalPortNumber() const {
+ if (m_socket != kInvalidSocketValue) {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength();
+ if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetPort();
+ } else if (!m_listen_sockets.empty()) {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength();
+ if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
+ &sock_addr_len) == 0)
+ return sock_addr.GetPort();
+ }
+ return 0;
+}
+
+std::string TCPSocket::GetLocalIPAddress() const {
+ // We bound to port zero, so we need to figure out which port we actually
+ // bound to
+ if (m_socket != kInvalidSocketValue) {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength();
+ if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetIPAddress();
+ }
+ return "";
+}
+
+uint16_t TCPSocket::GetRemotePortNumber() const {
+ if (m_socket != kInvalidSocketValue) {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength();
+ if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetPort();
+ }
+ return 0;
+}
+
+std::string TCPSocket::GetRemoteIPAddress() const {
+ // We bound to port zero, so we need to figure out which port we actually
+ // bound to
+ if (m_socket != kInvalidSocketValue) {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength();
+ if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetIPAddress();
+ }
+ return "";
+}
+
+std::string TCPSocket::GetRemoteConnectionURI() const {
+ if (m_socket != kInvalidSocketValue) {
+ return llvm::formatv("connect://[{0}]:{1}", GetRemoteIPAddress(),
+ GetRemotePortNumber());
+ }
+ return "";
+}
+
+Status TCPSocket::CreateSocket(int domain) {
+ Status error;
+ if (IsValid())
+ error = Close();
+ if (error.Fail())
+ return error;
+ m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP,
+ m_child_processes_inherit, error);
+ return error;
+}
+
+Status TCPSocket::Connect(llvm::StringRef name) {
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
+ LLDB_LOGF(log, "TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
+
+ Status error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
+ return error;
+
+ std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
+ host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
+ for (SocketAddress &address : addresses) {
+ error = CreateSocket(address.GetFamily());
+ if (error.Fail())
+ continue;
+
+ address.SetPort(port);
+
+ if (-1 == llvm::sys::RetryAfterSignal(-1, ::connect,
+ GetNativeSocket(), &address.sockaddr(), address.GetLength())) {
+ CLOSE_SOCKET(GetNativeSocket());
+ continue;
+ }
+
+ SetOptionNoDelay();
+
+ error.Clear();
+ return error;
+ }
+
+ error.SetErrorString("Failed to connect port");
+ return error;
+}
+
+Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ LLDB_LOGF(log, "TCPSocket::%s (%s)", __FUNCTION__, name.data());
+
+ Status error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
+ return error;
+
+ if (host_str == "*")
+ host_str = "0.0.0.0";
+ std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
+ host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
+ for (SocketAddress &address : addresses) {
+ int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
+ m_child_processes_inherit, error);
+ if (error.Fail()) {
+ error.Clear();
+ continue;
+ }
+
+ // enable local address reuse
+ int option_value = 1;
+ set_socket_option_arg_type option_value_p =
+ reinterpret_cast<set_socket_option_arg_type>(&option_value);
+ ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
+ sizeof(option_value));
+
+ SocketAddress listen_address = address;
+ if(!listen_address.IsLocalhost())
+ listen_address.SetToAnyAddress(address.GetFamily(), port);
+ else
+ listen_address.SetPort(port);
+
+ int err =
+ ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
+ if (-1 != err)
+ err = ::listen(fd, backlog);
+
+ if (-1 == err) {
+ CLOSE_SOCKET(fd);
+ continue;
+ }
+
+ if (port == 0) {
+ socklen_t sa_len = address.GetLength();
+ if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
+ port = address.GetPort();
+ }
+ m_listen_sockets[fd] = address;
+ }
+
+ if (m_listen_sockets.size() == 0)
+ error.SetErrorString("Failed to connect port");
+ return error;
+}
+
+void TCPSocket::CloseListenSockets() {
+ for (auto socket : m_listen_sockets)
+ CLOSE_SOCKET(socket.first);
+ m_listen_sockets.clear();
+}
+
+Status TCPSocket::Accept(Socket *&conn_socket) {
+ Status error;
+ if (m_listen_sockets.size() == 0) {
+ error.SetErrorString("No open listening sockets!");
+ return error;
+ }
+
+ int sock = -1;
+ int listen_sock = -1;
+ lldb_private::SocketAddress AcceptAddr;
+ MainLoop accept_loop;
+ std::vector<MainLoopBase::ReadHandleUP> handles;
+ for (auto socket : m_listen_sockets) {
+ auto fd = socket.first;
+ auto inherit = this->m_child_processes_inherit;
+ auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));
+ handles.emplace_back(accept_loop.RegisterReadObject(
+ io_sp, [fd, inherit, &sock, &AcceptAddr, &error,
+ &listen_sock](MainLoopBase &loop) {
+ socklen_t sa_len = AcceptAddr.GetMaxLength();
+ sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,
+ error);
+ listen_sock = fd;
+ loop.RequestTermination();
+ }, error));
+ if (error.Fail())
+ return error;
+ }
+
+ bool accept_connection = false;
+ std::unique_ptr<TCPSocket> accepted_socket;
+ // Loop until we are happy with our connection
+ while (!accept_connection) {
+ accept_loop.Run();
+
+ if (error.Fail())
+ return error;
+
+ lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
+ if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
+ CLOSE_SOCKET(sock);
+ llvm::errs() << llvm::formatv(
+ "error: rejecting incoming connection from {0} (expecting {1})",
+ AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
+ continue;
+ }
+ accept_connection = true;
+ accepted_socket.reset(new TCPSocket(sock, *this));
+ }
+
+ if (!accepted_socket)
+ return error;
+
+ // Keep our TCP packets coming without any delays.
+ accepted_socket->SetOptionNoDelay();
+ error.Clear();
+ conn_socket = accepted_socket.release();
+ return error;
+}
+
+int TCPSocket::SetOptionNoDelay() {
+ return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
+}
+
+int TCPSocket::SetOptionReuseAddress() {
+ return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
+}