ovyalov updated this revision to Diff 37525. ovyalov marked 3 inline comments as done. ovyalov added a comment.
Addressed review suggestions. Please take another look. http://reviews.llvm.org/D13754 Files: include/lldb/Host/Socket.h include/lldb/Host/common/TCPSocket.h include/lldb/Host/common/UDPSocket.h include/lldb/Host/posix/DomainSocket.h lldb.xcodeproj/project.pbxproj source/Host/CMakeLists.txt source/Host/common/Socket.cpp source/Host/common/TCPSocket.cpp source/Host/common/UDPSocket.cpp source/Host/posix/ConnectionFileDescriptorPosix.cpp source/Host/posix/DomainSocket.cpp source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp tools/lldb-server/lldb-platform.cpp unittests/Host/SocketTest.cpp
Index: unittests/Host/SocketTest.cpp =================================================================== --- unittests/Host/SocketTest.cpp +++ unittests/Host/SocketTest.cpp @@ -13,11 +13,20 @@ #include <eh.h> #endif +#include <cstdio> +#include <functional> #include <thread> #include "gtest/gtest.h" +#include "lldb/Host/Config.h" #include "lldb/Host/Socket.h" +#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/common/UDPSocket.h" + +#ifndef LLDB_DISABLE_POSIX +#include "lldb/Host/posix/DomainSocket.h" +#endif using namespace lldb_private; @@ -46,45 +55,40 @@ AcceptThread(Socket *listen_socket, const char *listen_remote_address, bool child_processes_inherit, Socket **accept_socket, Error *error) { - *error = listen_socket->BlockingAccept(listen_remote_address, child_processes_inherit, *accept_socket); + *error = listen_socket->Accept(listen_remote_address, child_processes_inherit, *accept_socket); } + template<typename SocketType> void - CreateConnectedSockets(std::unique_ptr<Socket> *a_up, std::unique_ptr<Socket> *b_up) + CreateConnectedSockets(const char *listen_remote_address, const std::function<std::string(const SocketType&)> &get_connect_addr, std::unique_ptr<SocketType> *a_up, std::unique_ptr<SocketType> *b_up) { - Predicate<uint16_t> port_predicate; - // Used when binding to port zero to wait for the thread - // that creates the socket, binds and listens to resolve - // the port number. - - port_predicate.SetValue(0, eBroadcastNever); - bool child_processes_inherit = false; - Socket *socket = nullptr; - const char *listen_remote_address = "localhost:0"; - Error error = Socket::TcpListen(listen_remote_address, child_processes_inherit, socket, &port_predicate); - std::unique_ptr<Socket> listen_socket_up(socket); - socket = nullptr; + Error error; + std::unique_ptr<SocketType> listen_socket_up(new SocketType(child_processes_inherit, error)); + EXPECT_FALSE(error.Fail()); + error = listen_socket_up->Listen(listen_remote_address, 5); EXPECT_FALSE(error.Fail()); - EXPECT_NE(nullptr, listen_socket_up.get()); EXPECT_TRUE(listen_socket_up->IsValid()); Error accept_error; Socket *accept_socket; std::thread accept_thread(AcceptThread, listen_socket_up.get(), listen_remote_address, child_processes_inherit, &accept_socket, &accept_error); - char connect_remote_address[64]; - snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", port_predicate.GetValue()); - error = Socket::TcpConnect(connect_remote_address, child_processes_inherit, socket); - a_up->reset(socket); - socket = nullptr; + std::string connect_remote_address = get_connect_addr(*listen_socket_up); + std::unique_ptr<SocketType> connect_socket_up(new SocketType(child_processes_inherit, error)); + EXPECT_FALSE(error.Fail()); + error = connect_socket_up->Connect(connect_remote_address.c_str()); + EXPECT_FALSE(error.Fail()); + EXPECT_TRUE(connect_socket_up->IsValid()); + + a_up->swap(connect_socket_up); EXPECT_TRUE(error.Success()); EXPECT_NE(nullptr, a_up->get()); EXPECT_TRUE((*a_up)->IsValid()); accept_thread.join(); - b_up->reset(accept_socket); + b_up->reset(static_cast<SocketType*>(accept_socket)); EXPECT_TRUE(accept_error.Success()); EXPECT_NE(nullptr, b_up->get()); EXPECT_TRUE((*b_up)->IsValid()); @@ -124,25 +128,74 @@ EXPECT_STREQ ("0", port_str.c_str ()); EXPECT_EQ (0, port); EXPECT_TRUE (error.Success ()); - } -TEST_F (SocketTest, Listen0ConnectAccept) +#ifndef LLDB_DISABLE_POSIX +TEST_F (SocketTest, DomainListen0ConnectAccept) { - std::unique_ptr<Socket> socket_a_up; - std::unique_ptr<Socket> socket_b_up; - CreateConnectedSockets (&socket_a_up, &socket_b_up); + char* file_name_str = tempnam(nullptr, nullptr); + EXPECT_NE (nullptr, file_name_str); + const std::string file_name(file_name_str); + free(file_name_str); + + std::unique_ptr<DomainSocket> socket_a_up; + std::unique_ptr<DomainSocket> socket_b_up; + CreateConnectedSockets<DomainSocket>(file_name.c_str(), + [=](const DomainSocket &) + { + return file_name; + }, + &socket_a_up, &socket_b_up); } +#endif -TEST_F (SocketTest, GetAddress) +TEST_F (SocketTest, TCPListen0ConnectAccept) { - std::unique_ptr<Socket> socket_a_up; - std::unique_ptr<Socket> socket_b_up; - CreateConnectedSockets (&socket_a_up, &socket_b_up); - + std::unique_ptr<TCPSocket> socket_a_up; + std::unique_ptr<TCPSocket> socket_b_up; + CreateConnectedSockets<TCPSocket>("127.0.0.1:0", + [=](const TCPSocket &s) + { + char connect_remote_address[64]; + snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber()); + return std::string(connect_remote_address); + }, + &socket_a_up, &socket_b_up); +} + +TEST_F (SocketTest, TCPGetAddress) +{ + std::unique_ptr<TCPSocket> socket_a_up; + std::unique_ptr<TCPSocket> socket_b_up; + CreateConnectedSockets<TCPSocket>("127.0.0.1:0", + [=](const TCPSocket &s) + { + char connect_remote_address[64]; + snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber()); + return std::string(connect_remote_address); + }, + &socket_a_up, + &socket_b_up); + EXPECT_EQ (socket_a_up->GetLocalPortNumber (), socket_b_up->GetRemotePortNumber ()); EXPECT_EQ (socket_b_up->GetLocalPortNumber (), socket_a_up->GetRemotePortNumber ()); EXPECT_NE (socket_a_up->GetLocalPortNumber (), socket_b_up->GetLocalPortNumber ()); EXPECT_STREQ ("127.0.0.1", socket_a_up->GetRemoteIPAddress ().c_str ()); EXPECT_STREQ ("127.0.0.1", socket_b_up->GetRemoteIPAddress ().c_str ()); } + +TEST_F (SocketTest, UDPConnect) +{ + Socket* socket_a; + Socket* socket_b; + + bool child_processes_inherit = false; + auto error = UDPSocket::Connect("127.0.0.1:0", child_processes_inherit, socket_a, socket_b); + + std::unique_ptr<Socket> a_up(socket_a); + std::unique_ptr<Socket> b_up(socket_b); + + EXPECT_TRUE(error.Success ()); + EXPECT_TRUE(a_up->IsValid()); + EXPECT_TRUE(b_up->IsValid()); +} Index: tools/lldb-server/lldb-platform.cpp =================================================================== --- tools/lldb-server/lldb-platform.cpp +++ tools/lldb-server/lldb-platform.cpp @@ -29,7 +29,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostGetOpt.h" #include "lldb/Host/OptionParser.h" -#include "lldb/Host/Socket.h" +#include "lldb/Host/common/TCPSocket.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" #include "LLDBServerUtilities.h" @@ -283,22 +283,26 @@ exit(option_error); } - std::unique_ptr<Socket> listening_socket_up; Socket *socket = nullptr; const bool children_inherit_listen_socket = false; // the test suite makes many connections in parallel, let's not miss any. // The highest this should get reasonably is a function of the number // of target CPUs. For now, let's just use 100 const int backlog = 100; - error = Socket::TcpListen(listen_host_port.c_str(), children_inherit_listen_socket, socket, NULL, backlog); + std::unique_ptr<TCPSocket> listening_socket_up(new TCPSocket(children_inherit_listen_socket, error)); + if (error.Fail()) + { + fprintf(stderr, "failed to create socket: %s", error.AsCString()); + exit(socket_error); + } + + error = listening_socket_up->Listen(listen_host_port.c_str(), backlog); if (error.Fail()) { printf("error: %s\n", error.AsCString()); exit(socket_error); } - listening_socket_up.reset(socket); - printf ("Listening for a connection from %u...\n", listening_socket_up->GetLocalPortNumber()); if (port_file) { error = save_port_to_file(listening_socket_up->GetLocalPortNumber(), port_file); @@ -322,7 +326,7 @@ const bool children_inherit_accept_socket = true; socket = nullptr; - error = listening_socket_up->BlockingAccept(listen_host_port.c_str(), children_inherit_accept_socket, socket); + error = listening_socket_up->Accept(listen_host_port.c_str(), children_inherit_accept_socket, socket); if (error.Fail()) { printf ("error: %s\n", error.AsCString()); Index: source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp =================================================================== --- source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -24,8 +24,8 @@ #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" #include "lldb/Host/Symbols.h" -#include "lldb/Host/Socket.h" #include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/common/TCPSocket.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" @@ -276,7 +276,7 @@ if (conn_ap->IsConnected()) { - const Socket& socket = static_cast<const Socket&>(*conn_ap->GetReadObject()); + const TCPSocket& socket = static_cast<const TCPSocket&>(*conn_ap->GetReadObject()); const uint16_t reply_port = socket.GetLocalPortNumber(); if (reply_port != 0) Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -10,9 +10,7 @@ // Other libraries and framework includes #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" -#include "lldb/Host/Socket.h" - -// Project includes +#include "lldb/Host/common/TCPSocket.h" #include "AdbClient.h" #include "PlatformAndroidRemoteGDBServer.h" #include "Utility/UriParser.h" @@ -52,13 +50,15 @@ static Error FindUnusedPort (uint16_t& port) { - Socket* socket = nullptr; - auto error = Socket::TcpListen ("127.0.0.1:0", false, socket, nullptr); - if (error.Success ()) - { - port = socket->GetLocalPortNumber (); - delete socket; - } + Error error; + std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(false, error)); + if (error.Fail()) + return error; + + error = tcp_socket->Listen("127.0.0.1:0", 1); + if (error.Success()) + port = tcp_socket->GetLocalPortNumber(); + return error; } Index: source/Host/posix/DomainSocket.cpp =================================================================== --- /dev/null +++ source/Host/posix/DomainSocket.cpp @@ -0,0 +1,93 @@ +//===-- DomainSocket.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/posix/DomainSocket.h" + +#include "lldb/Host/FileSystem.h" + +#include <sys/socket.h> +#include <sys/un.h> + +using namespace lldb; +using namespace lldb_private; + +#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 { + +const int kDomain = AF_UNIX; +const int kType = SOCK_STREAM; + +void SetSockAddr(llvm::StringRef name, sockaddr_un* saddr_un) +{ + saddr_un->sun_family = kDomain; + ::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 +} + +} + +DomainSocket::DomainSocket(NativeSocket socket) + : Socket(socket, ProtocolUnixDomain, true) +{ +} + +DomainSocket::DomainSocket(bool child_processes_inherit, Error &error) + : DomainSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) +{ +} + +Error +DomainSocket::Connect(llvm::StringRef name) +{ + sockaddr_un saddr_un; + SetSockAddr(name, &saddr_un); + + Error error; + if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) + SetLastError (error); + + return error; +} + +Error +DomainSocket::Listen(llvm::StringRef name, int backlog) +{ + sockaddr_un saddr_un; + SetSockAddr(name, &saddr_un); + + FileSystem::Unlink(FileSpec{name, true}); + + Error error; + if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0) + if (::listen(GetNativeSocket(), backlog) == 0) + return error; + + SetLastError(error); + return error; +} + +Error +DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) +{ + Error error; + auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, child_processes_inherit, error); + if (error.Success()) + socket = new DomainSocket(conn_fd); + + return error; +} Index: source/Host/posix/ConnectionFileDescriptorPosix.cpp =================================================================== --- source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -47,6 +47,7 @@ #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Host/Socket.h" +#include "lldb/Host/common/TCPSocket.h" #include "lldb/Interpreter/Args.h" #include "Utility/UriParser.h" @@ -233,8 +234,8 @@ // allow us to specify this. For now, we assume we must // assume we don't own it. - std::unique_ptr<Socket> tcp_socket; - tcp_socket.reset(new Socket(fd, Socket::ProtocolTcp, false)); + std::unique_ptr<TCPSocket> tcp_socket; + tcp_socket.reset(new TCPSocket(fd, false)); // Try and get a socket option from this file descriptor to // see if this is a socket and set m_is_socket accordingly. int resuse; @@ -790,7 +791,7 @@ listening_socket_up.reset(socket); socket = nullptr; - error = listening_socket_up->BlockingAccept(s, m_child_processes_inherit, socket); + error = listening_socket_up->Accept(s, m_child_processes_inherit, socket); listening_socket_up.reset(); if (error_ptr) *error_ptr = error; @@ -866,9 +867,12 @@ void ConnectionFileDescriptor::InitializeSocket(Socket* socket) { + assert(socket->GetSocketProtocol() == Socket::ProtocolTcp); + TCPSocket* tcp_socket = static_cast<TCPSocket*>(socket); + m_write_sp.reset(socket); m_read_sp = m_write_sp; StreamString strm; - strm.Printf("connect://%s:%u",socket->GetRemoteIPAddress().c_str(), socket->GetRemotePortNumber()); + strm.Printf("connect://%s:%u",tcp_socket->GetRemoteIPAddress().c_str(), tcp_socket->GetRemotePortNumber()); m_uri.swap(strm.GetString()); } Index: source/Host/common/UDPSocket.cpp =================================================================== --- /dev/null +++ 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; +} Index: source/Host/common/TCPSocket.cpp =================================================================== --- /dev/null +++ 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); +} Index: source/Host/common/Socket.cpp =================================================================== --- source/Host/common/Socket.cpp +++ 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 @@ 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 @@ 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 @@ 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 @@ // 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 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 @@ 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 @@ { 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; } Index: source/Host/CMakeLists.txt =================================================================== --- source/Host/CMakeLists.txt +++ source/Host/CMakeLists.txt @@ -34,11 +34,13 @@ common/SoftwareBreakpoint.cpp common/StringConvert.cpp common/Symbols.cpp + common/TCPSocket.cpp common/Terminal.cpp common/ThisThread.cpp common/ThreadLauncher.cpp common/TimeValue.cpp common/XML.cpp + common/UDPSocket.cpp ) # Keep track of whether we want to provide a define for the @@ -81,6 +83,7 @@ endif() add_host_subdirectory(posix + posix/DomainSocket.cpp posix/FileSystem.cpp posix/HostInfoPosix.cpp posix/HostProcessPosix.cpp Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -100,6 +100,9 @@ 256CBDBA1ADD107200BC6CDC /* RegisterContextLinux_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 256CBDB61ADD107200BC6CDC /* RegisterContextLinux_arm.cpp */; }; 256CBDBC1ADD107200BC6CDC /* RegisterContextLinux_mips64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 256CBDB81ADD107200BC6CDC /* RegisterContextLinux_mips64.cpp */; }; 256CBDC01ADD11C000BC6CDC /* RegisterContextPOSIX_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 256CBDBE1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.cpp */; }; + 2579065C1BD0488100178368 /* TCPSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2579065A1BD0488100178368 /* TCPSocket.cpp */; }; + 2579065D1BD0488100178368 /* UDPSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2579065B1BD0488100178368 /* UDPSocket.cpp */; }; + 2579065F1BD0488D00178368 /* DomainSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2579065E1BD0488D00178368 /* DomainSocket.cpp */; }; 257E47171AA56C2000A62F81 /* ModuleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 257E47151AA56C2000A62F81 /* ModuleCache.cpp */; }; 25EF23781AC09B3700908DF0 /* AdbClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25EF23751AC09AD800908DF0 /* AdbClient.cpp */; }; 260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; @@ -713,8 +716,8 @@ 6D95DC001B9DC057000E318A /* DIERef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D95DBFD1B9DC057000E318A /* DIERef.cpp */; }; 6D95DC011B9DC057000E318A /* HashedNameToDIE.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D95DBFE1B9DC057000E318A /* HashedNameToDIE.cpp */; }; 6D95DC021B9DC057000E318A /* SymbolFileDWARFDwo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D95DBFF1B9DC057000E318A /* SymbolFileDWARFDwo.cpp */; }; - 6D9AB3DD1BB2B74E003F2289 /* TypeMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D9AB3DC1BB2B74E003F2289 /* TypeMap.cpp */; }; 6D99A3631BBC2F3200979793 /* ArmUnwindInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D99A3621BBC2F3200979793 /* ArmUnwindInfo.cpp */; }; + 6D9AB3DD1BB2B74E003F2289 /* TypeMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D9AB3DC1BB2B74E003F2289 /* TypeMap.cpp */; }; 8C2D6A53197A1EAF006989C9 /* MemoryHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */; }; 8C2D6A5E197A250F006989C9 /* MemoryHistoryASan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */; }; 8CCB017E19BA28A80009FD44 /* ThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */; }; @@ -1198,6 +1201,9 @@ 256CBDB91ADD107200BC6CDC /* RegisterContextLinux_mips64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextLinux_mips64.h; path = Utility/RegisterContextLinux_mips64.h; sourceTree = "<group>"; }; 256CBDBE1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextPOSIX_arm.cpp; path = Utility/RegisterContextPOSIX_arm.cpp; sourceTree = "<group>"; }; 256CBDBF1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextPOSIX_arm.h; path = Utility/RegisterContextPOSIX_arm.h; sourceTree = "<group>"; }; + 2579065A1BD0488100178368 /* TCPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TCPSocket.cpp; sourceTree = "<group>"; }; + 2579065B1BD0488100178368 /* UDPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UDPSocket.cpp; sourceTree = "<group>"; }; + 2579065E1BD0488D00178368 /* DomainSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DomainSocket.cpp; sourceTree = "<group>"; }; 257E47151AA56C2000A62F81 /* ModuleCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleCache.cpp; path = source/Utility/ModuleCache.cpp; sourceTree = "<group>"; }; 257E47161AA56C2000A62F81 /* ModuleCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleCache.h; path = source/Utility/ModuleCache.h; sourceTree = "<group>"; }; 25EF23751AC09AD800908DF0 /* AdbClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdbClient.cpp; sourceTree = "<group>"; }; @@ -2407,10 +2413,10 @@ 6D95DBFF1B9DC057000E318A /* SymbolFileDWARFDwo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolFileDWARFDwo.cpp; sourceTree = "<group>"; }; 6D95DC031B9DC06F000E318A /* DIERef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DIERef.h; sourceTree = "<group>"; }; 6D95DC041B9DC06F000E318A /* SymbolFileDWARFDwo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolFileDWARFDwo.h; sourceTree = "<group>"; }; - 6D9AB3DC1BB2B74E003F2289 /* TypeMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeMap.cpp; path = source/Symbol/TypeMap.cpp; sourceTree = "<group>"; }; - 6D9AB3DE1BB2B76B003F2289 /* TypeMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeMap.h; path = include/lldb/Symbol/TypeMap.h; sourceTree = "<group>"; }; 6D99A3611BBC2F1600979793 /* ArmUnwindInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ArmUnwindInfo.h; path = include/lldb/Symbol/ArmUnwindInfo.h; sourceTree = "<group>"; }; 6D99A3621BBC2F3200979793 /* ArmUnwindInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ArmUnwindInfo.cpp; path = source/Symbol/ArmUnwindInfo.cpp; sourceTree = "<group>"; }; + 6D9AB3DC1BB2B74E003F2289 /* TypeMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeMap.cpp; path = source/Symbol/TypeMap.cpp; sourceTree = "<group>"; }; + 6D9AB3DE1BB2B76B003F2289 /* TypeMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeMap.h; path = include/lldb/Symbol/TypeMap.h; sourceTree = "<group>"; }; 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MemoryHistory.cpp; path = source/Target/MemoryHistory.cpp; sourceTree = "<group>"; }; 8C2D6A54197A1EBE006989C9 /* MemoryHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MemoryHistory.h; path = include/lldb/Target/MemoryHistory.h; sourceTree = "<group>"; }; 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryHistoryASan.cpp; sourceTree = "<group>"; }; @@ -5018,6 +5024,7 @@ 3FDFDDC4199D37BE009756A7 /* posix */ = { isa = PBXGroup; children = ( + 2579065E1BD0488D00178368 /* DomainSocket.cpp */, 255EFF751AFABA950069F277 /* LockFilePosix.cpp */, 30DED5DC1B4ECB17004CC508 /* MainLoopPosix.cpp */, AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp */, @@ -5224,6 +5231,8 @@ 69A01E1A1236C5D400C660B5 /* common */ = { isa = PBXGroup; children = ( + 2579065A1BD0488100178368 /* TCPSocket.cpp */, + 2579065B1BD0488100178368 /* UDPSocket.cpp */, 255EFF731AFABA720069F277 /* LockFileBase.cpp */, 250D6AE11A9679270049CC70 /* FileSystem.cpp */, 33E5E8411A672A240024ED68 /* StringConvert.cpp */, @@ -6421,6 +6430,7 @@ 2689008D13353E4200698AC0 /* DynamicLoaderMacOSXDYLD.cpp in Sources */, 2689008E13353E4200698AC0 /* DynamicLoaderStatic.cpp in Sources */, 2689009613353E4200698AC0 /* ObjectContainerBSDArchive.cpp in Sources */, + 2579065D1BD0488100178368 /* UDPSocket.cpp in Sources */, AE8F624919EF3E1E00326B21 /* OperatingSystemGo.cpp in Sources */, 26BC179A18C7F2B300D2196D /* JITLoaderList.cpp in Sources */, 2689009713353E4200698AC0 /* ObjectContainerUniversalMachO.cpp in Sources */, @@ -6490,6 +6500,7 @@ 268900D313353E6F00698AC0 /* ClangExternalASTSourceCallbacks.cpp in Sources */, 268900D513353E6F00698AC0 /* CompileUnit.cpp in Sources */, 268900D613353E6F00698AC0 /* Declaration.cpp in Sources */, + 2579065C1BD0488100178368 /* TCPSocket.cpp in Sources */, 268900D713353E6F00698AC0 /* DWARFCallFrameInfo.cpp in Sources */, 268900D813353E6F00698AC0 /* Function.cpp in Sources */, 268900D913353E6F00698AC0 /* FuncUnwinders.cpp in Sources */, @@ -6548,6 +6559,7 @@ 94B6385D1B8FB178004FE1E4 /* CPlusPlusLanguage.cpp in Sources */, 268900FE13353E6F00698AC0 /* ThreadPlanCallUserExpression.cpp in Sources */, 268900FF13353E6F00698AC0 /* ThreadPlanShouldStopHere.cpp in Sources */, + 2579065F1BD0488D00178368 /* DomainSocket.cpp in Sources */, 2689010013353E6F00698AC0 /* ThreadPlanStepInstruction.cpp in Sources */, 232CB61B191E00CD00EF39FC /* NativeThreadProtocol.cpp in Sources */, 2689010113353E6F00698AC0 /* ThreadPlanStepOut.cpp in Sources */, Index: include/lldb/Host/posix/DomainSocket.h =================================================================== --- /dev/null +++ include/lldb/Host/posix/DomainSocket.h @@ -0,0 +1,30 @@ +//===-- DomainSocket.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DomainSocket_h_ +#define liblldb_DomainSocket_h_ + +#include "lldb/Host/Socket.h" + +namespace lldb_private +{ + class DomainSocket: public Socket + { + public: + DomainSocket(bool child_processes_inherit, Error &error); + + Error Connect(llvm::StringRef name) override; + Error Listen(llvm::StringRef name, int backlog) override; + Error Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) override; + private: + DomainSocket(NativeSocket socket); + }; +} + +#endif // ifndef liblldb_DomainSocket_h_ Index: include/lldb/Host/common/UDPSocket.h =================================================================== --- /dev/null +++ include/lldb/Host/common/UDPSocket.h @@ -0,0 +1,35 @@ +//===-- UDPSocket.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UDPSocket_h_ +#define liblldb_UDPSocket_h_ + +#include "lldb/Host/Socket.h" + +namespace lldb_private +{ + class UDPSocket: public Socket + { + public: + static Error Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket); + + private: + UDPSocket(NativeSocket socket); + UDPSocket(bool child_processes_inherit, Error &error); + + size_t Send(const void *buf, const size_t num_bytes) override; + Error Connect(llvm::StringRef name) override; + Error Listen(llvm::StringRef name, int backlog) override; + Error Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) override; + + SocketAddress m_send_sockaddr; + }; +} + +#endif // ifndef liblldb_UDPSocket_h_ Index: include/lldb/Host/common/TCPSocket.h =================================================================== --- /dev/null +++ include/lldb/Host/common/TCPSocket.h @@ -0,0 +1,46 @@ +//===-- TCPSocket.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_TCPSocket_h_ +#define liblldb_TCPSocket_h_ + +#include "lldb/Host/Socket.h" + +namespace lldb_private +{ + class TCPSocket: public Socket + { + public: + TCPSocket(NativeSocket socket, bool should_close); + TCPSocket(bool child_processes_inherit, Error &error); + + // returns port number or 0 if error + uint16_t GetLocalPortNumber () const; + + // returns ip address string or empty string if error + std::string GetLocalIPAddress () const; + + // must be connected + // returns port number or 0 if error + uint16_t GetRemotePortNumber () const; + + // must be connected + // returns ip address string or empty string if error + std::string GetRemoteIPAddress () const; + + int SetOptionNoDelay(); + int SetOptionReuseAddress(); + + Error Connect(llvm::StringRef name) override; + Error Listen(llvm::StringRef name, int backlog) override; + Error Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&conn_socket) override; + }; +} + +#endif // ifndef liblldb_TCPSocket_h_ Index: include/lldb/Host/Socket.h =================================================================== --- include/lldb/Host/Socket.h +++ include/lldb/Host/Socket.h @@ -50,9 +50,12 @@ static const NativeSocket kInvalidSocketValue; - Socket(NativeSocket socket, SocketProtocol protocol, bool should_close); ~Socket() override; + virtual Error Connect(llvm::StringRef name) = 0; + virtual Error Listen(llvm::StringRef name, int backlog) = 0; + virtual Error Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) = 0; + // Initialize a Tcp Socket object in listening mode. listen and accept are implemented // separately because the caller may wish to manipulate or query the socket after it is // initialized, but before entering a blocking accept. @@ -67,31 +70,9 @@ static Error UnixDomainConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket); static Error UnixDomainAccept(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket); - // Blocks on a listening socket until a connection is received. This method assumes that - // |this->m_socket| is a listening socket, created via either TcpListen() or via the native - // constructor that takes a NativeSocket, which itself was created via a call to |listen()| - Error BlockingAccept(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket); - int GetOption (int level, int option_name, int &option_value); int SetOption (int level, int option_name, int option_value); - // returns port number or 0 if error - static uint16_t GetLocalPortNumber (const NativeSocket& socket); - - // returns port number or 0 if error - uint16_t GetLocalPortNumber () const; - - // returns ip address string or empty string if error - std::string GetLocalIPAddress () const; - - // must be connected - // returns port number or 0 if error - uint16_t GetRemotePortNumber () const; - - // must be connected - // returns ip address string or empty string if error - std::string GetRemoteIPAddress () const; - NativeSocket GetNativeSocket () const { return m_socket; } SocketProtocol GetSocketProtocol () const { return m_protocol; } @@ -112,9 +93,18 @@ Error *error_ptr); protected: + Socket(NativeSocket socket, SocketProtocol protocol, bool should_close); + + virtual size_t Send(const void *buf, const size_t num_bytes); + + static void SetLastError(Error &error); + static NativeSocket CreateSocket( + const int domain, const int type, const int protocol, bool child_processes_inherit, Error& error); + static NativeSocket AcceptSocket( + NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, bool child_processes_inherit, Error& error); + SocketProtocol m_protocol; NativeSocket m_socket; - SocketAddress m_udp_send_sockaddr; // Send address used for UDP connections. }; } // namespace lldb_private
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits