1 //===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===//
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/Log.h"
18
19 #include "llvm/Config/llvm-config.h"
20 #include "llvm/Support/Errno.h"
21 #include "llvm/Support/raw_ostream.h"
22
23 #if LLDB_ENABLE_POSIX
24 #include <arpa/inet.h>
25 #include <netinet/tcp.h>
26 #include <sys/socket.h>
27 #endif
28
29 #if defined(_WIN32)
30 #include <winsock2.h>
31 #endif
32
33 #ifdef _WIN32
34 #define CLOSE_SOCKET closesocket
35 typedef const char *set_socket_option_arg_type;
36 #else
37 #include <unistd.h>
38 #define CLOSE_SOCKET ::close
39 typedef const void *set_socket_option_arg_type;
40 #endif
41
42 using namespace lldb;
43 using namespace lldb_private;
44
45 namespace {
46 const int kType = SOCK_STREAM;
47 }
48
TCPSocket(bool should_close,bool child_processes_inherit)49 TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)
50 : Socket(ProtocolTcp, should_close, child_processes_inherit) {}
51
TCPSocket(NativeSocket socket,const TCPSocket & listen_socket)52 TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket)
53 : Socket(ProtocolTcp, listen_socket.m_should_close_fd,
54 listen_socket.m_child_processes_inherit) {
55 m_socket = socket;
56 }
57
TCPSocket(NativeSocket socket,bool should_close,bool child_processes_inherit)58 TCPSocket::TCPSocket(NativeSocket socket, bool should_close,
59 bool child_processes_inherit)
60 : Socket(ProtocolTcp, should_close, child_processes_inherit) {
61 m_socket = socket;
62 }
63
~TCPSocket()64 TCPSocket::~TCPSocket() { CloseListenSockets(); }
65
IsValid() const66 bool TCPSocket::IsValid() const {
67 return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
68 }
69
70 // Return the port number that is being used by the socket.
GetLocalPortNumber() const71 uint16_t TCPSocket::GetLocalPortNumber() const {
72 if (m_socket != kInvalidSocketValue) {
73 SocketAddress sock_addr;
74 socklen_t sock_addr_len = sock_addr.GetMaxLength();
75 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
76 return sock_addr.GetPort();
77 } else if (!m_listen_sockets.empty()) {
78 SocketAddress sock_addr;
79 socklen_t sock_addr_len = sock_addr.GetMaxLength();
80 if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
81 &sock_addr_len) == 0)
82 return sock_addr.GetPort();
83 }
84 return 0;
85 }
86
GetLocalIPAddress() const87 std::string TCPSocket::GetLocalIPAddress() const {
88 // We bound to port zero, so we need to figure out which port we actually
89 // bound to
90 if (m_socket != kInvalidSocketValue) {
91 SocketAddress sock_addr;
92 socklen_t sock_addr_len = sock_addr.GetMaxLength();
93 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
94 return sock_addr.GetIPAddress();
95 }
96 return "";
97 }
98
GetRemotePortNumber() const99 uint16_t TCPSocket::GetRemotePortNumber() const {
100 if (m_socket != kInvalidSocketValue) {
101 SocketAddress sock_addr;
102 socklen_t sock_addr_len = sock_addr.GetMaxLength();
103 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
104 return sock_addr.GetPort();
105 }
106 return 0;
107 }
108
GetRemoteIPAddress() const109 std::string TCPSocket::GetRemoteIPAddress() const {
110 // We bound to port zero, so we need to figure out which port we actually
111 // bound to
112 if (m_socket != kInvalidSocketValue) {
113 SocketAddress sock_addr;
114 socklen_t sock_addr_len = sock_addr.GetMaxLength();
115 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
116 return sock_addr.GetIPAddress();
117 }
118 return "";
119 }
120
GetRemoteConnectionURI() const121 std::string TCPSocket::GetRemoteConnectionURI() const {
122 if (m_socket != kInvalidSocketValue) {
123 return llvm::formatv("connect://[{0}]:{1}", GetRemoteIPAddress(),
124 GetRemotePortNumber());
125 }
126 return "";
127 }
128
CreateSocket(int domain)129 Status TCPSocket::CreateSocket(int domain) {
130 Status error;
131 if (IsValid())
132 error = Close();
133 if (error.Fail())
134 return error;
135 m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP,
136 m_child_processes_inherit, error);
137 return error;
138 }
139
Connect(llvm::StringRef name)140 Status TCPSocket::Connect(llvm::StringRef name) {
141
142 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
143 LLDB_LOGF(log, "TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
144
145 Status error;
146 std::string host_str;
147 std::string port_str;
148 int32_t port = INT32_MIN;
149 if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
150 return error;
151
152 std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
153 host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
154 for (SocketAddress &address : addresses) {
155 error = CreateSocket(address.GetFamily());
156 if (error.Fail())
157 continue;
158
159 address.SetPort(port);
160
161 if (-1 == llvm::sys::RetryAfterSignal(-1, ::connect,
162 GetNativeSocket(), &address.sockaddr(), address.GetLength())) {
163 CLOSE_SOCKET(GetNativeSocket());
164 continue;
165 }
166
167 SetOptionNoDelay();
168
169 error.Clear();
170 return error;
171 }
172
173 error.SetErrorString("Failed to connect port");
174 return error;
175 }
176
Listen(llvm::StringRef name,int backlog)177 Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
178 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
179 LLDB_LOGF(log, "TCPSocket::%s (%s)", __FUNCTION__, name.data());
180
181 Status error;
182 std::string host_str;
183 std::string port_str;
184 int32_t port = INT32_MIN;
185 if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
186 return error;
187
188 if (host_str == "*")
189 host_str = "0.0.0.0";
190 std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
191 host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
192 for (SocketAddress &address : addresses) {
193 int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
194 m_child_processes_inherit, error);
195 if (error.Fail()) {
196 error.Clear();
197 continue;
198 }
199
200 // enable local address reuse
201 int option_value = 1;
202 set_socket_option_arg_type option_value_p =
203 reinterpret_cast<set_socket_option_arg_type>(&option_value);
204 ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
205 sizeof(option_value));
206
207 SocketAddress listen_address = address;
208 if(!listen_address.IsLocalhost())
209 listen_address.SetToAnyAddress(address.GetFamily(), port);
210 else
211 listen_address.SetPort(port);
212
213 int err =
214 ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
215 if (-1 != err)
216 err = ::listen(fd, backlog);
217
218 if (-1 == err) {
219 CLOSE_SOCKET(fd);
220 continue;
221 }
222
223 if (port == 0) {
224 socklen_t sa_len = address.GetLength();
225 if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
226 port = address.GetPort();
227 }
228 m_listen_sockets[fd] = address;
229 }
230
231 if (m_listen_sockets.size() == 0)
232 error.SetErrorString("Failed to connect port");
233 return error;
234 }
235
CloseListenSockets()236 void TCPSocket::CloseListenSockets() {
237 for (auto socket : m_listen_sockets)
238 CLOSE_SOCKET(socket.first);
239 m_listen_sockets.clear();
240 }
241
Accept(Socket * & conn_socket)242 Status TCPSocket::Accept(Socket *&conn_socket) {
243 Status error;
244 if (m_listen_sockets.size() == 0) {
245 error.SetErrorString("No open listening sockets!");
246 return error;
247 }
248
249 int sock = -1;
250 int listen_sock = -1;
251 lldb_private::SocketAddress AcceptAddr;
252 MainLoop accept_loop;
253 std::vector<MainLoopBase::ReadHandleUP> handles;
254 for (auto socket : m_listen_sockets) {
255 auto fd = socket.first;
256 auto inherit = this->m_child_processes_inherit;
257 auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));
258 handles.emplace_back(accept_loop.RegisterReadObject(
259 io_sp, [fd, inherit, &sock, &AcceptAddr, &error,
260 &listen_sock](MainLoopBase &loop) {
261 socklen_t sa_len = AcceptAddr.GetMaxLength();
262 sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,
263 error);
264 listen_sock = fd;
265 loop.RequestTermination();
266 }, error));
267 if (error.Fail())
268 return error;
269 }
270
271 bool accept_connection = false;
272 std::unique_ptr<TCPSocket> accepted_socket;
273 // Loop until we are happy with our connection
274 while (!accept_connection) {
275 accept_loop.Run();
276
277 if (error.Fail())
278 return error;
279
280 lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
281 if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
282 CLOSE_SOCKET(sock);
283 llvm::errs() << llvm::formatv(
284 "error: rejecting incoming connection from {0} (expecting {1})",
285 AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
286 continue;
287 }
288 accept_connection = true;
289 accepted_socket.reset(new TCPSocket(sock, *this));
290 }
291
292 if (!accepted_socket)
293 return error;
294
295 // Keep our TCP packets coming without any delays.
296 accepted_socket->SetOptionNoDelay();
297 error.Clear();
298 conn_socket = accepted_socket.release();
299 return error;
300 }
301
SetOptionNoDelay()302 int TCPSocket::SetOptionNoDelay() {
303 return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
304 }
305
SetOptionReuseAddress()306 int TCPSocket::SetOptionReuseAddress() {
307 return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
308 }
309