xref: /freebsd-src/contrib/llvm-project/lldb/source/Host/common/TCPSocket.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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 #ifndef LLDB_DISABLE_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 
49 TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)
50     : Socket(ProtocolTcp, should_close, child_processes_inherit) {}
51 
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 
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 
64 TCPSocket::~TCPSocket() { CloseListenSockets(); }
65 
66 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.
71 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 
87 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 
99 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 
109 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 
121 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 
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 
140 Status TCPSocket::Connect(llvm::StringRef name) {
141 
142   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
143   if (log)
144     log->Printf("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
145 
146   Status error;
147   std::string host_str;
148   std::string port_str;
149   int32_t port = INT32_MIN;
150   if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
151     return error;
152 
153   auto addresses = lldb_private::SocketAddress::GetAddressInfo(
154       host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
155   for (auto address : addresses) {
156     error = CreateSocket(address.GetFamily());
157     if (error.Fail())
158       continue;
159 
160     address.SetPort(port);
161 
162     if (-1 == llvm::sys::RetryAfterSignal(-1, ::connect,
163           GetNativeSocket(), &address.sockaddr(), address.GetLength())) {
164       CLOSE_SOCKET(GetNativeSocket());
165       continue;
166     }
167 
168     SetOptionNoDelay();
169 
170     error.Clear();
171     return error;
172   }
173 
174   error.SetErrorString("Failed to connect port");
175   return error;
176 }
177 
178 Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
179   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
180   if (log)
181     log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data());
182 
183   Status error;
184   std::string host_str;
185   std::string port_str;
186   int32_t port = INT32_MIN;
187   if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
188     return error;
189 
190   if (host_str == "*")
191     host_str = "0.0.0.0";
192   auto addresses = lldb_private::SocketAddress::GetAddressInfo(
193       host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
194   for (auto address : addresses) {
195     int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
196                                   m_child_processes_inherit, error);
197     if (error.Fail()) {
198       error.Clear();
199       continue;
200     }
201 
202     // enable local address reuse
203     int option_value = 1;
204     set_socket_option_arg_type option_value_p =
205         reinterpret_cast<set_socket_option_arg_type>(&option_value);
206     ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
207                  sizeof(option_value));
208 
209     SocketAddress listen_address = address;
210     if(!listen_address.IsLocalhost())
211       listen_address.SetToAnyAddress(address.GetFamily(), port);
212     else
213       listen_address.SetPort(port);
214 
215     int err =
216         ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
217     if (-1 != err)
218       err = ::listen(fd, backlog);
219 
220     if (-1 == err) {
221       CLOSE_SOCKET(fd);
222       continue;
223     }
224 
225     if (port == 0) {
226       socklen_t sa_len = address.GetLength();
227       if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
228         port = address.GetPort();
229     }
230     m_listen_sockets[fd] = address;
231   }
232 
233   if (m_listen_sockets.size() == 0)
234     error.SetErrorString("Failed to connect port");
235   return error;
236 }
237 
238 void TCPSocket::CloseListenSockets() {
239   for (auto socket : m_listen_sockets)
240   CLOSE_SOCKET(socket.first);
241   m_listen_sockets.clear();
242 }
243 
244 Status TCPSocket::Accept(Socket *&conn_socket) {
245   Status error;
246   if (m_listen_sockets.size() == 0) {
247     error.SetErrorString("No open listening sockets!");
248     return error;
249   }
250 
251   int sock = -1;
252   int listen_sock = -1;
253   lldb_private::SocketAddress AcceptAddr;
254   MainLoop accept_loop;
255   std::vector<MainLoopBase::ReadHandleUP> handles;
256   for (auto socket : m_listen_sockets) {
257     auto fd = socket.first;
258     auto inherit = this->m_child_processes_inherit;
259     auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));
260     handles.emplace_back(accept_loop.RegisterReadObject(
261         io_sp, [fd, inherit, &sock, &AcceptAddr, &error,
262                         &listen_sock](MainLoopBase &loop) {
263           socklen_t sa_len = AcceptAddr.GetMaxLength();
264           sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,
265                               error);
266           listen_sock = fd;
267           loop.RequestTermination();
268         }, error));
269     if (error.Fail())
270       return error;
271   }
272 
273   bool accept_connection = false;
274   std::unique_ptr<TCPSocket> accepted_socket;
275   // Loop until we are happy with our connection
276   while (!accept_connection) {
277     accept_loop.Run();
278 
279     if (error.Fail())
280         return error;
281 
282     lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
283     if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
284       CLOSE_SOCKET(sock);
285       llvm::errs() << llvm::formatv(
286           "error: rejecting incoming connection from {0} (expecting {1})",
287           AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
288       continue;
289     }
290     accept_connection = true;
291     accepted_socket.reset(new TCPSocket(sock, *this));
292   }
293 
294   if (!accepted_socket)
295     return error;
296 
297   // Keep our TCP packets coming without any delays.
298   accepted_socket->SetOptionNoDelay();
299   error.Clear();
300   conn_socket = accepted_socket.release();
301   return error;
302 }
303 
304 int TCPSocket::SetOptionNoDelay() {
305   return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
306 }
307 
308 int TCPSocket::SetOptionReuseAddress() {
309   return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
310 }
311