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
55bool TCPSocket::IsValid() const {
56 return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
57}
58
59// Return the port number that is being used by the socket.
62 SocketAddress sock_addr;
63 socklen_t sock_addr_len = sock_addr.GetMaxLength();
64 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
65 return sock_addr.GetPort();
66 } else if (!m_listen_sockets.empty()) {
67 SocketAddress sock_addr;
68 socklen_t sock_addr_len = sock_addr.GetMaxLength();
69 if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
70 &sock_addr_len) == 0)
71 return sock_addr.GetPort();
72 }
73 return 0;
74}
75
76std::string TCPSocket::GetLocalIPAddress() const {
77 // We bound to port zero, so we need to figure out which port we actually
78 // bound to
80 SocketAddress sock_addr;
81 socklen_t sock_addr_len = sock_addr.GetMaxLength();
82 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
83 return sock_addr.GetIPAddress();
84 }
85 return "";
86}
87
90 SocketAddress sock_addr;
91 socklen_t sock_addr_len = sock_addr.GetMaxLength();
92 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
93 return sock_addr.GetPort();
94 }
95 return 0;
96}
97
98std::string TCPSocket::GetRemoteIPAddress() const {
99 // We bound to port zero, so we need to figure out which port we actually
100 // bound to
102 SocketAddress sock_addr;
103 socklen_t sock_addr_len = sock_addr.GetMaxLength();
104 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
105 return sock_addr.GetIPAddress();
106 }
107 return "";
108}
109
112 return std::string(llvm::formatv(
113 "connect://[{0}]:{1}", GetRemoteIPAddress(), GetRemotePortNumber()));
114 }
115 return "";
116}
117
118std::vector<std::string> TCPSocket::GetListeningConnectionURI() const {
119 std::vector<std::string> URIs;
120 for (const auto &[fd, addr] : m_listen_sockets)
121 URIs.emplace_back(llvm::formatv("connection://[{0}]:{1}",
122 addr.GetIPAddress(), addr.GetPort()));
123 return URIs;
124}
125
128 if (IsValid())
129 error = Close();
130 if (error.Fail())
131 return error;
132 m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP, error);
133 return error;
134}
135
136Status TCPSocket::Connect(llvm::StringRef name) {
137
139 LLDB_LOG(log, "Connect to host/port {0}", name);
140
142 llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);
143 if (!host_port)
144 return Status::FromError(host_port.takeError());
145
146 std::vector<SocketAddress> addresses =
147 SocketAddress::GetAddressInfo(host_port->hostname.c_str(), nullptr,
148 AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
149 for (SocketAddress &address : addresses) {
150 error = CreateSocket(address.GetFamily());
151 if (error.Fail())
152 continue;
153
154 address.SetPort(host_port->port);
155
156 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
157 &address.sockaddr(),
158 address.GetLength()) == -1) {
159 Close();
160 continue;
161 }
162
163 if (SetOptionNoDelay() == -1) {
164 Close();
165 continue;
166 }
167
168 error.Clear();
169 return error;
170 }
171
172 error = Status::FromErrorString("Failed to connect port");
173 return error;
174}
175
176Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
178 LLDB_LOG(log, "Listen to {0}", name);
179
181 llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);
182 if (!host_port)
183 return Status::FromError(host_port.takeError());
184
185 if (host_port->hostname == "*")
186 host_port->hostname = "0.0.0.0";
187 std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
188 host_port->hostname.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
189 for (SocketAddress &address : addresses) {
190 int fd =
191 Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, error);
192 if (error.Fail() || fd < 0)
193 continue;
194
195 // enable local address reuse
196 if (SetOption(fd, SOL_SOCKET, SO_REUSEADDR, 1) == -1) {
197 CloseSocket(fd);
198 continue;
199 }
200
201 SocketAddress listen_address = address;
202 if(!listen_address.IsLocalhost())
203 listen_address.SetToAnyAddress(address.GetFamily(), host_port->port);
204 else
205 listen_address.SetPort(host_port->port);
206
207 int err =
208 ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
209 if (err != -1)
210 err = ::listen(fd, backlog);
211
212 if (err == -1) {
214 CloseSocket(fd);
215 continue;
216 }
217
218 if (host_port->port == 0) {
219 socklen_t sa_len = listen_address.GetLength();
220 if (getsockname(fd, &listen_address.sockaddr(), &sa_len) == 0)
221 host_port->port = listen_address.GetPort();
222 }
223 m_listen_sockets[fd] = listen_address;
224 }
225
226 if (m_listen_sockets.empty()) {
227 assert(error.Fail());
228 return error;
229 }
230 return Status();
231}
232
234 for (auto socket : m_listen_sockets)
235 CloseSocket(socket.first);
236 m_listen_sockets.clear();
237}
238
239llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
241 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
242 if (m_listen_sockets.size() == 0)
243 return llvm::createStringError("No open listening sockets!");
244
245 std::vector<MainLoopBase::ReadHandleUP> handles;
246 for (auto socket : m_listen_sockets) {
247 auto fd = socket.first;
248 auto io_sp = std::make_shared<TCPSocket>(fd, false);
249 auto cb = [this, fd, sock_cb](MainLoopBase &loop) {
251 socklen_t sa_len = AcceptAddr.GetMaxLength();
253 NativeSocket sock =
254 AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, error);
255 Log *log = GetLog(LLDBLog::Host);
256 if (error.Fail()) {
257 LLDB_LOG(log, "AcceptSocket({0}): {1}", fd, error);
258 return;
259 }
260
262 if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
263 CloseSocket(sock);
264 LLDB_LOG(log, "rejecting incoming connection from {0} (expecting {1})",
265 AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
266 return;
267 }
268 std::unique_ptr<TCPSocket> sock_up(new TCPSocket(sock, *this));
269
270 // Keep our TCP packets coming without any delays.
271 sock_up->SetOptionNoDelay();
272
273 sock_cb(std::move(sock_up));
274 };
276 handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));
277 if (error.Fail())
278 return error.ToError();
279 }
280
281 return handles;
282}
283
285 return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
286}
287
289 return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
290}
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:138
static const NativeSocket kInvalidSocketValue
Definition: Socket.h:86
static NativeSocket CreateSocket(const int domain, const int type, const int protocol, Status &error)
Definition: Socket.cpp:436
static llvm::Expected< HostAndPort > DecodeHostAndPort(llvm::StringRef host_and_port)
Definition: Socket.cpp:287
static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, Status &error)
Definition: Socket.cpp:472
static Status GetLastError()
Definition: Socket.cpp:418
static int CloseSocket(NativeSocket sockfd)
Definition: Socket.cpp:428
NativeSocket m_socket
Definition: Socket.h:174
static int SetOption(NativeSocket sockfd, int level, int option_name, int option_value)
Definition: Socket.cpp:398
Status Close() override
Definition: Socket.cpp:370
An error handling class.
Definition: Status.h:118
static Status FromErrorString(const char *str)
Definition: Status.h:141
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
Definition: TCPSocket.cpp:118
Status Listen(llvm::StringRef name, int backlog) override
Definition: TCPSocket.cpp:176
bool IsValid() const override
Definition: TCPSocket.cpp:55
uint16_t GetRemotePortNumber() const
Definition: TCPSocket.cpp:88
Status CreateSocket(int domain)
Definition: TCPSocket.cpp:126
std::string GetRemoteConnectionURI() const override
Definition: TCPSocket.cpp:110
llvm::Expected< std::vector< MainLoopBase::ReadHandleUP > > Accept(MainLoopBase &loop, std::function< void(std::unique_ptr< Socket > socket)> sock_cb) override
Definition: TCPSocket.cpp:240
std::string GetLocalIPAddress() const
Definition: TCPSocket.cpp:76
std::string GetRemoteIPAddress() const
Definition: TCPSocket.cpp:98
uint16_t GetLocalPortNumber() const
Definition: TCPSocket.cpp:60
TCPSocket(bool should_close)
Definition: TCPSocket.cpp:41
std::map< int, SocketAddress > m_listen_sockets
Definition: TCPSocket.h:64
Status Connect(llvm::StringRef name) override
Definition: TCPSocket.cpp:136
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
Definition: SBAddress.h:15