Skip to content

Commit 3d5e1ec

Browse files
authored
[lldb] Add a callback version of TCPSocket::Accept (#106955)
The existing function already used the MainLoop class, which allows one to wait on multiple events at once. It needed to do this in order to wait for v4 and v6 connections simultaneously. However, since it was creating its own instance of MainLoop, this meant that it was impossible to multiplex these sockets with anything else. This patch simply adds a version of this function which uses an externally provided main loop instance, which allows the caller to add any events it deems necessary. The previous function becomes a very thin wrapper over the new one.
1 parent 4353530 commit 3d5e1ec

File tree

3 files changed

+97
-51
lines changed

3 files changed

+97
-51
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLDB_HOST_COMMON_TCPSOCKET_H
1010
#define LLDB_HOST_COMMON_TCPSOCKET_H
1111

12+
#include "lldb/Host/MainLoopBase.h"
1213
#include "lldb/Host/Socket.h"
1314
#include "lldb/Host/SocketAddress.h"
1415
#include <map>
@@ -40,6 +41,16 @@ class TCPSocket : public Socket {
4041

4142
Status Connect(llvm::StringRef name) override;
4243
Status Listen(llvm::StringRef name, int backlog) override;
44+
45+
// Use the provided main loop instance to accept new connections. The callback
46+
// will be called (from MainLoop::Run) for each new connection. This function
47+
// does not block.
48+
llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
49+
Accept(MainLoopBase &loop,
50+
std::function<void(std::unique_ptr<TCPSocket> socket)> sock_cb);
51+
52+
// Accept a single connection and "return" it in the pointer argument. This
53+
// function blocks until the connection arrives.
4354
Status Accept(Socket *&conn_socket) override;
4455

4556
Status CreateSocket(int domain);

lldb/source/Host/common/TCPSocket.cpp

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "llvm/Config/llvm-config.h"
2121
#include "llvm/Support/Errno.h"
22+
#include "llvm/Support/Error.h"
2223
#include "llvm/Support/WindowsError.h"
2324
#include "llvm/Support/raw_ostream.h"
2425

@@ -254,67 +255,63 @@ void TCPSocket::CloseListenSockets() {
254255
m_listen_sockets.clear();
255256
}
256257

257-
Status TCPSocket::Accept(Socket *&conn_socket) {
258-
Status error;
259-
if (m_listen_sockets.size() == 0) {
260-
error = Status::FromErrorString("No open listening sockets!");
261-
return error;
262-
}
258+
llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> TCPSocket::Accept(
259+
MainLoopBase &loop,
260+
std::function<void(std::unique_ptr<TCPSocket> socket)> sock_cb) {
261+
if (m_listen_sockets.size() == 0)
262+
return llvm::createStringError("No open listening sockets!");
263263

264-
NativeSocket sock = kInvalidSocketValue;
265-
NativeSocket listen_sock = kInvalidSocketValue;
266-
lldb_private::SocketAddress AcceptAddr;
267-
MainLoop accept_loop;
268264
std::vector<MainLoopBase::ReadHandleUP> handles;
269265
for (auto socket : m_listen_sockets) {
270266
auto fd = socket.first;
271-
auto inherit = this->m_child_processes_inherit;
272-
auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));
273-
handles.emplace_back(accept_loop.RegisterReadObject(
274-
io_sp, [fd, inherit, &sock, &AcceptAddr, &error,
275-
&listen_sock](MainLoopBase &loop) {
276-
socklen_t sa_len = AcceptAddr.GetMaxLength();
277-
sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,
278-
error);
279-
listen_sock = fd;
280-
loop.RequestTermination();
281-
}, error));
282-
if (error.Fail())
283-
return error;
284-
}
285-
286-
bool accept_connection = false;
287-
std::unique_ptr<TCPSocket> accepted_socket;
288-
// Loop until we are happy with our connection
289-
while (!accept_connection) {
290-
accept_loop.Run();
291-
292-
if (error.Fail())
293-
return error;
267+
auto io_sp =
268+
std::make_shared<TCPSocket>(fd, false, this->m_child_processes_inherit);
269+
auto cb = [this, fd, sock_cb](MainLoopBase &loop) {
270+
lldb_private::SocketAddress AcceptAddr;
271+
socklen_t sa_len = AcceptAddr.GetMaxLength();
272+
Status error;
273+
NativeSocket sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len,
274+
m_child_processes_inherit, error);
275+
Log *log = GetLog(LLDBLog::Host);
276+
if (error.Fail()) {
277+
LLDB_LOG(log, "AcceptSocket({0}): {1}", fd, error);
278+
return;
279+
}
294280

295-
lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
296-
if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
297-
if (sock != kInvalidSocketValue) {
281+
const lldb_private::SocketAddress &AddrIn = m_listen_sockets[fd];
282+
if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
298283
CLOSE_SOCKET(sock);
299-
sock = kInvalidSocketValue;
284+
LLDB_LOG(log, "rejecting incoming connection from {0} (expecting {1})",
285+
AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
286+
return;
300287
}
301-
llvm::errs() << llvm::formatv(
302-
"error: rejecting incoming connection from {0} (expecting {1})",
303-
AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
304-
continue;
305-
}
306-
accept_connection = true;
307-
accepted_socket.reset(new TCPSocket(sock, *this));
288+
std::unique_ptr<TCPSocket> sock_up(new TCPSocket(sock, *this));
289+
290+
// Keep our TCP packets coming without any delays.
291+
sock_up->SetOptionNoDelay();
292+
293+
sock_cb(std::move(sock_up));
294+
};
295+
Status error;
296+
handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));
297+
if (error.Fail())
298+
return error.ToError();
308299
}
309300

