Index: include/lldb/Host/Socket.h =================================================================== --- include/lldb/Host/Socket.h +++ include/lldb/Host/Socket.h @@ -57,8 +57,7 @@ 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; + virtual Error Accept(Socket *&socket) = 0; // Initialize a Tcp Socket object in listening mode. listen and accept are // implemented @@ -103,7 +102,8 @@ int32_t &port, Error *error_ptr); protected: - Socket(NativeSocket socket, SocketProtocol protocol, bool should_close); + Socket(SocketProtocol protocol, bool should_close, + bool m_child_process_inherit); virtual size_t Send(const void *buf, const size_t num_bytes); @@ -117,6 +117,7 @@ SocketProtocol m_protocol; NativeSocket m_socket; + bool m_child_processes_inherit; }; } // namespace lldb_private Index: include/lldb/Host/common/TCPSocket.h =================================================================== --- include/lldb/Host/common/TCPSocket.h +++ include/lldb/Host/common/TCPSocket.h @@ -11,12 +11,16 @@ #define liblldb_TCPSocket_h_ #include "lldb/Host/Socket.h" +#include "lldb/Host/SocketAddress.h" +#include namespace lldb_private { class TCPSocket : public Socket { public: - TCPSocket(NativeSocket socket, bool should_close); - TCPSocket(bool child_processes_inherit, Error &error); + TCPSocket(bool should_close, bool child_processes_inherit); + TCPSocket(NativeSocket socket, bool should_close, + bool child_processes_inherit); + ~TCPSocket(); // returns port number or 0 if error uint16_t GetLocalPortNumber() const; @@ -37,8 +41,18 @@ 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; + Error Accept(Socket *&conn_socket) override; + + Error CreateSocket(int domain); + + bool IsValid() const override; + +private: + TCPSocket(NativeSocket socket, const TCPSocket &listen_socket); + + void CloseListenSockets(); + + std::map m_listen_sockets; }; } Index: include/lldb/Host/common/UDPSocket.h =================================================================== --- include/lldb/Host/common/UDPSocket.h +++ include/lldb/Host/common/UDPSocket.h @@ -15,19 +15,20 @@ namespace lldb_private { class UDPSocket : public Socket { public: - UDPSocket(bool child_processes_inherit, Error &error); + UDPSocket(bool should_close, bool child_processes_inherit); static Error Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket); private: - UDPSocket(NativeSocket socket); + UDPSocket(NativeSocket socket, const UDPSocket &listen_socket); 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; + Error Accept(Socket *&socket) override; + + Error CreateSocket(); SocketAddress m_sockaddr; }; Index: include/lldb/Host/freebsd/Config.h =================================================================== --- include/lldb/Host/freebsd/Config.h +++ include/lldb/Host/freebsd/Config.h @@ -25,4 +25,7 @@ //#define LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 1 +// FIXME: This should be set by a configure-time check. +#define HAVE_SYS_EVENT_H 1 + #endif // #ifndef liblldb_Platform_Config_h_ Index: include/lldb/Host/linux/AbstractSocket.h =================================================================== --- include/lldb/Host/linux/AbstractSocket.h +++ include/lldb/Host/linux/AbstractSocket.h @@ -15,7 +15,7 @@ namespace lldb_private { class AbstractSocket : public DomainSocket { public: - AbstractSocket(bool child_processes_inherit, Error &error); + AbstractSocket(bool child_processes_inherit); protected: size_t GetNameOffset() const override; Index: include/lldb/Host/macosx/Config.h =================================================================== --- include/lldb/Host/macosx/Config.h +++ include/lldb/Host/macosx/Config.h @@ -14,8 +14,8 @@ // platform functionality availability. //---------------------------------------------------------------------- -#ifndef liblldb_Platform_Config_h_ -#define liblldb_Platform_Config_h_ +#ifndef LLDB_HOST_MACOSX_CONFIG_H +#define LLDB_HOST_MACOSX_CONFIG_H #define LLDB_CONFIG_TERMIOS_SUPPORTED 1 @@ -25,4 +25,7 @@ #define LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 1 -#endif // #ifndef liblldb_Platform_Config_h_ +// FIXME: This should be set by a configure-time check. +#define HAVE_SYS_EVENT_H 1 + +#endif // LLDB_HOST_MACOSX_CONFIG_H Index: include/lldb/Host/posix/DomainSocket.h =================================================================== --- include/lldb/Host/posix/DomainSocket.h +++ include/lldb/Host/posix/DomainSocket.h @@ -15,22 +15,20 @@ namespace lldb_private { class DomainSocket : public Socket { public: - DomainSocket(bool child_processes_inherit, Error &error); + DomainSocket(bool should_close, bool child_processes_inherit); 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; + Error Accept(Socket *&socket) override; protected: - DomainSocket(SocketProtocol protocol, bool child_processes_inherit, - Error &error); + DomainSocket(SocketProtocol protocol, bool child_processes_inherit); virtual size_t GetNameOffset() const; virtual void DeleteSocketFile(llvm::StringRef name); private: - DomainSocket(NativeSocket socket); + DomainSocket(NativeSocket socket, const DomainSocket &listen_socket); }; } Index: source/Host/common/Socket.cpp =================================================================== --- source/Host/common/Socket.cpp +++ source/Host/common/Socket.cpp @@ -67,9 +67,11 @@ } } -Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close) +Socket::Socket(SocketProtocol protocol, bool should_close, + bool child_processes_inherit) : IOObject(eFDTypeSocket, should_close), m_protocol(protocol), - m_socket(socket) {} + m_socket(kInvalidSocketValue), + m_child_processes_inherit(child_processes_inherit) {} Socket::~Socket() { Close(); } @@ -81,14 +83,14 @@ std::unique_ptr socket_up; switch (protocol) { case ProtocolTcp: - socket_up.reset(new TCPSocket(child_processes_inherit, error)); + socket_up.reset(new TCPSocket(true, child_processes_inherit)); break; case ProtocolUdp: - socket_up.reset(new UDPSocket(child_processes_inherit, error)); + socket_up.reset(new UDPSocket(true, child_processes_inherit)); break; case ProtocolUnixDomain: #ifndef LLDB_DISABLE_POSIX - socket_up.reset(new DomainSocket(child_processes_inherit, error)); + socket_up.reset(new DomainSocket(true, child_processes_inherit)); #else error.SetErrorString( "Unix domain sockets are not supported on this platform."); @@ -96,7 +98,7 @@ break; case ProtocolUnixAbstract: #ifdef __linux__ - socket_up.reset(new AbstractSocket(child_processes_inherit, error)); + socket_up.reset(new AbstractSocket(true, child_processes_inherit)); #else error.SetErrorString( "Abstract domain sockets are not supported on this platform."); @@ -145,7 +147,7 @@ return error; std::unique_ptr listen_socket( - new TCPSocket(child_processes_inherit, error)); + new TCPSocket(child_processes_inherit, true)); if (error.Fail()) return error; @@ -208,7 +210,7 @@ if (error.Fail()) return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = listen_socket->Accept(socket); return error; } @@ -240,18 +242,22 @@ if (error.Fail()) return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = listen_socket->Accept(socket); return error; } bool Socket::DecodeHostAndPort(llvm::StringRef host_and_port, std::string &host_str, std::string &port_str, int32_t &port, Error *error_ptr) { - static RegularExpression g_regex(llvm::StringRef("([^:]+):([0-9]+)")); + static RegularExpression g_regex( + llvm::StringRef("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)")); RegularExpression::Match regex_match(2); if (g_regex.Execute(host_and_port, ®ex_match)) { if (regex_match.GetMatchAtIndex(host_and_port.data(), 1, host_str) && regex_match.GetMatchAtIndex(host_and_port.data(), 2, port_str)) { + // IPv6 addresses are wrapped in [] when specified with ports + if (host_str.front() == '[' && host_str.back() == ']') + host_str = host_str.substr(1, host_str.size() - 2); bool ok = false; port = StringConvert::ToUInt32(port_str.c_str(), UINT32_MAX, 10, &ok); if (ok && port <= UINT16_MAX) { @@ -404,12 +410,12 @@ const int protocol, bool child_processes_inherit, Error &error) { error.Clear(); - auto socketType = type; + auto socket_type = type; #ifdef SOCK_CLOEXEC if (!child_processes_inherit) - socketType |= SOCK_CLOEXEC; + socket_type |= SOCK_CLOEXEC; #endif - auto sock = ::socket(domain, socketType, protocol); + auto sock = ::socket(domain, socket_type, protocol); if (sock == kInvalidSocketValue) SetLastError(error); Index: source/Host/common/TCPSocket.cpp =================================================================== --- source/Host/common/TCPSocket.cpp +++ source/Host/common/TCPSocket.cpp @@ -22,22 +22,43 @@ #include #endif +// If kqueue(2) is available we prefer that over select(2). I believe that we +// only have kqueue(2) on Darwin and FreeBSD. +#if HAVE_SYS_EVENT_H +#include +#elif defined(_WIN32) +#include +#else +#include +#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 should_close, bool child_processes_inherit) + : Socket(ProtocolTcp, should_close, child_processes_inherit) {} + +TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket) + : Socket(ProtocolTcp, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} + +TCPSocket::TCPSocket(NativeSocket socket, bool should_close, + bool child_processes_inherit) + : Socket(ProtocolTcp, should_close, child_processes_inherit) { + m_socket = socket; +} + +TCPSocket::~TCPSocket() { CloseListenSockets(); } -TCPSocket::TCPSocket(bool child_processes_inherit, Error &error) - : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP, - child_processes_inherit, error), - true) {} +bool TCPSocket::IsValid() const { + return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0; +} // Return the port number that is being used by the socket. uint16_t TCPSocket::GetLocalPortNumber() const { @@ -46,6 +67,12 @@ socklen_t sock_addr_len = sock_addr.GetMaxLength(); if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) return sock_addr.GetPort(); + } else if (!m_listen_sockets.empty()) { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength(); + if (::getsockname(m_listen_sockets.begin()->first, sock_addr, + &sock_addr_len) == 0) + return sock_addr.GetPort(); } return 0; } @@ -84,9 +111,18 @@ return ""; } +Error TCPSocket::CreateSocket(int domain) { + Error error; + if (IsValid()) + error = Close(); + if (error.Fail()) + return error; + m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP, + m_child_processes_inherit, error); + return error; +} + Error TCPSocket::Connect(llvm::StringRef name) { - if (m_socket == kInvalidSocketValue) - return Error("Invalid socket"); Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); if (log) @@ -99,146 +135,199 @@ if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) return error; - struct sockaddr_in sa; - ::memset(&sa, 0, sizeof(sa)); - sa.sin_family = kDomain; - sa.sin_port = htons(port); - - int inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr); - - if (inet_pton_result <= 0) { - struct hostent *host_entry = gethostbyname(host_str.c_str()); - if (host_entry) - host_str = ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list); - inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr); - if (inet_pton_result <= 0) { - if (inet_pton_result == -1) - SetLastError(error); - else - error.SetErrorStringWithFormat("invalid host string: '%s'", - host_str.c_str()); + auto addresses = + lldb_private::SocketAddress::GetAddressInfo(host_str.c_str(), NULL); + for (auto address : addresses) { + error = CreateSocket(address.GetFamily()); + if (error.Fail()) + continue; + + address.SetPort(port); - return error; + if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(), + address.GetLength())) { + continue; } - } - if (-1 == - ::connect(GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) { - SetLastError(error); + SetOptionNoDelay(); + + error.Clear(); return error; } - // Keep our TCP packets coming without any delays. - SetOptionNoDelay(); - error.Clear(); + error.SetErrorString("Failed to connect port"); return error; } Error TCPSocket::Listen(llvm::StringRef name, int backlog) { - Error error; - - // enable local address reuse - SetOptionReuseAddress(); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data()); + Error error; std::string host_str; std::string port_str; int32_t port = INT32_MIN; if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) return error; - SocketAddress bind_addr; + auto addresses = + lldb_private::SocketAddress::GetAddressInfo(host_str.c_str(), NULL); + for (auto address : addresses) { + int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, + m_child_processes_inherit, error); + if (error.Fail()) { + error.Clear(); + continue; + } - // 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); + // enable local address reuse + SetOptionReuseAddress(); - if (!bind_addr_success) { - error.SetErrorString("Failed to bind port"); - return error; - } + address.SetPort(port); + + int err = ::bind(fd, &address.sockaddr(), address.GetLength()); + if (-1 != err) + err = ::listen(fd, backlog); - int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength()); - if (err != -1) - err = ::listen(GetNativeSocket(), backlog); + if (-1 == err) { +#if defined(_WIN32) + closesocket(fd); +#else + ::close(fd); +#endif + continue; + } - if (err == -1) - SetLastError(error); + if (port == 0) { + socklen_t sa_len = address.GetLength(); + if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) + port = address.GetPort(); + } + m_listen_sockets[fd] = address; + } + if (m_listen_sockets.size() == 0) + error.SetErrorString("Failed to connect port"); return error; } -Error TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&conn_socket) { +void TCPSocket::CloseListenSockets() { + for (auto socket : m_listen_sockets) +#if defined(_WIN32) + closesocket(socket.first); +#else + ::close(socket.first); +#endif + m_listen_sockets.clear(); +} + +Error TCPSocket::Accept(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)) + if (m_listen_sockets.size() == 0) { + error.SetErrorString("No open listening sockets!"); 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 accepted_socket; +#if HAVE_SYS_EVENT_H + + int queue_id = kqueue(); + if (queue_id < 0) { + error.SetErrorString("error: failed to create kqueue."); + return error; + } + + std::vector events; + events.resize(m_listen_sockets.size()); + int i = 0; + for (auto socket: m_listen_sockets) { + EV_SET(&events[i++], socket.first, EVFILT_READ, EV_ADD, 0, 0, 0); + } +#else + std::vector sock_set; + + int nfds = 0; + for (auto socket : m_listen_sockets) { + struct pollfd sock_fd; + sock_fd.fd = socket.first; + sock_fd.events = POLLIN | POLLERR; + sock_fd.revents = 0; + sock_set.push_back(sock_fd); + } +#endif + // 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; + int sock_fd = -1; +#if HAVE_SYS_EVENT_H + struct kevent event_list[4]; + int num_events = + kevent(queue_id, events.data(), events.size(), event_list, 4, NULL); + + if (num_events < 0) { + error.SetErrorString("error: kevent() failed."); + return error; + } + + for (int i = 0; i < num_events; ++i) { + auto socket_pair = m_listen_sockets.find(event_list[i].ident); + if (socket_pair == m_listen_sockets.end()) + continue; + sock_fd = event_list[i].ident; + } +#else + +#if defined(_WIN32) + int retval = WSAPoll(sock_set.data(), sock_set.size(), 1000); +#else + int retval = poll(sock_set.data(), sock_set.size(), 1000); +#endif + if (retval == -1) + break; + if (retval == 0) + continue; + + for (auto socket : sock_set) { + if ((socket.revents & POLLERR) != 0) { + error.SetErrorString("Socket error encountered"); + return error; + } + + if ((socket.revents & POLLIN) == 0) + continue; + sock_fd = socket.fd; + break; + } #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(-1 == sock_fd) + continue; + lldb_private::SocketAddress AccptAddr; + socklen_t sa_len = AccptAddr.GetMaxLength(); + int sock = AcceptSocket(sock_fd, &AccptAddr.sockaddr(), &sa_len, + m_child_processes_inherit, error); if (error.Fail()) - break; + return error; - bool is_same_addr = true; -#if !(defined(__linux__) || (defined(_WIN32))) - is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len); + lldb_private::SocketAddress &AddrIn = m_listen_sockets[sock_fd]; + if (!AddrIn.IsAnyAddr() && AccptAddr != AddrIn) { +#if defined(_WIN32) + closesocket(sock); +#else + ::close(sock); #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(); + ::fprintf( + stderr, + "error: rejecting incoming connection from %s (expecting %s)\n", + AccptAddr.GetIPAddress().c_str(), AddrIn.GetIPAddress().c_str()); + continue; } + accept_connection = true; + accepted_socket.reset(new TCPSocket(sock, *this)); } if (!accepted_socket) @@ -248,6 +337,7 @@ accepted_socket->SetOptionNoDelay(); error.Clear(); conn_socket = accepted_socket.release(); + CloseListenSockets(); return error; } Index: source/Host/common/UDPSocket.cpp =================================================================== --- source/Host/common/UDPSocket.cpp +++ source/Host/common/UDPSocket.cpp @@ -28,13 +28,16 @@ const int kType = SOCK_DGRAM; static const char *g_not_supported_error = "Not supported"; -} +} // namespace -UDPSocket::UDPSocket(NativeSocket socket) : Socket(socket, ProtocolUdp, true) {} +UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit) + : Socket(ProtocolUdp, should_close, child_processes_inherit) {} -UDPSocket::UDPSocket(bool child_processes_inherit, Error &error) - : UDPSocket( - CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {} +UDPSocket::UDPSocket(NativeSocket socket, const UDPSocket &listen_socket) + : Socket(ProtocolUdp, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { return ::sendto(m_socket, static_cast(buf), num_bytes, 0, @@ -42,27 +45,14 @@ } Error UDPSocket::Connect(llvm::StringRef name) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Listen(llvm::StringRef name, int backlog) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { - std::unique_ptr final_socket; - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); Error error; + if (error.Fail()) + return error; + std::string host_str; std::string port_str; int32_t port = INT32_MIN; @@ -94,12 +84,11 @@ 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( + m_socket = Socket::CreateSocket( service_info_ptr->ai_family, service_info_ptr->ai_socktype, - service_info_ptr->ai_protocol, child_processes_inherit, error); + service_info_ptr->ai_protocol, m_child_processes_inherit, error); if (error.Success()) { - final_socket.reset(new UDPSocket(send_fd)); - final_socket->m_sockaddr = service_info_ptr; + m_sockaddr = service_info_ptr; break; } else continue; @@ -107,16 +96,17 @@ ::freeaddrinfo(service_info_list); - if (!final_socket) + if (IsValid()) 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" || host_str == "localhost") - ? bind_addr.SetToLocalhost(kDomain, port) - : bind_addr.SetToAnyAddress(kDomain, port); + const bool bind_addr_success = + (host_str == "127.0.0.1" || host_str == "localhost") + ? bind_addr.SetToLocalhost(kDomain, port) + : bind_addr.SetToAnyAddress(kDomain, port); if (!bind_addr_success) { error.SetErrorString("Failed to get hostspec to bind for"); @@ -125,13 +115,37 @@ bind_addr.SetPort(0); // Let the source port # be determined dynamically - err = ::bind(final_socket->GetNativeSocket(), bind_addr, bind_addr.GetLength()); - - struct sockaddr_in source_info; - socklen_t address_len = sizeof (struct sockaddr_in); - err = ::getsockname(final_socket->GetNativeSocket(), (struct sockaddr *) &source_info, &address_len); + err = ::bind(m_socket, bind_addr, bind_addr.GetLength()); - socket = final_socket.release(); error.Clear(); return error; } + +Error UDPSocket::Listen(llvm::StringRef name, int backlog) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::Accept(Socket *&socket) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::CreateSocket() { + Error error; + if (IsValid()) + error = Close(); + if (error.Fail()) + return error; + m_socket = + Socket::CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + return error; +} + +Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, + Socket *&socket) { + std::unique_ptr final_socket( + new UDPSocket(true, child_processes_inherit)); + Error error = final_socket->Connect(name); + if (!error.Fail()) + socket = final_socket.release(); + return error; +} Index: source/Host/linux/AbstractSocket.cpp =================================================================== --- source/Host/linux/AbstractSocket.cpp +++ source/Host/linux/AbstractSocket.cpp @@ -14,8 +14,8 @@ using namespace lldb; using namespace lldb_private; -AbstractSocket::AbstractSocket(bool child_processes_inherit, Error &error) - : DomainSocket(ProtocolUnixAbstract, child_processes_inherit, error) {} +AbstractSocket::AbstractSocket(bool child_processes_inherit) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} size_t AbstractSocket::GetNameOffset() const { return 1; } Index: source/Host/posix/ConnectionFileDescriptorPosix.cpp =================================================================== --- source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -218,7 +218,7 @@ // assume we don't own it. std::unique_ptr tcp_socket; - tcp_socket.reset(new TCPSocket(fd, false)); + tcp_socket.reset(new TCPSocket(fd, false, 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; @@ -720,7 +720,7 @@ listening_socket_up.reset(socket); socket = nullptr; - error = listening_socket_up->Accept(s, m_child_processes_inherit, socket); + error = listening_socket_up->Accept(socket); listening_socket_up.reset(); if (error_ptr) *error_ptr = error; Index: source/Host/posix/DomainSocket.cpp =================================================================== --- source/Host/posix/DomainSocket.cpp +++ source/Host/posix/DomainSocket.cpp @@ -56,19 +56,21 @@ return true; } -} - -DomainSocket::DomainSocket(NativeSocket socket) - : Socket(socket, ProtocolUnixDomain, true) {} +} // namespace -DomainSocket::DomainSocket(bool child_processes_inherit, Error &error) - : DomainSocket( - CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {} +DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit) + : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {} DomainSocket::DomainSocket(SocketProtocol protocol, - bool child_processes_inherit, Error &error) - : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), - protocol, true) {} + bool child_processes_inherit) + : Socket(protocol, true, child_processes_inherit) {} + +DomainSocket::DomainSocket(NativeSocket socket, + const DomainSocket &listen_socket) + : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} Error DomainSocket::Connect(llvm::StringRef name) { sockaddr_un saddr_un; @@ -77,6 +79,9 @@ return Error("Failed to set socket address"); Error error; + m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + if (error.Fail()) + return error; if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) < 0) SetLastError(error); @@ -93,6 +98,9 @@ DeleteSocketFile(name); Error error; + m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + if (error.Fail()) + return error; if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 0) if (::listen(GetNativeSocket(), backlog) == 0) @@ -102,13 +110,12 @@ return error; } -Error DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { +Error DomainSocket::Accept(Socket *&socket) { Error error; auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, - child_processes_inherit, error); + m_child_processes_inherit, error); if (error.Success()) - socket = new DomainSocket(conn_fd); + socket = new DomainSocket(conn_fd, *this); return error; } Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -67,7 +67,7 @@ static Error FindUnusedPort(uint16_t &port) { Error error; - std::unique_ptr tcp_socket(new TCPSocket(false, error)); + std::unique_ptr tcp_socket(new TCPSocket(true, false)); if (error.Fail()) return error; Index: tools/lldb-server/Acceptor.cpp =================================================================== --- tools/lldb-server/Acceptor.cpp +++ tools/lldb-server/Acceptor.cpp @@ -62,8 +62,7 @@ Error Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) { Socket *conn_socket = nullptr; - auto error = m_listener_socket_up->Accept( - StringRef(m_name), child_processes_inherit, conn_socket); + auto error = m_listener_socket_up->Accept(conn_socket); if (error.Success()) conn = new ConnectionFileDescriptor(conn_socket); Index: unittests/Host/SocketTest.cpp =================================================================== --- unittests/Host/SocketTest.cpp +++ unittests/Host/SocketTest.cpp @@ -44,8 +44,7 @@ const char *listen_remote_address, bool child_processes_inherit, Socket **accept_socket, Error *error) { - *error = listen_socket->Accept(listen_remote_address, - child_processes_inherit, *accept_socket); + *error = listen_socket->Accept(*accept_socket); } template @@ -56,7 +55,7 @@ bool child_processes_inherit = false; Error error; std::unique_ptr listen_socket_up( - new SocketType(child_processes_inherit, error)); + new SocketType(true, child_processes_inherit)); EXPECT_FALSE(error.Fail()); error = listen_socket_up->Listen(listen_remote_address, 5); EXPECT_FALSE(error.Fail()); @@ -70,7 +69,7 @@ std::string connect_remote_address = get_connect_addr(*listen_socket_up); std::unique_ptr connect_socket_up( - new SocketType(child_processes_inherit, error)); + new SocketType(true, child_processes_inherit)); EXPECT_FALSE(error.Fail()); error = connect_socket_up->Connect(connect_remote_address); EXPECT_FALSE(error.Fail()); @@ -141,6 +140,20 @@ EXPECT_STREQ("65535", port_str.c_str()); EXPECT_EQ(65535, port); EXPECT_TRUE(error.Success()); + + EXPECT_TRUE( + Socket::DecodeHostAndPort("[::1]:12345", host_str, port_str, port, &error)); + EXPECT_STREQ("::1", host_str.c_str()); + EXPECT_STREQ("12345", port_str.c_str()); + EXPECT_EQ(12345, port); + EXPECT_TRUE(error.Success()); + + EXPECT_TRUE( + Socket::DecodeHostAndPort("[abcd:12fg:AF58::1]:12345", host_str, port_str, port, &error)); + EXPECT_STREQ("abcd:12fg:AF58::1", host_str.c_str()); + EXPECT_STREQ("12345", port_str.c_str()); + EXPECT_EQ(12345, port); + EXPECT_TRUE(error.Success()); } #ifndef LLDB_DISABLE_POSIX Index: unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp =================================================================== --- unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp +++ unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp @@ -33,15 +33,14 @@ void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server) { bool child_processes_inherit = false; Error error; - TCPSocket listen_socket(child_processes_inherit, error); + TCPSocket listen_socket(true, child_processes_inherit); ASSERT_FALSE(error.Fail()); error = listen_socket.Listen("127.0.0.1:0", 5); ASSERT_FALSE(error.Fail()); Socket *accept_socket; std::future accept_error = std::async(std::launch::async, [&] { - return listen_socket.Accept("127.0.0.1:0", child_processes_inherit, - accept_socket); + return listen_socket.Accept(accept_socket); }); char connect_remote_address[64];