Skip to content

Commit c14f062

Browse files
committed
[lldb] Updated TCPSocket to listen multiple ports on the same single thread
This is prerequisite for llvm#104238.
1 parent 899a3df commit c14f062

File tree

3 files changed

+87
-34
lines changed

3 files changed

+87
-34
lines changed

lldb/include/lldb/Host/common/TCPSocket.h

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class TCPSocket : public Socket {
2424
// returns port number or 0 if error
2525
uint16_t GetLocalPortNumber() const;
2626

27+
// returns port numbers of all listening sockets
28+
std::set<uint16_t> GetLocalPortNumbers() const;
29+
2730
// returns ip address string or empty string if error
2831
std::string GetLocalIPAddress() const;
2932

lldb/source/Host/common/TCPSocket.cpp

+71-34
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "lldb/Utility/LLDBLog.h"
1818
#include "lldb/Utility/Log.h"
1919

20+
#include "llvm/ADT/StringExtras.h"
2021
#include "llvm/Config/llvm-config.h"
2122
#include "llvm/Support/Errno.h"
2223
#include "llvm/Support/WindowsError.h"
@@ -94,6 +95,25 @@ uint16_t TCPSocket::GetLocalPortNumber() const {
9495
return 0;
9596
}
9697

98+
// Return all the port numbers that is being used by the socket.
99+
std::set<uint16_t> TCPSocket::GetLocalPortNumbers() const {
100+
std::set<uint16_t> ports;
101+
if (m_socket != kInvalidSocketValue) {
102+
SocketAddress sock_addr;
103+
socklen_t sock_addr_len = sock_addr.GetMaxLength();
104+
if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
105+
ports.insert(sock_addr.GetPort());
106+
} else if (!m_listen_sockets.empty()) {
107+
SocketAddress sock_addr;
108+
socklen_t sock_addr_len = sock_addr.GetMaxLength();
109+
for (auto listen_socket : m_listen_sockets) {
110+
if (::getsockname(listen_socket.first, sock_addr, &sock_addr_len) == 0)
111+
ports.insert(sock_addr.GetPort());
112+
}
113+
}
114+
return ports;
115+
}
116+
97117
std::string TCPSocket::GetLocalIPAddress() const {
98118
// We bound to port zero, so we need to figure out which port we actually
99119
// bound to
@@ -196,49 +216,66 @@ Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
196216
if (!host_port)
197217
return Status(host_port.takeError());
198218

219+
llvm::SmallVector<uint16_t, 2> ports;
220+
ports.push_back(host_port->port);
221+
222+
llvm::SmallVector<llvm::StringRef, 2> extra_ports;
223+
name.split(extra_ports, ',', -1, false);
224+
if (extra_ports.size() > 1) {
225+
for (auto i = extra_ports.begin() + 1; i != extra_ports.end(); ++i) {
226+
uint16_t port;
227+
if (!llvm::to_integer(*i, port, 10))
228+
return Status("invalid extra port number %s", i->str().c_str());
229+
ports.push_back(port);
230+
}
231+
}
232+
199233
if (host_port->hostname == "*")
200234
host_port->hostname = "0.0.0.0";
201235
std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
202236
host_port->hostname.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
203237
for (SocketAddress &address : addresses) {
204-
int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
205-
m_child_processes_inherit, error);
206-
if (error.Fail() || fd < 0)
207-
continue;
208-
209-
// enable local address reuse
210-
int option_value = 1;
211-
set_socket_option_arg_type option_value_p =
212-
reinterpret_cast<set_socket_option_arg_type>(&option_value);
213-
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
214-
sizeof(option_value)) == -1) {
215-
CLOSE_SOCKET(fd);
216-
continue;
217-
}
218-
219-
SocketAddress listen_address = address;
220-
if(!listen_address.IsLocalhost())
221-
listen_address.SetToAnyAddress(address.GetFamily(), host_port->port);
222-
else
223-
listen_address.SetPort(host_port->port);
238+
for (size_t i = 0; i < ports.size(); ++i) {
239+
int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
240+
m_child_processes_inherit, error);
241+
if (error.Fail() || fd < 0)
242+
continue;
243+
244+
// enable local address reuse
245+
int option_value = 1;
246+
set_socket_option_arg_type option_value_p =
247+
reinterpret_cast<set_socket_option_arg_type>(&option_value);
248+
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
249+
sizeof(option_value)) == -1) {
250+
CLOSE_SOCKET(fd);
251+
continue;
252+
}
224253

225-
int err =
226-
::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
227-
if (err != -1)
228-
err = ::listen(fd, backlog);
254+
SocketAddress listen_address = address;
255+
if (!listen_address.IsLocalhost())
256+
listen_address.SetToAnyAddress(address.GetFamily(), ports[i]);
257+
else
258+
listen_address.SetPort(ports[i]);
259+
260+
int err =
261+
::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
262+
if (err != -1)
263+
err = ::listen(fd, backlog);
264+
265+
if (err == -1) {
266+
error = GetLastSocketError();
267+
CLOSE_SOCKET(fd);
268+
continue;
269+
}
229270

230-
if (err == -1) {
231-
error = GetLastSocketError();
232-
CLOSE_SOCKET(fd);
233-
continue;
234-
}
271+
if (ports[i] == 0) {
272+
socklen_t sa_len = address.GetLength();
273+
if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
274+
ports[i] = address.GetPort();
275+
}
235276

236-
if (host_port->port == 0) {
237-
socklen_t sa_len = address.GetLength();
238-
if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
239-
host_port->port = address.GetPort();
277+
m_listen_sockets[fd] = address;
240278
}
241-
m_listen_sockets[fd] = address;
242279
}
243280

244281
if (m_listen_sockets.empty()) {

lldb/unittests/Host/SocketTest.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,19 @@ TEST_P(SocketTest, TCPListen0GetPort) {
136136
EXPECT_NE(sock.get()->GetLocalPortNumber(), 0);
137137
}
138138

139+
TEST_P(SocketTest, TCPListen00GetPort) {
140+
if (!HostSupportsIPv4())
141+
return;
142+
llvm::Expected<std::unique_ptr<TCPSocket>> sock =
143+
Socket::TcpListen("10.10.12.3:0,0", false);
144+
ASSERT_THAT_EXPECTED(sock, llvm::Succeeded());
145+
ASSERT_TRUE(sock.get()->IsValid());
146+
std::set<uint16_t> ports = sock.get()->GetLocalPortNumbers();
147+
ASSERT_EQ(2, ports.size());
148+
EXPECT_NE(*ports.begin(), 0);
149+
EXPECT_NE(*std::next(ports.begin()), 0);
150+
}
151+
139152
TEST_P(SocketTest, TCPGetConnectURI) {
140153
std::unique_ptr<TCPSocket> socket_a_up;
141154
std::unique_ptr<TCPSocket> socket_b_up;

0 commit comments

Comments
 (0)