Index: vendor/lldb/dist/source/Host/common/TCPSocket.cpp =================================================================== --- vendor/lldb/dist/source/Host/common/TCPSocket.cpp (revision 323097) +++ vendor/lldb/dist/source/Host/common/TCPSocket.cpp (revision 323098) @@ -1,297 +1,302 @@ //===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #if defined(_MSC_VER) #define _WINSOCK_DEPRECATED_NO_WARNINGS #endif #include "lldb/Host/common/TCPSocket.h" #include "lldb/Host/Config.h" #include "lldb/Host/MainLoop.h" #include "lldb/Utility/Log.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/raw_ostream.h" #ifndef LLDB_DISABLE_POSIX #include #include #include #endif #if defined(LLVM_ON_WIN32) #include #endif #ifdef LLVM_ON_WIN32 #define CLOSE_SOCKET closesocket typedef const char *set_socket_option_arg_type; #else #include #define CLOSE_SOCKET ::close typedef const void *set_socket_option_arg_type; #endif using namespace lldb; using namespace lldb_private; namespace { const int kType = SOCK_STREAM; } TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit) : Socket(ProtocolTcp, should_close, child_processes_inherit) {} TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket) : Socket(ProtocolTcp, listen_socket.m_should_close_fd, listen_socket.m_child_processes_inherit) { m_socket = socket; } TCPSocket::TCPSocket(NativeSocket socket, bool should_close, bool child_processes_inherit) : Socket(ProtocolTcp, should_close, child_processes_inherit) { m_socket = socket; } TCPSocket::~TCPSocket() { CloseListenSockets(); } 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 { 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(); } 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; } 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 ""; } Status TCPSocket::CreateSocket(int domain) { Status 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; } Status TCPSocket::Connect(llvm::StringRef name) { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); if (log) log->Printf("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); Status error; std::string host_str; std::string port_str; int32_t port = INT32_MIN; if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) return error; auto addresses = lldb_private::SocketAddress::GetAddressInfo( host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); for (auto address : addresses) { error = CreateSocket(address.GetFamily()); if (error.Fail()) continue; address.SetPort(port); if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(), address.GetLength())) { CLOSE_SOCKET(GetNativeSocket()); continue; } SetOptionNoDelay(); error.Clear(); return error; } error.SetErrorString("Failed to connect port"); return error; } Status TCPSocket::Listen(llvm::StringRef name, int backlog) { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data()); Status 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; if (host_str == "*") host_str = "0.0.0.0"; auto addresses = lldb_private::SocketAddress::GetAddressInfo( host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); for (auto address : addresses) { int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, m_child_processes_inherit, error); if (error.Fail()) { error.Clear(); continue; } // enable local address reuse int option_value = 1; set_socket_option_arg_type option_value_p = reinterpret_cast(&option_value); ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p, sizeof(option_value)); - address.SetPort(port); + SocketAddress listen_address = address; + if(!listen_address.IsLocalhost()) + listen_address.SetToAnyAddress(address.GetFamily(), port); + else + listen_address.SetPort(port); - int err = ::bind(fd, &address.sockaddr(), address.GetLength()); + int err = + ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength()); if (-1 != err) err = ::listen(fd, backlog); if (-1 == err) { CLOSE_SOCKET(fd); continue; } 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; } void TCPSocket::CloseListenSockets() { for (auto socket : m_listen_sockets) CLOSE_SOCKET(socket.first); m_listen_sockets.clear(); } Status TCPSocket::Accept(Socket *&conn_socket) { Status error; if (m_listen_sockets.size() == 0) { error.SetErrorString("No open listening sockets!"); return error; } int sock = -1; int listen_sock = -1; lldb_private::SocketAddress AcceptAddr; MainLoop accept_loop; std::vector handles; for (auto socket : m_listen_sockets) { auto fd = socket.first; auto inherit = this->m_child_processes_inherit; auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit)); handles.emplace_back(accept_loop.RegisterReadObject( io_sp, [fd, inherit, &sock, &AcceptAddr, &error, &listen_sock](MainLoopBase &loop) { socklen_t sa_len = AcceptAddr.GetMaxLength(); sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit, error); listen_sock = fd; loop.RequestTermination(); }, error)); if (error.Fail()) return error; } bool accept_connection = false; std::unique_ptr accepted_socket; // Loop until we are happy with our connection while (!accept_connection) { accept_loop.Run(); if (error.Fail()) return error; lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock]; if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) { CLOSE_SOCKET(sock); llvm::errs() << llvm::formatv( "error: rejecting incoming connection from {0} (expecting {1})", AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress()); continue; } accept_connection = true; accepted_socket.reset(new TCPSocket(sock, *this)); } 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: vendor/lldb/dist/unittests/Host/SocketTest.cpp =================================================================== --- vendor/lldb/dist/unittests/Host/SocketTest.cpp (revision 323097) +++ vendor/lldb/dist/unittests/Host/SocketTest.cpp (revision 323098) @@ -1,222 +1,233 @@ //===-- SocketTest.cpp ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include #include #include #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; class SocketTest : public testing::Test { public: void SetUp() override { #if defined(_MSC_VER) WSADATA data; ::WSAStartup(MAKEWORD(2, 2), &data); #endif } void TearDown() override { #if defined(_MSC_VER) ::WSACleanup(); #endif } protected: static void AcceptThread(Socket *listen_socket, const char *listen_remote_address, bool child_processes_inherit, Socket **accept_socket, Status *error) { *error = listen_socket->Accept(*accept_socket); } template void CreateConnectedSockets( const char *listen_remote_address, const std::function &get_connect_addr, std::unique_ptr *a_up, std::unique_ptr *b_up) { bool child_processes_inherit = false; Status error; std::unique_ptr listen_socket_up( new SocketType(true, child_processes_inherit)); EXPECT_FALSE(error.Fail()); error = listen_socket_up->Listen(listen_remote_address, 5); EXPECT_FALSE(error.Fail()); EXPECT_TRUE(listen_socket_up->IsValid()); Status accept_error; Socket *accept_socket; std::thread accept_thread(AcceptThread, listen_socket_up.get(), listen_remote_address, child_processes_inherit, &accept_socket, &accept_error); std::string connect_remote_address = get_connect_addr(*listen_socket_up); std::unique_ptr connect_socket_up( new SocketType(true, child_processes_inherit)); EXPECT_FALSE(error.Fail()); error = connect_socket_up->Connect(connect_remote_address); 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(static_cast(accept_socket)); EXPECT_TRUE(accept_error.Success()); EXPECT_NE(nullptr, b_up->get()); EXPECT_TRUE((*b_up)->IsValid()); listen_socket_up.reset(); } }; TEST_F(SocketTest, DecodeHostAndPort) { std::string host_str; std::string port_str; int32_t port; Status error; EXPECT_TRUE(Socket::DecodeHostAndPort("localhost:1138", host_str, port_str, port, &error)); EXPECT_STREQ("localhost", host_str.c_str()); EXPECT_STREQ("1138", port_str.c_str()); EXPECT_EQ(1138, port); EXPECT_TRUE(error.Success()); EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:65536", host_str, port_str, port, &error)); EXPECT_TRUE(error.Fail()); EXPECT_STREQ("invalid host:port specification: 'google.com:65536'", error.AsCString()); EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:-1138", host_str, port_str, port, &error)); EXPECT_TRUE(error.Fail()); EXPECT_STREQ("invalid host:port specification: 'google.com:-1138'", error.AsCString()); EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:65536", host_str, port_str, port, &error)); EXPECT_TRUE(error.Fail()); EXPECT_STREQ("invalid host:port specification: 'google.com:65536'", error.AsCString()); EXPECT_TRUE( Socket::DecodeHostAndPort("12345", host_str, port_str, port, &error)); EXPECT_STREQ("", host_str.c_str()); EXPECT_STREQ("12345", port_str.c_str()); EXPECT_EQ(12345, port); EXPECT_TRUE(error.Success()); EXPECT_TRUE( Socket::DecodeHostAndPort("*:0", host_str, port_str, port, &error)); EXPECT_STREQ("*", host_str.c_str()); EXPECT_STREQ("0", port_str.c_str()); EXPECT_EQ(0, port); EXPECT_TRUE(error.Success()); EXPECT_TRUE( Socket::DecodeHostAndPort("*:65535", host_str, port_str, port, &error)); EXPECT_STREQ("*", host_str.c_str()); 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 TEST_F(SocketTest, DomainListenConnectAccept) { 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 socket_a_up; std::unique_ptr socket_b_up; CreateConnectedSockets( file_name.c_str(), [=](const DomainSocket &) { return file_name; }, &socket_a_up, &socket_b_up); } #endif TEST_F(SocketTest, TCPListen0ConnectAccept) { std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; CreateConnectedSockets( "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 socket_a_up; std::unique_ptr socket_b_up; CreateConnectedSockets( "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; bool child_processes_inherit = false; auto error = UDPSocket::Connect("127.0.0.1:0", child_processes_inherit, socket); std::unique_ptr socket_up(socket); EXPECT_TRUE(error.Success()); EXPECT_TRUE(socket_up->IsValid()); } + +TEST_F(SocketTest, TCPListen0GetPort) { + Socket *server_socket; + Predicate port_predicate; + port_predicate.SetValue(0, eBroadcastNever); + Status err = + Socket::TcpListen("10.10.12.3:0", false, server_socket, &port_predicate); + std::unique_ptr socket_up((TCPSocket*)server_socket); + EXPECT_TRUE(socket_up->IsValid()); + EXPECT_NE(socket_up->GetLocalPortNumber(), 0); +}