https://github.com/slydiman created https://github.com/llvm/llvm-project/pull/104797
This is prerequisite for #104238. >From c14f06278aff93f0c7433f6d13c3d9d944d7a1cf Mon Sep 17 00:00:00 2001 From: Dmitry Vasilyev <dvassil...@accesssoftek.com> Date: Mon, 19 Aug 2024 18:56:36 +0400 Subject: [PATCH] [lldb] Updated TCPSocket to listen multiple ports on the same single thread This is prerequisite for #104238. --- lldb/include/lldb/Host/common/TCPSocket.h | 3 + lldb/source/Host/common/TCPSocket.cpp | 105 +++++++++++++++------- lldb/unittests/Host/SocketTest.cpp | 13 +++ 3 files changed, 87 insertions(+), 34 deletions(-) diff --git a/lldb/include/lldb/Host/common/TCPSocket.h b/lldb/include/lldb/Host/common/TCPSocket.h index b782c9e6096c44..b45fdae00c6b43 100644 --- a/lldb/include/lldb/Host/common/TCPSocket.h +++ b/lldb/include/lldb/Host/common/TCPSocket.h @@ -24,6 +24,9 @@ class TCPSocket : public Socket { // returns port number or 0 if error uint16_t GetLocalPortNumber() const; + // returns port numbers of all listening sockets + std::set<uint16_t> GetLocalPortNumbers() const; + // returns ip address string or empty string if error std::string GetLocalIPAddress() const; diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp index df4737216ed3ac..e659b20bb0045e 100644 --- a/lldb/source/Host/common/TCPSocket.cpp +++ b/lldb/source/Host/common/TCPSocket.cpp @@ -17,6 +17,7 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/Errno.h" #include "llvm/Support/WindowsError.h" @@ -94,6 +95,25 @@ uint16_t TCPSocket::GetLocalPortNumber() const { return 0; } +// Return all the port numbers that is being used by the socket. +std::set<uint16_t> TCPSocket::GetLocalPortNumbers() const { + std::set<uint16_t> ports; + 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) + ports.insert(sock_addr.GetPort()); + } else if (!m_listen_sockets.empty()) { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength(); + for (auto listen_socket : m_listen_sockets) { + if (::getsockname(listen_socket.first, sock_addr, &sock_addr_len) == 0) + ports.insert(sock_addr.GetPort()); + } + } + return ports; +} + std::string TCPSocket::GetLocalIPAddress() const { // We bound to port zero, so we need to figure out which port we actually // bound to @@ -196,49 +216,66 @@ Status TCPSocket::Listen(llvm::StringRef name, int backlog) { if (!host_port) return Status(host_port.takeError()); + llvm::SmallVector<uint16_t, 2> ports; + ports.push_back(host_port->port); + + llvm::SmallVector<llvm::StringRef, 2> extra_ports; + name.split(extra_ports, ',', -1, false); + if (extra_ports.size() > 1) { + for (auto i = extra_ports.begin() + 1; i != extra_ports.end(); ++i) { + uint16_t port; + if (!llvm::to_integer(*i, port, 10)) + return Status("invalid extra port number %s", i->str().c_str()); + ports.push_back(port); + } + } + if (host_port->hostname == "*") host_port->hostname = "0.0.0.0"; std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo( host_port->hostname.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); for (SocketAddress &address : addresses) { - int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, - m_child_processes_inherit, error); - if (error.Fail() || fd < 0) - continue; - - // enable local address reuse - int option_value = 1; - set_socket_option_arg_type option_value_p = - reinterpret_cast<set_socket_option_arg_type>(&option_value); - if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p, - sizeof(option_value)) == -1) { - CLOSE_SOCKET(fd); - continue; - } - - SocketAddress listen_address = address; - if(!listen_address.IsLocalhost()) - listen_address.SetToAnyAddress(address.GetFamily(), host_port->port); - else - listen_address.SetPort(host_port->port); + for (size_t i = 0; i < ports.size(); ++i) { + int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, + m_child_processes_inherit, error); + if (error.Fail() || fd < 0) + continue; + + // enable local address reuse + int option_value = 1; + set_socket_option_arg_type option_value_p = + reinterpret_cast<set_socket_option_arg_type>(&option_value); + if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p, + sizeof(option_value)) == -1) { + CLOSE_SOCKET(fd); + continue; + } - int err = - ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength()); - if (err != -1) - err = ::listen(fd, backlog); + SocketAddress listen_address = address; + if (!listen_address.IsLocalhost()) + listen_address.SetToAnyAddress(address.GetFamily(), ports[i]); + else + listen_address.SetPort(ports[i]); + + int err = + ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength()); + if (err != -1) + err = ::listen(fd, backlog); + + if (err == -1) { + error = GetLastSocketError(); + CLOSE_SOCKET(fd); + continue; + } - if (err == -1) { - error = GetLastSocketError(); - CLOSE_SOCKET(fd); - continue; - } + if (ports[i] == 0) { + socklen_t sa_len = address.GetLength(); + if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) + ports[i] = address.GetPort(); + } - if (host_port->port == 0) { - socklen_t sa_len = address.GetLength(); - if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) - host_port->port = address.GetPort(); + m_listen_sockets[fd] = address; } - m_listen_sockets[fd] = address; } if (m_listen_sockets.empty()) { diff --git a/lldb/unittests/Host/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp index 78e1e11df06562..3e87af57d3ce51 100644 --- a/lldb/unittests/Host/SocketTest.cpp +++ b/lldb/unittests/Host/SocketTest.cpp @@ -136,6 +136,19 @@ TEST_P(SocketTest, TCPListen0GetPort) { EXPECT_NE(sock.get()->GetLocalPortNumber(), 0); } +TEST_P(SocketTest, TCPListen00GetPort) { + if (!HostSupportsIPv4()) + return; + llvm::Expected<std::unique_ptr<TCPSocket>> sock = + Socket::TcpListen("10.10.12.3:0,0", false); + ASSERT_THAT_EXPECTED(sock, llvm::Succeeded()); + ASSERT_TRUE(sock.get()->IsValid()); + std::set<uint16_t> ports = sock.get()->GetLocalPortNumbers(); + ASSERT_EQ(2, ports.size()); + EXPECT_NE(*ports.begin(), 0); + EXPECT_NE(*std::next(ports.begin()), 0); +} + TEST_P(SocketTest, TCPGetConnectURI) { std::unique_ptr<TCPSocket> socket_a_up; std::unique_ptr<TCPSocket> socket_b_up; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits