180814287SRaphael Isemann //===-- TCPSocket.cpp -----------------------------------------------------===//
2e98628ceSOleksiy Vyalov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e98628ceSOleksiy Vyalov //
7e98628ceSOleksiy Vyalov //===----------------------------------------------------------------------===//
8e98628ceSOleksiy Vyalov 
95a8ad459SZachary Turner #if defined(_MSC_VER)
105a8ad459SZachary Turner #define _WINSOCK_DEPRECATED_NO_WARNINGS
115a8ad459SZachary Turner #endif
125a8ad459SZachary Turner 
13e98628ceSOleksiy Vyalov #include "lldb/Host/common/TCPSocket.h"
14e98628ceSOleksiy Vyalov 
15e98628ceSOleksiy Vyalov #include "lldb/Host/Config.h"
1611827799SChris Bieneman #include "lldb/Host/MainLoop.h"
17c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
186f9e6901SZachary Turner #include "lldb/Utility/Log.h"
19e98628ceSOleksiy Vyalov 
209f3dd759SKamil Rytarowski #include "llvm/Config/llvm-config.h"
212819136fSMichal Gorny #include "llvm/Support/Errno.h"
2258435f69SPavel Labath #include "llvm/Support/WindowsError.h"
2311827799SChris Bieneman #include "llvm/Support/raw_ostream.h"
2411827799SChris Bieneman 
253011d55fSJonas Devlieghere #if LLDB_ENABLE_POSIX
26e98628ceSOleksiy Vyalov #include <arpa/inet.h>
27e98628ceSOleksiy Vyalov #include <netinet/tcp.h>
28e98628ceSOleksiy Vyalov #include <sys/socket.h>
29e98628ceSOleksiy Vyalov #endif
30e98628ceSOleksiy Vyalov 
31b1cb0b79SNico Weber #if defined(_WIN32)
3211827799SChris Bieneman #include <winsock2.h>
3311827799SChris Bieneman #endif
3411827799SChris Bieneman 
35b1cb0b79SNico Weber #ifdef _WIN32
3611827799SChris Bieneman #define CLOSE_SOCKET closesocket
372d1f6e11SChris Bieneman typedef const char *set_socket_option_arg_type;
3811827799SChris Bieneman #else
39b6dbe9a9SPavel Labath #include <unistd.h>
4011827799SChris Bieneman #define CLOSE_SOCKET ::close
412d1f6e11SChris Bieneman typedef const void *set_socket_option_arg_type;
4211827799SChris Bieneman #endif
4311827799SChris Bieneman 
44e98628ceSOleksiy Vyalov using namespace lldb;
45e98628ceSOleksiy Vyalov using namespace lldb_private;
46e98628ceSOleksiy Vyalov 
GetLastSocketError()4718e96a31SPavel Labath static Status GetLastSocketError() {
4818e96a31SPavel Labath   std::error_code EC;
4918e96a31SPavel Labath #ifdef _WIN32
5018e96a31SPavel Labath   EC = llvm::mapWindowsError(WSAGetLastError());
5118e96a31SPavel Labath #else
5218e96a31SPavel Labath   EC = std::error_code(errno, std::generic_category());
5318e96a31SPavel Labath #endif
5418e96a31SPavel Labath   return EC;
5518e96a31SPavel Labath }
5618e96a31SPavel Labath 
5793c1b3caSPavel Labath static const int kType = SOCK_STREAM;
58e98628ceSOleksiy Vyalov 
TCPSocket(bool should_close,bool child_processes_inherit)5911827799SChris Bieneman TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)
6011827799SChris Bieneman     : Socket(ProtocolTcp, should_close, child_processes_inherit) {}
61e98628ceSOleksiy Vyalov 
TCPSocket(NativeSocket socket,const TCPSocket & listen_socket)6211827799SChris Bieneman TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket)
6311827799SChris Bieneman     : Socket(ProtocolTcp, listen_socket.m_should_close_fd,
6411827799SChris Bieneman              listen_socket.m_child_processes_inherit) {
6511827799SChris Bieneman   m_socket = socket;
6611827799SChris Bieneman }
6711827799SChris Bieneman 
TCPSocket(NativeSocket socket,bool should_close,bool child_processes_inherit)6811827799SChris Bieneman TCPSocket::TCPSocket(NativeSocket socket, bool should_close,
6911827799SChris Bieneman                      bool child_processes_inherit)
7011827799SChris Bieneman     : Socket(ProtocolTcp, should_close, child_processes_inherit) {
7111827799SChris Bieneman   m_socket = socket;
7211827799SChris Bieneman }
7311827799SChris Bieneman 
~TCPSocket()7411827799SChris Bieneman TCPSocket::~TCPSocket() { CloseListenSockets(); }
7511827799SChris Bieneman 
IsValid() const7611827799SChris Bieneman bool TCPSocket::IsValid() const {
7711827799SChris Bieneman   return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
7811827799SChris Bieneman }
79e98628ceSOleksiy Vyalov 
80e98628ceSOleksiy Vyalov // Return the port number that is being used by the socket.
GetLocalPortNumber() const81b9c1b51eSKate Stone uint16_t TCPSocket::GetLocalPortNumber() const {
82b9c1b51eSKate Stone   if (m_socket != kInvalidSocketValue) {
83e98628ceSOleksiy Vyalov     SocketAddress sock_addr;
84e98628ceSOleksiy Vyalov     socklen_t sock_addr_len = sock_addr.GetMaxLength();
85e98628ceSOleksiy Vyalov     if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
86e98628ceSOleksiy Vyalov       return sock_addr.GetPort();
8711827799SChris Bieneman   } else if (!m_listen_sockets.empty()) {
8811827799SChris Bieneman     SocketAddress sock_addr;
8911827799SChris Bieneman     socklen_t sock_addr_len = sock_addr.GetMaxLength();
9011827799SChris Bieneman     if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
9111827799SChris Bieneman                       &sock_addr_len) == 0)
9211827799SChris Bieneman       return sock_addr.GetPort();
93e98628ceSOleksiy Vyalov   }
94e98628ceSOleksiy Vyalov   return 0;
95e98628ceSOleksiy Vyalov }
96e98628ceSOleksiy Vyalov 
GetLocalIPAddress() const97b9c1b51eSKate Stone std::string TCPSocket::GetLocalIPAddress() const {
98b9c1b51eSKate Stone   // We bound to port zero, so we need to figure out which port we actually
99b9c1b51eSKate Stone   // bound to
100b9c1b51eSKate Stone   if (m_socket != kInvalidSocketValue) {
101e98628ceSOleksiy Vyalov     SocketAddress sock_addr;
102e98628ceSOleksiy Vyalov     socklen_t sock_addr_len = sock_addr.GetMaxLength();
103e98628ceSOleksiy Vyalov     if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
104e98628ceSOleksiy Vyalov       return sock_addr.GetIPAddress();
105e98628ceSOleksiy Vyalov   }
106e98628ceSOleksiy Vyalov   return "";
107e98628ceSOleksiy Vyalov }
108e98628ceSOleksiy Vyalov 
GetRemotePortNumber() const109b9c1b51eSKate Stone uint16_t TCPSocket::GetRemotePortNumber() const {
110b9c1b51eSKate Stone   if (m_socket != kInvalidSocketValue) {
111e98628ceSOleksiy Vyalov     SocketAddress sock_addr;
112e98628ceSOleksiy Vyalov     socklen_t sock_addr_len = sock_addr.GetMaxLength();
113e98628ceSOleksiy Vyalov     if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
114e98628ceSOleksiy Vyalov       return sock_addr.GetPort();
115e98628ceSOleksiy Vyalov   }
116e98628ceSOleksiy Vyalov   return 0;
117e98628ceSOleksiy Vyalov }
118e98628ceSOleksiy Vyalov 
GetRemoteIPAddress() const119b9c1b51eSKate Stone std::string TCPSocket::GetRemoteIPAddress() const {
120b9c1b51eSKate Stone   // We bound to port zero, so we need to figure out which port we actually
121b9c1b51eSKate Stone   // bound to
122b9c1b51eSKate Stone   if (m_socket != kInvalidSocketValue) {
123e98628ceSOleksiy Vyalov     SocketAddress sock_addr;
124e98628ceSOleksiy Vyalov     socklen_t sock_addr_len = sock_addr.GetMaxLength();
125e98628ceSOleksiy Vyalov     if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
126e98628ceSOleksiy Vyalov       return sock_addr.GetIPAddress();
127e98628ceSOleksiy Vyalov   }
128e98628ceSOleksiy Vyalov   return "";
129e98628ceSOleksiy Vyalov }
130e98628ceSOleksiy Vyalov 
GetRemoteConnectionURI() const131d5560951SAntonio Afonso std::string TCPSocket::GetRemoteConnectionURI() const {
132d5560951SAntonio Afonso   if (m_socket != kInvalidSocketValue) {
133adcd0268SBenjamin Kramer     return std::string(llvm::formatv(
134adcd0268SBenjamin Kramer         "connect://[{0}]:{1}", GetRemoteIPAddress(), GetRemotePortNumber()));
135d5560951SAntonio Afonso   }
136d5560951SAntonio Afonso   return "";
1375a2a0540SAlexandre Ganea }
138d5560951SAntonio Afonso 
CreateSocket(int domain)13997206d57SZachary Turner Status TCPSocket::CreateSocket(int domain) {
14097206d57SZachary Turner   Status error;
14111827799SChris Bieneman   if (IsValid())
14211827799SChris Bieneman     error = Close();
14311827799SChris Bieneman   if (error.Fail())
14411827799SChris Bieneman     return error;
14511827799SChris Bieneman   m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP,
14611827799SChris Bieneman                                   m_child_processes_inherit, error);
14711827799SChris Bieneman   return error;
14811827799SChris Bieneman }
14911827799SChris Bieneman 
Connect(llvm::StringRef name)15097206d57SZachary Turner Status TCPSocket::Connect(llvm::StringRef name) {
151e98628ceSOleksiy Vyalov 
152a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Communication);
15363e5fb76SJonas Devlieghere   LLDB_LOGF(log, "TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
154e98628ceSOleksiy Vyalov 
15597206d57SZachary Turner   Status error;
156073c5d0eSMichał Górny   llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);
157073c5d0eSMichał Górny   if (!host_port)
158073c5d0eSMichał Górny     return Status(host_port.takeError());
159e98628ceSOleksiy Vyalov 
160073c5d0eSMichał Górny   std::vector<SocketAddress> addresses =
161073c5d0eSMichał Górny       SocketAddress::GetAddressInfo(host_port->hostname.c_str(), nullptr,
162073c5d0eSMichał Górny                                     AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
1636aa60b05SPavel Labath   for (SocketAddress &address : addresses) {
16411827799SChris Bieneman     error = CreateSocket(address.GetFamily());
16511827799SChris Bieneman     if (error.Fail())
16611827799SChris Bieneman       continue;
167e98628ceSOleksiy Vyalov 
168073c5d0eSMichał Górny     address.SetPort(host_port->port);
169e98628ceSOleksiy Vyalov 
170073c5d0eSMichał Górny     if (-1 == llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
171073c5d0eSMichał Górny                                           &address.sockaddr(),
172073c5d0eSMichał Górny                                           address.GetLength())) {
173*926a7ecdSPavel Labath       Close();
17411827799SChris Bieneman       continue;
175e98628ceSOleksiy Vyalov     }
176e98628ceSOleksiy Vyalov 
177107e6942SPavel Labath     SetOptionNoDelay();
17811827799SChris Bieneman 
179e98628ceSOleksiy Vyalov     error.Clear();
180e98628ceSOleksiy Vyalov     return error;
181e98628ceSOleksiy Vyalov   }
182e98628ceSOleksiy Vyalov 
18311827799SChris Bieneman   error.SetErrorString("Failed to connect port");
18411827799SChris Bieneman   return error;
18511827799SChris Bieneman }
18611827799SChris Bieneman 
Listen(llvm::StringRef name,int backlog)18797206d57SZachary Turner Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
188a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Connection);
18963e5fb76SJonas Devlieghere   LLDB_LOGF(log, "TCPSocket::%s (%s)", __FUNCTION__, name.data());
190e98628ceSOleksiy Vyalov 
19197206d57SZachary Turner   Status error;
192073c5d0eSMichał Górny   llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);
193073c5d0eSMichał Górny   if (!host_port)
194073c5d0eSMichał Górny     return Status(host_port.takeError());
195e98628ceSOleksiy Vyalov 
196073c5d0eSMichał Górny   if (host_port->hostname == "*")
197073c5d0eSMichał Górny     host_port->hostname = "0.0.0.0";
1986aa60b05SPavel Labath   std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(
199073c5d0eSMichał Górny       host_port->hostname.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
2006aa60b05SPavel Labath   for (SocketAddress &address : addresses) {
20111827799SChris Bieneman     int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
20211827799SChris Bieneman                                   m_child_processes_inherit, error);
20318e96a31SPavel Labath     if (error.Fail())
20411827799SChris Bieneman       continue;
205e98628ceSOleksiy Vyalov 
20611827799SChris Bieneman     // enable local address reuse
20711827799SChris Bieneman     int option_value = 1;
2087ba4d851SChris Bieneman     set_socket_option_arg_type option_value_p =
20926beacc1SChris Bieneman         reinterpret_cast<set_socket_option_arg_type>(&option_value);
2107ba4d851SChris Bieneman     ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
21111827799SChris Bieneman                  sizeof(option_value));
212e98628ceSOleksiy Vyalov 
213c6f6aa44SChris Bieneman     SocketAddress listen_address = address;
214c6f6aa44SChris Bieneman     if(!listen_address.IsLocalhost())
215073c5d0eSMichał Górny       listen_address.SetToAnyAddress(address.GetFamily(), host_port->port);
216c6f6aa44SChris Bieneman     else
217073c5d0eSMichał Górny       listen_address.SetPort(host_port->port);
21811827799SChris Bieneman 
219c6f6aa44SChris Bieneman     int err =
220c6f6aa44SChris Bieneman         ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
22111827799SChris Bieneman     if (-1 != err)
22211827799SChris Bieneman       err = ::listen(fd, backlog);
22311827799SChris Bieneman 
22411827799SChris Bieneman     if (-1 == err) {
22518e96a31SPavel Labath       error = GetLastSocketError();
22611827799SChris Bieneman       CLOSE_SOCKET(fd);
22711827799SChris Bieneman       continue;
22811827799SChris Bieneman     }
22911827799SChris Bieneman 
230073c5d0eSMichał Górny     if (host_port->port == 0) {
23111827799SChris Bieneman       socklen_t sa_len = address.GetLength();
23211827799SChris Bieneman       if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
233073c5d0eSMichał Górny         host_port->port = address.GetPort();
23411827799SChris Bieneman     }
23511827799SChris Bieneman     m_listen_sockets[fd] = address;
23611827799SChris Bieneman   }
23711827799SChris Bieneman 
2384d40d664SEric Christopher   if (m_listen_sockets.empty()) {
23918e96a31SPavel Labath     assert(error.Fail());
240e98628ceSOleksiy Vyalov     return error;
241e98628ceSOleksiy Vyalov   }
24218e96a31SPavel Labath   return Status();
24318e96a31SPavel Labath }
244e98628ceSOleksiy Vyalov 
CloseListenSockets()24511827799SChris Bieneman void TCPSocket::CloseListenSockets() {
24611827799SChris Bieneman   for (auto socket : m_listen_sockets)
24711827799SChris Bieneman     CLOSE_SOCKET(socket.first);
24811827799SChris Bieneman   m_listen_sockets.clear();
249e98628ceSOleksiy Vyalov }
250e98628ceSOleksiy Vyalov 
Accept(Socket * & conn_socket)25197206d57SZachary Turner Status TCPSocket::Accept(Socket *&conn_socket) {
25297206d57SZachary Turner   Status error;
25311827799SChris Bieneman   if (m_listen_sockets.size() == 0) {
25411827799SChris Bieneman     error.SetErrorString("No open listening sockets!");
255e98628ceSOleksiy Vyalov     return error;
256e98628ceSOleksiy Vyalov   }
25711827799SChris Bieneman 
25811827799SChris Bieneman   int sock = -1;
25911827799SChris Bieneman   int listen_sock = -1;
26011827799SChris Bieneman   lldb_private::SocketAddress AcceptAddr;
26111827799SChris Bieneman   MainLoop accept_loop;
26211827799SChris Bieneman   std::vector<MainLoopBase::ReadHandleUP> handles;
26311827799SChris Bieneman   for (auto socket : m_listen_sockets) {
26411827799SChris Bieneman     auto fd = socket.first;
26511827799SChris Bieneman     auto inherit = this->m_child_processes_inherit;
26611827799SChris Bieneman     auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));
26711827799SChris Bieneman     handles.emplace_back(accept_loop.RegisterReadObject(
26811827799SChris Bieneman         io_sp, [fd, inherit, &sock, &AcceptAddr, &error,
26911827799SChris Bieneman                         &listen_sock](MainLoopBase &loop) {
27011827799SChris Bieneman           socklen_t sa_len = AcceptAddr.GetMaxLength();
27111827799SChris Bieneman           sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,
27211827799SChris Bieneman                               error);
27311827799SChris Bieneman           listen_sock = fd;
27411827799SChris Bieneman           loop.RequestTermination();
27511827799SChris Bieneman         }, error));
27611827799SChris Bieneman     if (error.Fail())
27711827799SChris Bieneman       return error;
278e98628ceSOleksiy Vyalov   }
279e98628ceSOleksiy Vyalov 
280e98628ceSOleksiy Vyalov   bool accept_connection = false;
281e98628ceSOleksiy Vyalov   std::unique_ptr<TCPSocket> accepted_socket;
282e98628ceSOleksiy Vyalov   // Loop until we are happy with our connection
283b9c1b51eSKate Stone   while (!accept_connection) {
28411827799SChris Bieneman     accept_loop.Run();
285e98628ceSOleksiy Vyalov 
286e98628ceSOleksiy Vyalov     if (error.Fail())
28711827799SChris Bieneman         return error;
288e98628ceSOleksiy Vyalov 
28911827799SChris Bieneman     lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
29011827799SChris Bieneman     if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
29111827799SChris Bieneman       CLOSE_SOCKET(sock);
29211827799SChris Bieneman       llvm::errs() << llvm::formatv(
29311827799SChris Bieneman           "error: rejecting incoming connection from {0} (expecting {1})",
29411827799SChris Bieneman           AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
29511827799SChris Bieneman       continue;
296107e6942SPavel Labath     }
29711827799SChris Bieneman     accept_connection = true;
29811827799SChris Bieneman     accepted_socket.reset(new TCPSocket(sock, *this));
299e98628ceSOleksiy Vyalov   }
300e98628ceSOleksiy Vyalov 
301e98628ceSOleksiy Vyalov   if (!accepted_socket)
302e98628ceSOleksiy Vyalov     return error;
303e98628ceSOleksiy Vyalov 
304e98628ceSOleksiy Vyalov   // Keep our TCP packets coming without any delays.
305e98628ceSOleksiy Vyalov   accepted_socket->SetOptionNoDelay();
306e98628ceSOleksiy Vyalov   error.Clear();
307e98628ceSOleksiy Vyalov   conn_socket = accepted_socket.release();
308e98628ceSOleksiy Vyalov   return error;
309e98628ceSOleksiy Vyalov }
310e98628ceSOleksiy Vyalov 
SetOptionNoDelay()311b9c1b51eSKate Stone int TCPSocket::SetOptionNoDelay() {
312e98628ceSOleksiy Vyalov   return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
313e98628ceSOleksiy Vyalov }
314e98628ceSOleksiy Vyalov 
SetOptionReuseAddress()315b9c1b51eSKate Stone int TCPSocket::SetOptionReuseAddress() {
316e98628ceSOleksiy Vyalov   return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
317e98628ceSOleksiy Vyalov }
318