summaryrefslogtreecommitdiffstats
path: root/lldb/source/Host/common/TCPSocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Host/common/TCPSocket.cpp')
-rw-r--r--lldb/source/Host/common/TCPSocket.cpp248
1 files changed, 110 insertions, 138 deletions
diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp
index 2f7384bbb57..9a009280a90 100644
--- a/lldb/source/Host/common/TCPSocket.cpp
+++ b/lldb/source/Host/common/TCPSocket.cpp
@@ -14,55 +14,30 @@
#include "lldb/Host/common/TCPSocket.h"
#include "lldb/Host/Config.h"
-#include "lldb/Host/MainLoop.h"
#include "lldb/Utility/Log.h"
-#include "llvm/Config/config.h"
-#include "llvm/Support/raw_ostream.h"
-
#ifndef LLDB_DISABLE_POSIX
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#endif
-#if defined(LLVM_ON_WIN32)
-#include <winsock2.h>
-#endif
-
-#ifdef LLVM_ON_WIN32
-#define CLOSE_SOCKET closesocket
-#else
-#define CLOSE_SOCKET ::close
-#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;
+const int kDomain = AF_INET;
+const int kType = SOCK_STREAM;
}
-TCPSocket::~TCPSocket() { CloseListenSockets(); }
+TCPSocket::TCPSocket(NativeSocket socket, bool should_close)
+ : Socket(socket, ProtocolTcp, should_close) {}
-bool TCPSocket::IsValid() const {
- return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
-}
+TCPSocket::TCPSocket(bool child_processes_inherit, Error &error)
+ : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP,
+ child_processes_inherit, error),
+ true) {}
// Return the port number that is being used by the socket.
uint16_t TCPSocket::GetLocalPortNumber() const {
@@ -71,12 +46,6 @@ uint16_t TCPSocket::GetLocalPortNumber() const {
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;
}
@@ -115,18 +84,9 @@ std::string TCPSocket::GetRemoteIPAddress() const {
return "";
}
-Error TCPSocket::CreateSocket(int domain) {
- Error 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;
-}
-
Error TCPSocket::Connect(llvm::StringRef name) {
+ if (m_socket == kInvalidSocketValue)
+ return Error("Invalid socket");
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
if (log)
@@ -139,133 +99,146 @@ Error TCPSocket::Connect(llvm::StringRef name) {
if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
return error;
- auto addresses =
- lldb_private::SocketAddress::GetAddressInfo(host_str.c_str(), NULL);
- for (auto address : addresses) {
- error = CreateSocket(address.GetFamily());
- if (error.Fail())
- continue;
-
- address.SetPort(port);
+ struct sockaddr_in sa;
+ ::memset(&sa, 0, sizeof(sa));
+ sa.sin_family = kDomain;
+ sa.sin_port = htons(port);
+
+ int inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr);
+
+ if (inet_pton_result <= 0) {
+ struct hostent *host_entry = gethostbyname(host_str.c_str());
+ if (host_entry)
+ host_str = ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list);
+ inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr);
+ if (inet_pton_result <= 0) {
+ if (inet_pton_result == -1)
+ SetLastError(error);
+ else
+ error.SetErrorStringWithFormat("invalid host string: '%s'",
+ host_str.c_str());
- if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(),
- address.GetLength())) {
- continue;
+ return error;
}
+ }
- SetOptionNoDelay();
-
- error.Clear();
+ if (-1 ==
+ ::connect(GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) {
+ SetLastError(error);
return error;
}
- error.SetErrorString("Failed to connect port");
+ // Keep our TCP packets coming without any delays.
+ SetOptionNoDelay();
+ error.Clear();
return error;
}
Error TCPSocket::Listen(llvm::StringRef name, int backlog) {
+ Error error;
+
+ // enable local address reuse
+ SetOptionReuseAddress();
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data());
- Error 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;
- auto addresses =
- lldb_private::SocketAddress::GetAddressInfo(host_str.c_str(), NULL);
- for (auto 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
- SetOptionReuseAddress();
+ SocketAddress bind_addr;
- address.SetPort(port);
+ // Only bind to the loopback address if we are expecting a connection from
+ // localhost to avoid any firewall issues.
+ const bool bind_addr_success = (host_str == "127.0.0.1")
+ ? bind_addr.SetToLocalhost(kDomain, port)
+ : bind_addr.SetToAnyAddress(kDomain, port);
- int err = ::bind(fd, &address.sockaddr(), address.GetLength());
- if (-1 != err)
- err = ::listen(fd, backlog);
+ if (!bind_addr_success) {
+ error.SetErrorString("Failed to bind port");
+ return error;
+ }
- if (-1 == err) {
- CLOSE_SOCKET(fd);
- continue;
- }
+ int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength());
+ if (err != -1)
+ err = ::listen(GetNativeSocket(), backlog);
- 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 (err == -1)
+ SetLastError(error);
- 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();
-}
-
-Error TCPSocket::Accept(Socket *&conn_socket) {
+Error TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&conn_socket) {
Error error;
- if (m_listen_sockets.size() == 0) {
- error.SetErrorString("No open listening sockets!");
+ std::string host_str;
+ std::string port_str;
+ int32_t port;
+ if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
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())
+ const sa_family_t family = kDomain;
+ const int socktype = kType;
+ const int protocol = IPPROTO_TCP;
+ SocketAddress listen_addr;
+ if (host_str.empty())
+ listen_addr.SetToLocalhost(family, port);
+ else if (host_str.compare("*") == 0)
+ listen_addr.SetToAnyAddress(family, port);
+ else {
+ if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family,
+ socktype, protocol)) {
+ error.SetErrorStringWithFormat("unable to resolve hostname '%s'",
+ host_str.c_str());
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();
-
+ struct sockaddr_in accept_addr;
+ ::memset(&accept_addr, 0, sizeof accept_addr);
+#if !(defined(__linux__) || defined(_WIN32))
+ accept_addr.sin_len = sizeof accept_addr;
+#endif
+ socklen_t accept_addr_len = sizeof accept_addr;
+
+ int sock = AcceptSocket(GetNativeSocket(), (struct sockaddr *)&accept_addr,
+ &accept_addr_len, child_processes_inherit, error);
+
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;
+ break;
+
+ bool is_same_addr = true;
+#if !(defined(__linux__) || (defined(_WIN32)))
+ is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len);
+#endif
+ if (is_same_addr)
+ is_same_addr = (accept_addr.sin_addr.s_addr ==
+ listen_addr.sockaddr_in().sin_addr.s_addr);
+
+ if (is_same_addr ||
+ (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)) {
+ accept_connection = true;
+ accepted_socket.reset(new TCPSocket(sock, true));
+ } else {
+ const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
+ const uint8_t *listen_ip =
+ (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr;
+ ::fprintf(stderr, "error: rejecting incoming connection from %u.%u.%u.%u "
+ "(expecting %u.%u.%u.%u)\n",
+ accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
+ listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
+ accepted_socket.reset();
}
- accept_connection = true;
- accepted_socket.reset(new TCPSocket(sock, *this));
}
if (!accepted_socket)
@@ -275,7 +248,6 @@ Error TCPSocket::Accept(Socket *&conn_socket) {
accepted_socket->SetOptionNoDelay();
error.Clear();
conn_socket = accepted_socket.release();
- CloseListenSockets();
return error;
}
OpenPOWER on IntegriCloud