*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
257 lines
7.7 KiB
C++
257 lines
7.7 KiB
C++
//===-- TcpSocket.cpp -------------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Host/common/TCPSocket.h"
|
|
|
|
#include "lldb/Core/Log.h"
|
|
#include "lldb/Host/Config.h"
|
|
|
|
#ifndef LLDB_DISABLE_POSIX
|
|
#include <arpa/inet.h>
|
|
#include <netinet/tcp.h>
|
|
#include <sys/socket.h>
|
|
#endif
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
namespace {
|
|
|
|
const int kDomain = AF_INET;
|
|
const int kType = SOCK_STREAM;
|
|
}
|
|
|
|
TCPSocket::TCPSocket(NativeSocket socket, bool should_close)
|
|
: Socket(socket, ProtocolTcp, should_close) {}
|
|
|
|
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 {
|
|
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();
|
|
}
|
|
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 "";
|
|
}
|
|
|
|
Error TCPSocket::Connect(llvm::StringRef name) {
|
|
if (m_socket == kInvalidSocketValue)
|
|
return Error("Invalid socket");
|
|
|
|
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
|
|
if (log)
|
|
log->Printf("TCPSocket::%s (host/port = %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;
|
|
|
|
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());
|
|
|
|
return error;
|
|
}
|
|
}
|
|
|
|
if (-1 ==
|
|
::connect(GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) {
|
|
SetLastError(error);
|
|
return error;
|
|
}
|
|
|
|
// 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());
|
|
|
|
std::string host_str;
|
|
std::string port_str;
|
|
int32_t port = INT32_MIN;
|
|
if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
|
|
return error;
|
|
|
|
SocketAddress bind_addr;
|
|
|
|
// 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);
|
|
|
|
if (!bind_addr_success) {
|
|
error.SetErrorString("Failed to bind port");
|
|
return error;
|
|
}
|
|
|
|
int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength());
|
|
if (err != -1)
|
|
err = ::listen(GetNativeSocket(), backlog);
|
|
|
|
if (err == -1)
|
|
SetLastError(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
Error TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit,
|
|
Socket *&conn_socket) {
|
|
Error error;
|
|
std::string host_str;
|
|
std::string port_str;
|
|
int32_t port;
|
|
if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
|
|
return error;
|
|
|
|
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) {
|
|
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())
|
|
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();
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|