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
13#include "lldb/Host/common/TCPSocket.h"
14
15#include "lldb/Host/Config.h"
16#include "lldb/Host/MainLoop.h"
17#include "lldb/Utility/LLDBLog.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
53TCPSocket::~TCPSocket() { CloseListenSockets(); }
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.
60uint16_t TCPSocket::GetLocalPortNumber() const {
61 if (m_socket != kInvalidSocketValue) {
62 SocketAddress sock_addr;
63 socklen_t sock_addr_len = sock_addr.GetMaxLength();
64 if (::getsockname(fd: m_socket, addr: sock_addr, len: &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(fd: m_listen_sockets.begin()->first, addr: sock_addr,
70 len: &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
79 if (m_socket != kInvalidSocketValue) {
80 SocketAddress sock_addr;
81 socklen_t sock_addr_len = sock_addr.GetMaxLength();
82 if (::getsockname(fd: m_socket, addr: sock_addr, len: &sock_addr_len) == 0)
83 return sock_addr.GetIPAddress();
84 }
85 return "";
86}
87
88uint16_t TCPSocket::GetRemotePortNumber() const {
89 if (m_socket != kInvalidSocketValue) {
90 SocketAddress sock_addr;
91 socklen_t sock_addr_len = sock_addr.GetMaxLength();
92 if (::getpeername(fd: m_socket, addr: sock_addr, len: &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
101 if (m_socket != kInvalidSocketValue) {
102 SocketAddress sock_addr;
103 socklen_t sock_addr_len = sock_addr.GetMaxLength();
104 if (::getpeername(fd: m_socket, addr: sock_addr, len: &sock_addr_len) == 0)
105 return sock_addr.GetIPAddress();
106 }
107 return "";
108}
109
110std::string TCPSocket::GetRemoteConnectionURI() const {
111 if (m_socket != kInvalidSocketValue) {
112 return std::string(llvm::formatv(
113 Fmt: "connect://[{0}]:{1}", Vals: GetRemoteIPAddress(), Vals: 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(args: llvm::formatv(Fmt: "connection://[{0}]:{1}",
122 Vals: addr.GetIPAddress(), Vals: addr.GetPort()));
123 return URIs;
124}
125
126Status TCPSocket::CreateSocket(int domain) {
127 Status error;
128 if (IsValid())
129 error = Close();
130 if (error.Fail())
131 return error;
132 m_socket = Socket::CreateSocket(domain, type: kType, IPPROTO_TCP, error);
133 return error;
134}
135
136Status TCPSocket::Connect(llvm::StringRef name) {
137
138 Log *log = GetLog(mask: LLDBLog::Communication);
139 LLDB_LOG(log, "Connect to host/port {0}", name);
140
141 Status error;
142 llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(host_and_port: name);
143 if (!host_port)
144 return Status::FromError(error: host_port.takeError());
145
146 std::vector<SocketAddress> addresses =
147 SocketAddress::GetAddressInfo(hostname: host_port->hostname.c_str(), servname: nullptr,
148 AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
149 for (SocketAddress &address : addresses) {
150 error = CreateSocket(domain: address.GetFamily());
151 if (error.Fail())
152 continue;
153
154 address.SetPort(host_port->port);
155
156 if (llvm::sys::RetryAfterSignal(Fail: -1, F&: ::connect, As: GetNativeSocket(),
157 As: &address.sockaddr(),
158 As: 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::FromErrorStringWithFormatv(
173 format: "Failed to connect to {0}:{1}", args&: host_port->hostname, args&: host_port->port);
174 return error;
175}
176
177Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
178 Log *log = GetLog(mask: LLDBLog::Connection);
179 LLDB_LOG(log, "Listen to {0}", name);
180
181 Status error;
182 llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(host_and_port: name);
183 if (!host_port)
184 return Status::FromError(error: host_port.takeError());
185
186 if (host_port->hostname == "*")
187 host_port->hostname = "0.0.0.0";
188 std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
189 hostname: host_port->hostname.c_str(), servname: nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
190 for (SocketAddress &address : addresses) {
191 int fd =
192 Socket::CreateSocket(domain: address.GetFamily(), type: kType, IPPROTO_TCP, error);
193 if (error.Fail() || fd < 0)
194 continue;
195
196 // enable local address reuse
197 if (SetOption(sockfd: fd, SOL_SOCKET, SO_REUSEADDR, option_value: 1) == -1) {
198 CloseSocket(sockfd: fd);
199 continue;
200 }
201
202 SocketAddress listen_address = address;
203 if(!listen_address.IsLocalhost())
204 listen_address.SetToAnyAddress(family: address.GetFamily(), port: host_port->port);
205 else
206 listen_address.SetPort(host_port->port);
207
208 int err =
209 ::bind(fd: fd, addr: &listen_address.sockaddr(), len: listen_address.GetLength());
210 if (err != -1)
211 err = ::listen(fd: fd, n: backlog);
212
213 if (err == -1) {
214 error = GetLastError();
215 CloseSocket(sockfd: fd);
216 continue;
217 }
218
219 if (host_port->port == 0) {
220 socklen_t sa_len = listen_address.GetLength();
221 if (getsockname(fd: fd, addr: &listen_address.sockaddr(), len: &sa_len) == 0)
222 host_port->port = listen_address.GetPort();
223 }
224 m_listen_sockets[fd] = listen_address;
225 }
226
227 if (m_listen_sockets.empty()) {
228 assert(error.Fail());
229 return error;
230 }
231 return Status();
232}
233
234void TCPSocket::CloseListenSockets() {
235 for (auto socket : m_listen_sockets)
236 CloseSocket(sockfd: socket.first);
237 m_listen_sockets.clear();
238}
239
240llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
241TCPSocket::Accept(MainLoopBase &loop,
242 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
243 if (m_listen_sockets.size() == 0)
244 return llvm::createStringError(Fmt: "No open listening sockets!");
245
246 std::vector<MainLoopBase::ReadHandleUP> handles;
247 for (auto socket : m_listen_sockets) {
248 auto fd = socket.first;
249 auto io_sp = std::make_shared<TCPSocket>(args&: fd, args: false);
250 auto cb = [this, fd, sock_cb](MainLoopBase &loop) {
251 lldb_private::SocketAddress AcceptAddr;
252 socklen_t sa_len = AcceptAddr.GetMaxLength();
253 Status error;
254 NativeSocket sock =
255 AcceptSocket(sockfd: fd, addr: &AcceptAddr.sockaddr(), addrlen: &sa_len, error);
256 Log *log = GetLog(mask: LLDBLog::Host);
257 if (error.Fail()) {
258 LLDB_LOG(log, "AcceptSocket({0}): {1}", fd, error);
259 return;
260 }
261
262 const lldb_private::SocketAddress &AddrIn = m_listen_sockets[fd];
263 if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
264 CloseSocket(sockfd: sock);
265 LLDB_LOG(log, "rejecting incoming connection from {0} (expecting {1})",
266 AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
267 return;
268 }
269 std::unique_ptr<TCPSocket> sock_up(new TCPSocket(sock, *this));
270
271 // Keep our TCP packets coming without any delays.
272 sock_up->SetOptionNoDelay();
273
274 sock_cb(std::move(sock_up));
275 };
276 Status error;
277 handles.emplace_back(args: loop.RegisterReadObject(object_sp: io_sp, callback: cb, error));
278 if (error.Fail())
279 return error.ToError();
280 }
281
282 return handles;
283}
284
285int TCPSocket::SetOptionNoDelay() {
286 return SetOption(IPPROTO_TCP, TCP_NODELAY, option_value: 1);
287}
288
289int TCPSocket::SetOptionReuseAddress() {
290 return SetOption(SOL_SOCKET, SO_REUSEADDR, option_value: 1);
291}
292

source code of lldb/source/Host/common/TCPSocket.cpp