310-
if (!accepted_socket)
311-
return error;
301+
return handles;
302+
}
312303

313-
// Keep our TCP packets coming without any delays.
314-
accepted_socket->SetOptionNoDelay();
315-
error.Clear();
316-
conn_socket = accepted_socket.release();
317-
return error;
304+
Status TCPSocket::Accept(Socket *&conn_socket) {
305+
MainLoop accept_loop;
306+
llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> expected_handles =
307+
Accept(accept_loop,
308+
[&accept_loop, &conn_socket](std::unique_ptr<TCPSocket> sock) {
309+
conn_socket = sock.release();
310+
accept_loop.RequestTermination();
311+
});
312+
if (!expected_handles)
313+
return Status(expected_handles.takeError());
314+
return accept_loop.Run();
318315
}
319316

320317
int TCPSocket::SetOptionNoDelay() {

lldb/unittests/Host/SocketTest.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "TestingSupport/Host/SocketTestUtilities.h"
1010
#include "TestingSupport/SubsystemRAII.h"
1111
#include "lldb/Host/Config.h"
12+
#include "lldb/Host/MainLoop.h"
1213
#include "lldb/Utility/UriParser.h"
1314
#include "llvm/Testing/Support/Error.h"
1415
#include "gtest/gtest.h"
@@ -95,6 +96,43 @@ TEST_P(SocketTest, TCPListen0ConnectAccept) {
9596
&socket_b_up);
9697
}
9798

99+
TEST_P(SocketTest, TCPMainLoopAccept) {
100+
if (!HostSupportsProtocol())
101+
return;
102+
103+
const bool child_processes_inherit = false;
104+
auto listen_socket_up =
105+
std::make_unique<TCPSocket>(true, child_processes_inherit);
106+
Status error = listen_socket_up->Listen(
107+
llvm::formatv("[{0}]:0", GetParam().localhost_ip).str(), 5);
108+
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
109+
ASSERT_TRUE(listen_socket_up->IsValid());
110+
111+
MainLoop loop;
112+
std::unique_ptr<TCPSocket> accepted_socket_up;
113+
auto expected_handles = listen_socket_up->Accept(
114+
loop, [&accepted_socket_up, &loop](std::unique_ptr<TCPSocket> sock_up) {
115+
accepted_socket_up = std::move(sock_up);
116+
loop.RequestTermination();
117+
});
118+
ASSERT_THAT_EXPECTED(expected_handles, llvm::Succeeded());
119+
120+
std::unique_ptr<TCPSocket> connect_socket_up(
121+
new TCPSocket(true, child_processes_inherit));
122+
ASSERT_THAT_ERROR(
123+
connect_socket_up
124+
->Connect(llvm::formatv("[{0}]:{1}", GetParam().localhost_ip,
125+
listen_socket_up->GetLocalPortNumber())
126+
.str())
127+
.ToError(),
128+
llvm::Succeeded());
129+
ASSERT_TRUE(connect_socket_up->IsValid());
130+
131+
loop.Run();
132+
ASSERT_TRUE(accepted_socket_up);
133+
ASSERT_TRUE(accepted_socket_up->IsValid());
134+
}
135+
98136
TEST_P(SocketTest, TCPGetAddress) {
99137
std::unique_ptr<TCPSocket> socket_a_up;
100138
std::unique_ptr<TCPSocket> socket_b_up;

0 commit comments

Comments
 (0)