diff options
author | Oleksiy Vyalov <ovyalov@google.com> | 2015-10-15 23:54:09 +0000 |
---|---|---|
committer | Oleksiy Vyalov <ovyalov@google.com> | 2015-10-15 23:54:09 +0000 |
commit | e98628cecbe1d1731a5b0181a0d2723621cb297c (patch) | |
tree | dac18f72df0ba71eb7d77b64d35ed3733511095b /lldb/source/Host/common | |
parent | 15709991d09d940834029baf20a078d44f55234a (diff) | |
download | bcm5719-llvm-e98628cecbe1d1731a5b0181a0d2723621cb297c.tar.gz bcm5719-llvm-e98628cecbe1d1731a5b0181a0d2723621cb297c.zip |
Split Socket class into Tcp/Udp/DomainSocket subclasses.
http://reviews.llvm.org/D13754
llvm-svn: 250474
Diffstat (limited to 'lldb/source/Host/common')
-rw-r--r-- | lldb/source/Host/common/Socket.cpp | 569 | ||||
-rw-r--r-- | lldb/source/Host/common/TCPSocket.cpp | 288 | ||||
-rw-r--r-- | lldb/source/Host/common/UDPSocket.cpp | 158 |
3 files changed, 546 insertions, 469 deletions
diff --git a/lldb/source/Host/common/Socket.cpp b/lldb/source/Host/common/Socket.cpp index 8e44797ce0b..b080e38f9c8 100644 --- a/lldb/source/Host/common/Socket.cpp +++ b/lldb/source/Host/common/Socket.cpp @@ -12,11 +12,23 @@ #include "lldb/Core/Log.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Host/Config.h" -#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/SocketAddress.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/common/UDPSocket.h" + +#ifndef LLDB_DISABLE_POSIX +#include "lldb/Host/posix/DomainSocket.h" + +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/socket.h> +#include <sys/un.h> +#endif #ifdef __ANDROID_NDK__ #include <linux/tcp.h> @@ -31,15 +43,6 @@ #endif // ANDROID_ARM_BUILD_STATIC #endif // __ANDROID_NDK__ -#ifndef LLDB_DISABLE_POSIX -#include <arpa/inet.h> -#include <netdb.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <sys/socket.h> -#include <sys/un.h> -#endif - using namespace lldb; using namespace lldb_private; @@ -53,65 +56,8 @@ typedef void * get_socket_option_arg_type; const NativeSocket Socket::kInvalidSocketValue = -1; #endif // #if defined(_WIN32) -#ifdef __ANDROID__ -// Android does not have SUN_LEN -#ifndef SUN_LEN -#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) -#endif -#endif // #ifdef __ANDROID__ - namespace { -NativeSocket CreateSocket(const int domain, const int type, const int protocol, bool child_processes_inherit) -{ - auto socketType = type; -#ifdef SOCK_CLOEXEC - if (!child_processes_inherit) { - socketType |= SOCK_CLOEXEC; - } -#endif - return ::socket (domain, socketType, protocol); -} - -NativeSocket Accept(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, bool child_processes_inherit) -{ -#if defined(ANDROID_ARM_BUILD_STATIC) - // Temporary workaround for statically linking Android lldb-server with the - // latest API. - int fd = syscall(__NR_accept, sockfd, addr, addrlen); - if (fd >= 0 && !child_processes_inherit) - { - int flags = ::fcntl(fd, F_GETFD); - if (flags == -1) - return -1; - if (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) - return -1; - } - return fd; -#elif defined(SOCK_CLOEXEC) - int flags = 0; - if (!child_processes_inherit) { - flags |= SOCK_CLOEXEC; - } -#if defined(__NetBSD__) - return ::paccept (sockfd, addr, addrlen, NULL, flags); -#else - return ::accept4 (sockfd, addr, addrlen, flags); -#endif -#else - return ::accept (sockfd, addr, addrlen); -#endif -} - -void SetLastError(Error &error) -{ -#if defined(_WIN32) - error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32); -#else - error.SetErrorToErrno(); -#endif -} - bool IsInterrupted() { #if defined(_WIN32) @@ -138,70 +84,19 @@ Socket::~Socket() Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket) { - // Store the result in a unique_ptr in case we error out, the memory will get correctly freed. - std::unique_ptr<Socket> final_socket; - NativeSocket sock = kInvalidSocketValue; - Error error; - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); if (log) - log->Printf ("Socket::TcpConnect (host/port = %s)", host_and_port.data()); + log->Printf ("Socket::%s (host/port = %s)", __FUNCTION__, host_and_port.data()); - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error)) - return error; - - // Create the socket - sock = CreateSocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, child_processes_inherit); - if (sock == kInvalidSocketValue) - { - SetLastError (error); + Error error; + std::unique_ptr<TCPSocket> connect_socket(new TCPSocket(child_processes_inherit, error)); + if (error.Fail()) return error; - } - - // Since they both refer to the same socket descriptor, arbitrarily choose the send socket to - // be the owner. - final_socket.reset(new Socket(sock, ProtocolTcp, true)); - - // Enable local address reuse - final_socket->SetOption(SOL_SOCKET, SO_REUSEADDR, 1); - - struct sockaddr_in sa; - ::memset (&sa, 0, sizeof (sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons (port); - - int inet_pton_result = ::inet_pton (AF_INET, 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 (AF_INET, 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 (sock, (const struct sockaddr *)&sa, sizeof(sa))) - { - SetLastError (error); - return error; - } + error = connect_socket->Connect(host_and_port); + if (error.Success()) + socket = connect_socket.release(); - // Keep our TCP packets coming without any delays. - final_socket->SetOption(IPPROTO_TCP, TCP_NODELAY, 1); - error.Clear(); - socket = final_socket.release(); return error; } @@ -212,61 +107,24 @@ Socket::TcpListen (llvm::StringRef host_and_port, Predicate<uint16_t>* predicate, int backlog) { - std::unique_ptr<Socket> listen_socket; - NativeSocket listen_sock = kInvalidSocketValue; - Error error; - - const sa_family_t family = AF_INET; - const int socktype = SOCK_STREAM; - const int protocol = IPPROTO_TCP; - listen_sock = ::CreateSocket (family, socktype, protocol, child_processes_inherit); - if (listen_sock == kInvalidSocketValue) - { - SetLastError (error); - return error; - } - - listen_socket.reset(new Socket(listen_sock, ProtocolTcp, true)); - - // enable local address reuse - listen_socket->SetOption(SOL_SOCKET, SO_REUSEADDR, 1); - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) - log->Printf ("Socket::TcpListen (%s)", host_and_port.data()); + log->Printf ("Socket::%s (%s)", __FUNCTION__, host_and_port.data()); + Error error; std::string host_str; std::string port_str; int32_t port = INT32_MIN; if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error)) return error; - SocketAddress bind_addr; - bool bind_addr_success = false; - - // Only bind to the loopback address if we are expecting a connection from - // localhost to avoid any firewall issues. - if (host_str == "127.0.0.1") - bind_addr_success = bind_addr.SetToLocalhost (family, port); - else - bind_addr_success = bind_addr.SetToAnyAddress (family, port); + std::unique_ptr<TCPSocket> listen_socket(new TCPSocket(child_processes_inherit, error)); + if (error.Fail()) + return error; - if (bind_addr_success) + error = listen_socket->Listen(host_and_port, backlog); + if (error.Success()) { - int err = ::bind (listen_sock, bind_addr, bind_addr.GetLength()); - if (err == -1) - { - SetLastError (error); - return error; - } - - err = ::listen (listen_sock, backlog); - if (err == -1) - { - SetLastError (error); - return error; - } - // We were asked to listen on port zero which means we // must now read the actual port that was given to us // as port zero is a special code for "find an open port @@ -281,228 +139,32 @@ Socket::TcpListen (llvm::StringRef host_and_port, // another thread in an efficient manor. if (predicate) predicate->SetValue (port, eBroadcastAlways); - socket = listen_socket.release(); } return error; } -Error Socket::BlockingAccept(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket) -{ - Error error; - std::string host_str; - std::string port_str; - int32_t port; - if (!DecodeHostAndPort(host_and_port, host_str, port_str, port, &error)) - return error; - - const sa_family_t family = AF_INET; - const int socktype = SOCK_STREAM; - 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<Socket> 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 = Accept (this->GetNativeSocket(), - (struct sockaddr *)&accept_addr, - &accept_addr_len, - child_processes_inherit); - - if (sock == kInvalidSocketValue) - { - SetLastError (error); - 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; - // Since both sockets have the same descriptor, arbitrarily choose the send - // socket to be the owner. - accepted_socket.reset(new Socket(sock, ProtocolTcp, 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->SetOption (IPPROTO_TCP, TCP_NODELAY, 1); - error.Clear(); - socket = accepted_socket.release(); - return error; - -} - Error Socket::UdpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket) { - std::unique_ptr<Socket> final_send_socket; - std::unique_ptr<Socket> final_recv_socket; - NativeSocket final_send_fd = kInvalidSocketValue; - NativeSocket final_recv_fd = kInvalidSocketValue; - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) - log->Printf ("Socket::UdpConnect (host/port = %s)", host_and_port.data()); - - Error error; - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error)) - return error; - - // Setup the receiving end of the UDP connection on this localhost - // on port zero. After we bind to port zero we can read the port. - final_recv_fd = ::CreateSocket (AF_INET, SOCK_DGRAM, 0, child_processes_inherit); - if (final_recv_fd == kInvalidSocketValue) - { - // Socket creation failed... - SetLastError (error); - } - else - { - final_recv_socket.reset(new Socket(final_recv_fd, ProtocolUdp, true)); - - // Socket was created, now lets bind to the requested port - SocketAddress addr; - addr.SetToAnyAddress (AF_INET, 0); - - if (::bind (final_recv_fd, addr, addr.GetLength()) == -1) - { - // Bind failed... - SetLastError (error); - } - } - - assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid())); - if (error.Fail()) - return error; - - // At this point we have setup the receive port, now we need to - // setup the UDP send socket - - struct addrinfo hints; - struct addrinfo *service_info_list = NULL; - - ::memset (&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list); - if (err != 0) - { - error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", - host_str.c_str(), - port_str.c_str(), - err, - gai_strerror(err)); - return error; - } - - for (struct addrinfo *service_info_ptr = service_info_list; - service_info_ptr != NULL; - service_info_ptr = service_info_ptr->ai_next) - { - final_send_fd = ::CreateSocket (service_info_ptr->ai_family, - service_info_ptr->ai_socktype, - service_info_ptr->ai_protocol, - child_processes_inherit); - - if (final_send_fd != kInvalidSocketValue) - { - final_send_socket.reset(new Socket(final_send_fd, ProtocolUdp, true)); - final_send_socket->m_udp_send_sockaddr = service_info_ptr; - break; - } - else - continue; - } - - :: freeaddrinfo (service_info_list); - - if (final_send_fd == kInvalidSocketValue) - { - SetLastError (error); - return error; - } + log->Printf ("Socket::%s (host/port = %s)", __FUNCTION__, host_and_port.data()); - send_socket = final_send_socket.release(); - recv_socket = final_recv_socket.release(); - error.Clear(); - return error; + return UDPSocket::Connect(host_and_port, child_processes_inherit, send_socket, recv_socket); } Error Socket::UnixDomainConnect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) { Error error; #ifndef LLDB_DISABLE_POSIX - std::unique_ptr<Socket> final_socket; - - // Open the socket that was passed in as an option - struct sockaddr_un saddr_un; - int fd = ::CreateSocket (AF_UNIX, SOCK_STREAM, 0, child_processes_inherit); - if (fd == kInvalidSocketValue) - { - SetLastError (error); - return error; - } - - final_socket.reset(new Socket(fd, ProtocolUnixDomain, true)); - - saddr_un.sun_family = AF_UNIX; - ::strncpy(saddr_un.sun_path, name.data(), sizeof(saddr_un.sun_path) - 1); - saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - saddr_un.sun_len = SUN_LEN (&saddr_un); -#endif - - if (::connect (fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) - { - SetLastError (error); + std::unique_ptr<DomainSocket> connect_socket(new DomainSocket(child_processes_inherit, error)); + if (error.Fail()) return error; - } - socket = final_socket.release(); + error = connect_socket->Connect(name); + if (error.Success()) + socket = connect_socket.release(); #else error.SetErrorString("Unix domain sockets are not supported on this platform."); #endif @@ -513,52 +175,15 @@ Error Socket::UnixDomainAccept(llvm::StringRef name, bool child_processes_inheri { Error error; #ifndef LLDB_DISABLE_POSIX - struct sockaddr_un saddr_un; - std::unique_ptr<Socket> listen_socket; - std::unique_ptr<Socket> final_socket; - NativeSocket listen_fd = kInvalidSocketValue; - NativeSocket socket_fd = kInvalidSocketValue; - - listen_fd = ::CreateSocket (AF_UNIX, SOCK_STREAM, 0, child_processes_inherit); - if (listen_fd == kInvalidSocketValue) - { - SetLastError (error); + std::unique_ptr<DomainSocket> listen_socket(new DomainSocket(child_processes_inherit, error)); + if (error.Fail()) return error; - } - - listen_socket.reset(new Socket(listen_fd, ProtocolUnixDomain, true)); - - saddr_un.sun_family = AF_UNIX; - ::strncpy(saddr_un.sun_path, name.data(), sizeof(saddr_un.sun_path) - 1); - saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - saddr_un.sun_len = SUN_LEN (&saddr_un); -#endif - FileSystem::Unlink(FileSpec{name, true}); - bool success = false; - if (::bind (listen_fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0) - { - if (::listen (listen_fd, 5) == 0) - { - socket_fd = Accept (listen_fd, NULL, 0, child_processes_inherit); - if (socket_fd > 0) - { - final_socket.reset(new Socket(socket_fd, ProtocolUnixDomain, true)); - success = true; - } - } - } - - if (!success) - { - SetLastError (error); + error = listen_socket->Listen(name, 5); + if (error.Fail()) return error; - } - // We are done with the listen port - listen_socket.reset(); - socket = final_socket.release(); + error = listen_socket->Accept(name, child_processes_inherit, socket); #else error.SetErrorString("Unix domain sockets are not supported on this platform."); #endif @@ -657,17 +282,7 @@ Error Socket::Write (const void *buf, size_t &num_bytes) int bytes_sent = 0; do { - if (m_protocol == ProtocolUdp) - { - bytes_sent = ::sendto (m_socket, - static_cast<const char*>(buf), - num_bytes, - 0, - m_udp_send_sockaddr, - m_udp_send_sockaddr.GetLength()); - } - else - bytes_sent = ::send (m_socket, static_cast<const char *>(buf), num_bytes, 0); + bytes_sent = Send(buf, num_bytes); } while (bytes_sent < 0 && IsInterrupted ()); if (bytes_sent < 0) @@ -729,68 +344,84 @@ int Socket::GetOption(int level, int option_name, int &option_value) { get_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value); socklen_t option_value_size = sizeof(int); - return ::getsockopt(m_socket, level, option_name, option_value_p, &option_value_size); + return ::getsockopt(m_socket, level, option_name, option_value_p, &option_value_size); } int Socket::SetOption(int level, int option_name, int option_value) { set_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value); - return ::setsockopt(m_socket, level, option_name, option_value_p, sizeof(option_value)); + return ::setsockopt(m_socket, level, option_name, option_value_p, sizeof(option_value)); } -uint16_t Socket::GetLocalPortNumber(const NativeSocket& socket) +size_t Socket::Send(const void *buf, const size_t num_bytes) { - // We bound to port zero, so we need to figure out which port we actually bound to - if (socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getsockname (socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetPort (); - } - return 0; + return ::send (m_socket, static_cast<const char *>(buf), num_bytes, 0); } -// Return the port number that is being used by the socket. -uint16_t Socket::GetLocalPortNumber() const +void Socket::SetLastError(Error &error) { - return GetLocalPortNumber (m_socket); +#if defined(_WIN32) + error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32); +#else + error.SetErrorToErrno(); +#endif } -std::string Socket::GetLocalIPAddress () const +NativeSocket +Socket::CreateSocket(const int domain, + const int type, + const int protocol, + bool child_processes_inherit, + Error& error) { - // 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 ""; -} + error.Clear(); + auto socketType = type; +#ifdef SOCK_CLOEXEC + if (!child_processes_inherit) + socketType |= SOCK_CLOEXEC; +#endif + auto sock = ::socket (domain, socketType, protocol); + if (sock == kInvalidSocketValue) + SetLastError(error); -uint16_t Socket::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; + return sock; } -std::string Socket::GetRemoteIPAddress () const +NativeSocket +Socket::AcceptSocket(NativeSocket sockfd, + struct sockaddr *addr, + socklen_t *addrlen, + bool child_processes_inherit, + Error& error) { - // We bound to port zero, so we need to figure out which port we actually bound to - if (m_socket != kInvalidSocketValue) + error.Clear(); +#if defined(ANDROID_ARM_BUILD_STATIC) + // Temporary workaround for statically linking Android lldb-server with the + // latest API. + int fd = syscall(__NR_accept, sockfd, addr, addrlen); + if (fd >= 0 && !child_processes_inherit) { - 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 (); + int flags = ::fcntl(fd, F_GETFD); + if (flags != -1 && ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1) + return fd; + SetLastError(error); + close(fd); } - return ""; + return fd; +#elif defined(SOCK_CLOEXEC) + int flags = 0; + if (!child_processes_inherit) { + flags |= SOCK_CLOEXEC; + } +#if defined(__NetBSD__) + NativeSocket fd = ::paccept (sockfd, addr, addrlen, nullptr, flags); +#else + NativeSocket fd = ::accept4 (sockfd, addr, addrlen, flags); +#endif +#else + NativeSocket fd = ::accept (sockfd, addr, addrlen); +#endif + if (fd == kInvalidSocketValue) + SetLastError(error); + return fd; } diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp new file mode 100644 index 00000000000..b23055ee7d8 --- /dev/null +++ b/lldb/source/Host/common/TCPSocket.cpp @@ -0,0 +1,288 @@ +//===-- 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; + + // Enable local address reuse + SetOptionReuseAddress(); + + 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); +} diff --git a/lldb/source/Host/common/UDPSocket.cpp b/lldb/source/Host/common/UDPSocket.cpp new file mode 100644 index 00000000000..8297232ae72 --- /dev/null +++ b/lldb/source/Host/common/UDPSocket.cpp @@ -0,0 +1,158 @@ +//===-- UdpSocket.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/UDPSocket.h" + +#include "lldb/Core/Log.h" +#include "lldb/Host/Config.h" + +#ifndef LLDB_DISABLE_POSIX +#include <arpa/inet.h> +#include <sys/socket.h> +#endif + +#include <memory> + +using namespace lldb; +using namespace lldb_private; + +namespace { + +const int kDomain = AF_INET; +const int kType = SOCK_DGRAM; + +const Error kNotSupported("Not supported"); + +} + +UDPSocket::UDPSocket(NativeSocket socket) + : Socket(socket, ProtocolUdp, true) +{ +} + +UDPSocket::UDPSocket(bool child_processes_inherit, Error &error) + : UDPSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) +{ +} + +size_t +UDPSocket::Send(const void *buf, const size_t num_bytes) +{ + return ::sendto (m_socket, + static_cast<const char*>(buf), + num_bytes, + 0, + m_send_sockaddr, + m_send_sockaddr.GetLength()); +} + +Error +UDPSocket::Connect(llvm::StringRef name) +{ + return kNotSupported; +} + +Error +UDPSocket::Listen(llvm::StringRef name, int backlog) +{ + return kNotSupported; +} + +Error +UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) +{ + return kNotSupported; +} + +Error +UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket) +{ + std::unique_ptr<UDPSocket> final_send_socket; + std::unique_ptr<UDPSocket> final_recv_socket; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf ("UDPSocket::%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; + + // Setup the receiving end of the UDP connection on this localhost + // on port zero. After we bind to port zero we can read the port. + final_recv_socket.reset(new UDPSocket(child_processes_inherit, error)); + if (error.Success()) + { + // Socket was created, now lets bind to the requested port + SocketAddress addr; + addr.SetToAnyAddress (AF_INET, 0); + + if (::bind (final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) == -1) + { + // Bind failed... + SetLastError (error); + } + } + + assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid())); + if (error.Fail()) + return error; + + // At this point we have setup the receive port, now we need to + // setup the UDP send socket + + struct addrinfo hints; + struct addrinfo *service_info_list = nullptr; + + ::memset (&hints, 0, sizeof(hints)); + hints.ai_family = kDomain; + hints.ai_socktype = kType; + int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list); + if (err != 0) + { + error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", + host_str.c_str(), + port_str.c_str(), + err, + gai_strerror(err)); + return error; + } + + for (struct addrinfo *service_info_ptr = service_info_list; + service_info_ptr != nullptr; + service_info_ptr = service_info_ptr->ai_next) + { + auto send_fd = CreateSocket (service_info_ptr->ai_family, + service_info_ptr->ai_socktype, + service_info_ptr->ai_protocol, + child_processes_inherit, + error); + if (error.Success()) + { + final_send_socket.reset(new UDPSocket(send_fd)); + final_send_socket->m_send_sockaddr = service_info_ptr; + break; + } + else + continue; + } + + :: freeaddrinfo (service_info_list); + + if (!final_send_socket) + return error; + + send_socket = final_send_socket.release(); + recv_socket = final_recv_socket.release(); + error.Clear(); + return error; +} |