LLDB mainline
TCPSocket.cpp
Go to the documentation of this file.
1//===-- TCPSocket.cpp -----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#if defined(_MSC_VER)
10#define _WINSOCK_DEPRECATED_NO_WARNINGS
11#endif
12
14
15#include "lldb/Host/Config.h"
16#include "lldb/Host/MainLoop.h"
18#include "lldb/Utility/Log.h"
19
20#include "llvm/Config/llvm-config.h"
21#include "llvm/Support/Errno.h"
22#include "llvm/Support/Error.h"
23#include "llvm/Support/WindowsError.h"
24#include "llvm/Support/raw_ostream.h"
25
26#if LLDB_ENABLE_POSIX
27#include <arpa/inet.h>
28#include <netinet/tcp.h>
29#include <sys/socket.h>
30#endif
31
32#if defined(_WIN32)
33#include <winsock2.h>
34#endif
35
36using namespace lldb;
37using namespace lldb_private;
38
39static const int kType = SOCK_STREAM;
40
41TCPSocket::TCPSocket(bool should_close) : Socket(ProtocolTcp, should_close) {}
42
43TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket)
44 : Socket(ProtocolTcp, listen_socket.m_should_close_fd) {
45 m_socket = socket;
46}
47
48TCPSocket::TCPSocket(NativeSocket socket, bool should_close)
49 : Socket(ProtocolTcp, should_close) {
50 m_socket = socket;
51}
52
54
55llvm::Expected<TCPSocket::Pair> TCPSocket::CreatePair() {
56 auto listen_socket_up = std::make_unique<TCPSocket>(true);
57 if (Status error = listen_socket_up->Listen("localhost:0", 5); error.Fail())
58 return error.takeError();
59
60 std::string connect_address =
61 llvm::StringRef(listen_socket_up->GetListeningConnectionURI()[0])
62 .split("://")
63 .second.str();
64
65 auto connect_socket_up = std::make_unique<TCPSocket>(true);
66 if (Status error = connect_socket_up->Connect(connect_address); error.Fail())
67 return error.takeError();
68
69 // Connection has already been made above, so a short timeout is sufficient.
70 Socket *accept_socket;
71 if (Status error =
72 listen_socket_up->Accept(std::chrono::seconds(1), accept_socket);
73 error.Fail())
74 return error.takeError();
75
76 return Pair(
77 std::move(connect_socket_up),
78 std::unique_ptr<TCPSocket>(static_cast<TCPSocket *>(accept_socket)));
79}
80
81bool TCPSocket::IsValid() const {
82 return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
83}
84
85// Return the port number that is being used by the socket.
88 SocketAddress sock_addr;
89 socklen_t sock_addr_len = sock_addr.GetMaxLength();
90 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
91 return sock_addr.GetPort();
92 } else if (!m_listen_sockets.empty()) {
93 SocketAddress sock_addr;
94 socklen_t sock_addr_len = sock_addr.GetMaxLength();
95 if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
96 &sock_addr_len) == 0)
97 return sock_addr.GetPort();
98 }
99 return 0;
100}
101
102std::string TCPSocket::GetLocalIPAddress() const {
103 // We bound to port zero, so we need to figure out which port we actually
104 // bound to
106 SocketAddress sock_addr;
107 socklen_t sock_addr_len = sock_addr.GetMaxLength();
108 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
109 return sock_addr.GetIPAddress();
110 }
111 return "";
112}
113
116 SocketAddress sock_addr;
117 socklen_t sock_addr_len = sock_addr.GetMaxLength();
118 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
119 return sock_addr.GetPort();
120 }
121 return 0;
122}
123
124std::string TCPSocket::GetRemoteIPAddress() const {
125 // We bound to port zero, so we need to figure out which port we actually
126 // bound to
128 SocketAddress sock_addr;
129 socklen_t sock_addr_len = sock_addr.GetMaxLength();
130 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
131 return sock_addr.GetIPAddress();
132 }
133 return "";
134}
135
138 return std::string(llvm::formatv(
139 "connect://[{0}]:{1}", GetRemoteIPAddress(), GetRemotePortNumber()));
140 }
141 return "";
142}
143
144std::vector<std::string> TCPSocket::GetListeningConnectionURI() const {
145 std::vector<std::string> URIs;
146 for (const auto &[fd, addr] : m_listen_sockets)
147 URIs.emplace_back(llvm::formatv("connection://[{0}]:{1}",
148 addr.GetIPAddress(), addr.GetPort()));
149 return URIs;
150}
151
154 if (IsValid())
155 error = Close();
156 if (error.Fail())
157 return error;
158 m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP, error);
159 return error;
160}
161
162Status TCPSocket::Connect(llvm::StringRef name) {
163
165 LLDB_LOG(log, "Connect to host/port {0}", name);
166
168 llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);
169 if (!host_port)
170 return Status::FromError(host_port.takeError());
171
172 std::vector<SocketAddress> addresses =
173 SocketAddress::GetAddressInfo(host_port->hostname.c_str(), nullptr,
174 AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
175 for (SocketAddress &address : addresses) {
176 error = CreateSocket(address.GetFamily());
177 if (error.Fail())
178 continue;
179
180 address.SetPort(host_port->port);
181
182 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
183 &address.sockaddr(),
184 address.GetLength()) == -1) {
185 Close();
186 continue;
187 }
188
189 if (SetOptionNoDelay() == -1) {
190 Close();
191 continue;
192 }
193
194 error.Clear();
195 return error;
196 }
197
199 "Failed to connect to {0}:{1}", host_port->hostname, host_port->port);
200 return error;
201}
202
203Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
205 LLDB_LOG(log, "Listen to {0}", name);
206
208 llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);
209 if (!host_port)
210 return Status::FromError(host_port.takeError());
211
212 if (host_port->hostname == "*")
213 host_port->hostname = "0.0.0.0";
214 std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
215 host_port->hostname.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
216 for (SocketAddress &address : addresses) {
217 int fd =
218 Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, error);
219 if (error.Fail() || fd < 0)
220 continue;
221
222 // enable local address reuse
223 if (SetOption(fd, SOL_SOCKET, SO_REUSEADDR, 1) == -1) {
224 CloseSocket(fd);
225 continue;
226 }
227
228 SocketAddress listen_address = address;
229 if(!listen_address.IsLocalhost())
230 listen_address.SetToAnyAddress(address.GetFamily(), host_port->port);
231 else
232 listen_address.SetPort(host_port->port);
233
234 int err =
235 ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
236 if (err != -1)
237 err = ::listen(fd, backlog);
238
239 if (err == -1) {
241 CloseSocket(fd);
242 continue;
243 }
244
245 if (host_port->port == 0) {
246 socklen_t sa_len = listen_address.GetLength();
247 if (getsockname(fd, &listen_address.sockaddr(), &sa_len) == 0)
248 host_port->port = listen_address.GetPort();
249 }
250 m_listen_sockets[fd] = listen_address;
251 }
252
253 if (m_listen_sockets.empty()) {
254 assert(error.Fail());
255 return error;
256 }
257 return Status();
258}
259
261 for (auto socket : m_listen_sockets)
262 CloseSocket(socket.first);
263 m_listen_sockets.clear();
264}
265
266llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
268 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
269 if (m_listen_sockets.size() == 0)
270 return llvm::createStringError("No open listening sockets!");
271
272 std::vector<MainLoopBase::ReadHandleUP> handles;
273 for (auto socket : m_listen_sockets) {
274 auto fd = socket.first;
275 auto io_sp = std::make_shared<TCPSocket>(fd, false);
276 auto cb = [this, fd, sock_cb](MainLoopBase &loop) {
278 socklen_t sa_len = AcceptAddr.GetMaxLength();
280 NativeSocket sock =
281 AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, error);
282 Log *log = GetLog(LLDBLog::Host);
283 if (error.Fail()) {
284 LLDB_LOG(log, "AcceptSocket({0}): {1}", fd, error);
285 return;
286 }
287
289 if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
290 CloseSocket(sock);
291 LLDB_LOG(log, "rejecting incoming connection from {0} (expecting {1})",
292 AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
293 return;
294 }
295 std::unique_ptr<TCPSocket> sock_up(new TCPSocket(sock, *this));
296
297 // Keep our TCP packets coming without any delays.
298 sock_up->SetOptionNoDelay();
299
300 sock_cb(std::move(sock_up));
301 };
303 handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));
304 if (error.Fail())
305 return error.ToError();
306 }
307
308 return handles;
309}
310
312 return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
313}
314
316 return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
317}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:369
static const int kType
Definition TCPSocket.cpp:39
virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Status &error)=0
static std::vector< SocketAddress > GetAddressInfo(const char *hostname, const char *servname, int ai_family, int ai_socktype, int ai_protocol, int ai_flags=0)
bool SetToAnyAddress(sa_family_t family, uint16_t port)
std::string GetIPAddress() const
static socklen_t GetMaxLength()
struct sockaddr & sockaddr()
bool SetPort(uint16_t port)
NativeSocket GetNativeSocket() const
Definition Socket.h:151
static const NativeSocket kInvalidSocketValue
Definition Socket.h:95
static NativeSocket CreateSocket(const int domain, const int type, const int protocol, Status &error)
Definition Socket.cpp:440
static llvm::Expected< HostAndPort > DecodeHostAndPort(llvm::StringRef host_and_port)
Definition Socket.cpp:292
static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, Status &error)
Definition Socket.cpp:476
static Status GetLastError()
Definition Socket.cpp:422
static int CloseSocket(NativeSocket sockfd)
Definition Socket.cpp:432
NativeSocket m_socket
Definition Socket.h:187
static int SetOption(NativeSocket sockfd, int level, int option_name, int option_value)
Definition Socket.cpp:402
Status Close() override
Definition Socket.cpp:374
Socket(SocketProtocol protocol, bool should_close)
Definition Socket.cpp:170
An error handling class.
Definition Status.h:118
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:137
std::vector< std::string > GetListeningConnectionURI() const override
Status Listen(llvm::StringRef name, int backlog) override
bool IsValid() const override
Definition TCPSocket.cpp:81
uint16_t GetRemotePortNumber() const
Status CreateSocket(int domain)
std::string GetRemoteConnectionURI() const override
llvm::Expected< std::vector< MainLoopBase::ReadHandleUP > > Accept(MainLoopBase &loop, std::function< void(std::unique_ptr< Socket > socket)> sock_cb) override
std::string GetLocalIPAddress() const
std::string GetRemoteIPAddress() const
uint16_t GetLocalPortNumber() const
Definition TCPSocket.cpp:86
TCPSocket(bool should_close)
Definition TCPSocket.cpp:41
static llvm::Expected< Pair > CreatePair()
Definition TCPSocket.cpp:55
std::map< int, SocketAddress > m_listen_sockets
Definition TCPSocket.h:68
std::pair< std::unique_ptr< TCPSocket >, std::unique_ptr< TCPSocket > > Pair
Definition TCPSocket.h:26
Status Connect(llvm::StringRef name) override
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
int NativeSocket
Definition Socket.h:41