1 //===-- TCPSocket.cpp -----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 #define _WINSOCK_DEPRECATED_NO_WARNINGS
13 #include "lldb/Host/common/TCPSocket.h"
15 #include "lldb/Host/Config.h"
16 #include "lldb/Host/MainLoop.h"
17 #include "lldb/Utility/LLDBLog.h"
18 #include "lldb/Utility/Log.h"
20 #include "llvm/Config/llvm-config.h"
21 #include "llvm/Support/Errno.h"
22 #include "llvm/Support/WindowsError.h"
23 #include "llvm/Support/raw_ostream.h"
26 #include <arpa/inet.h>
27 #include <netinet/tcp.h>
28 #include <sys/socket.h>
36 #define CLOSE_SOCKET closesocket
37 typedef const char *set_socket_option_arg_type
;
40 #define CLOSE_SOCKET ::close
41 typedef const void *set_socket_option_arg_type
;
45 using namespace lldb_private
;
47 static Status
GetLastSocketError() {
50 EC
= llvm::mapWindowsError(WSAGetLastError());
52 EC
= std::error_code(errno
, std::generic_category());
57 static const int kType
= SOCK_STREAM
;
59 TCPSocket::TCPSocket(bool should_close
, bool child_processes_inherit
)
60 : Socket(ProtocolTcp
, should_close
, child_processes_inherit
) {}
62 TCPSocket::TCPSocket(NativeSocket socket
, const TCPSocket
&listen_socket
)
63 : Socket(ProtocolTcp
, listen_socket
.m_should_close_fd
,
64 listen_socket
.m_child_processes_inherit
) {
68 TCPSocket::TCPSocket(NativeSocket socket
, bool should_close
,
69 bool child_processes_inherit
)
70 : Socket(ProtocolTcp
, should_close
, child_processes_inherit
) {
74 TCPSocket::~TCPSocket() { CloseListenSockets(); }
76 bool TCPSocket::IsValid() const {
77 return m_socket
!= kInvalidSocketValue
|| m_listen_sockets
.size() != 0;
80 // Return the port number that is being used by the socket.
81 uint16_t TCPSocket::GetLocalPortNumber() const {
82 if (m_socket
!= kInvalidSocketValue
) {
83 SocketAddress sock_addr
;
84 socklen_t sock_addr_len
= sock_addr
.GetMaxLength();
85 if (::getsockname(m_socket
, sock_addr
, &sock_addr_len
) == 0)
86 return sock_addr
.GetPort();
87 } else if (!m_listen_sockets
.empty()) {
88 SocketAddress sock_addr
;
89 socklen_t sock_addr_len
= sock_addr
.GetMaxLength();
90 if (::getsockname(m_listen_sockets
.begin()->first
, sock_addr
,
92 return sock_addr
.GetPort();
97 std::string
TCPSocket::GetLocalIPAddress() const {
98 // We bound to port zero, so we need to figure out which port we actually
100 if (m_socket
!= kInvalidSocketValue
) {
101 SocketAddress sock_addr
;
102 socklen_t sock_addr_len
= sock_addr
.GetMaxLength();
103 if (::getsockname(m_socket
, sock_addr
, &sock_addr_len
) == 0)
104 return sock_addr
.GetIPAddress();
109 uint16_t TCPSocket::GetRemotePortNumber() const {
110 if (m_socket
!= kInvalidSocketValue
) {
111 SocketAddress sock_addr
;
112 socklen_t sock_addr_len
= sock_addr
.GetMaxLength();
113 if (::getpeername(m_socket
, sock_addr
, &sock_addr_len
) == 0)
114 return sock_addr
.GetPort();
119 std::string
TCPSocket::GetRemoteIPAddress() const {
120 // We bound to port zero, so we need to figure out which port we actually
122 if (m_socket
!= kInvalidSocketValue
) {
123 SocketAddress sock_addr
;
124 socklen_t sock_addr_len
= sock_addr
.GetMaxLength();
125 if (::getpeername(m_socket
, sock_addr
, &sock_addr_len
) == 0)
126 return sock_addr
.GetIPAddress();
131 std::string
TCPSocket::GetRemoteConnectionURI() const {
132 if (m_socket
!= kInvalidSocketValue
) {
133 return std::string(llvm::formatv(
134 "connect://[{0}]:{1}", GetRemoteIPAddress(), GetRemotePortNumber()));
139 Status
TCPSocket::CreateSocket(int domain
) {
145 m_socket
= Socket::CreateSocket(domain
, kType
, IPPROTO_TCP
,
146 m_child_processes_inherit
, error
);
150 Status
TCPSocket::Connect(llvm::StringRef name
) {
152 Log
*log
= GetLog(LLDBLog::Communication
);
153 LLDB_LOG(log
, "Connect to host/port {0}", name
);
156 llvm::Expected
<HostAndPort
> host_port
= DecodeHostAndPort(name
);
158 return Status(host_port
.takeError());
160 std::vector
<SocketAddress
> addresses
=
161 SocketAddress::GetAddressInfo(host_port
->hostname
.c_str(), nullptr,
162 AF_UNSPEC
, SOCK_STREAM
, IPPROTO_TCP
);
163 for (SocketAddress
&address
: addresses
) {
164 error
= CreateSocket(address
.GetFamily());
168 address
.SetPort(host_port
->port
);
170 if (llvm::sys::RetryAfterSignal(-1, ::connect
, GetNativeSocket(),
172 address
.GetLength()) == -1) {
177 if (SetOptionNoDelay() == -1) {
186 error
.SetErrorString("Failed to connect port");
190 Status
TCPSocket::Listen(llvm::StringRef name
, int backlog
) {
191 Log
*log
= GetLog(LLDBLog::Connection
);
192 LLDB_LOG(log
, "Listen to {0}", name
);
195 llvm::Expected
<HostAndPort
> host_port
= DecodeHostAndPort(name
);
197 return Status(host_port
.takeError());
199 if (host_port
->hostname
== "*")
200 host_port
->hostname
= "0.0.0.0";
201 std::vector
<SocketAddress
> addresses
= SocketAddress::GetAddressInfo(
202 host_port
->hostname
.c_str(), nullptr, AF_UNSPEC
, SOCK_STREAM
, IPPROTO_TCP
);
203 for (SocketAddress
&address
: addresses
) {
204 int fd
= Socket::CreateSocket(address
.GetFamily(), kType
, IPPROTO_TCP
,
205 m_child_processes_inherit
, error
);
206 if (error
.Fail() || fd
< 0)
209 // enable local address reuse
210 int option_value
= 1;
211 set_socket_option_arg_type option_value_p
=
212 reinterpret_cast<set_socket_option_arg_type
>(&option_value
);
213 if (::setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, option_value_p
,
214 sizeof(option_value
)) == -1) {
219 SocketAddress listen_address
= address
;
220 if(!listen_address
.IsLocalhost())
221 listen_address
.SetToAnyAddress(address
.GetFamily(), host_port
->port
);
223 listen_address
.SetPort(host_port
->port
);
226 ::bind(fd
, &listen_address
.sockaddr(), listen_address
.GetLength());
228 err
= ::listen(fd
, backlog
);
231 error
= GetLastSocketError();
236 if (host_port
->port
== 0) {
237 socklen_t sa_len
= address
.GetLength();
238 if (getsockname(fd
, &address
.sockaddr(), &sa_len
) == 0)
239 host_port
->port
= address
.GetPort();
241 m_listen_sockets
[fd
] = address
;
244 if (m_listen_sockets
.empty()) {
245 assert(error
.Fail());
251 void TCPSocket::CloseListenSockets() {
252 for (auto socket
: m_listen_sockets
)
253 CLOSE_SOCKET(socket
.first
);
254 m_listen_sockets
.clear();
257 Status
TCPSocket::Accept(Socket
*&conn_socket
) {
259 if (m_listen_sockets
.size() == 0) {
260 error
.SetErrorString("No open listening sockets!");
264 NativeSocket sock
= kInvalidSocketValue
;
265 NativeSocket listen_sock
= kInvalidSocketValue
;
266 lldb_private::SocketAddress AcceptAddr
;
267 MainLoop accept_loop
;
268 std::vector
<MainLoopBase::ReadHandleUP
> handles
;
269 for (auto socket
: m_listen_sockets
) {
270 auto fd
= socket
.first
;
271 auto inherit
= this->m_child_processes_inherit
;
272 auto io_sp
= IOObjectSP(new TCPSocket(socket
.first
, false, inherit
));
273 handles
.emplace_back(accept_loop
.RegisterReadObject(
274 io_sp
, [fd
, inherit
, &sock
, &AcceptAddr
, &error
,
275 &listen_sock
](MainLoopBase
&loop
) {
276 socklen_t sa_len
= AcceptAddr
.GetMaxLength();
277 sock
= AcceptSocket(fd
, &AcceptAddr
.sockaddr(), &sa_len
, inherit
,
280 loop
.RequestTermination();
286 bool accept_connection
= false;
287 std::unique_ptr
<TCPSocket
> accepted_socket
;
288 // Loop until we are happy with our connection
289 while (!accept_connection
) {
295 lldb_private::SocketAddress
&AddrIn
= m_listen_sockets
[listen_sock
];
296 if (!AddrIn
.IsAnyAddr() && AcceptAddr
!= AddrIn
) {
297 if (sock
!= kInvalidSocketValue
) {
299 sock
= kInvalidSocketValue
;
301 llvm::errs() << llvm::formatv(
302 "error: rejecting incoming connection from {0} (expecting {1})",
303 AcceptAddr
.GetIPAddress(), AddrIn
.GetIPAddress());
306 accept_connection
= true;
307 accepted_socket
.reset(new TCPSocket(sock
, *this));
310 if (!accepted_socket
)
313 // Keep our TCP packets coming without any delays.
314 accepted_socket
->SetOptionNoDelay();
316 conn_socket
= accepted_socket
.release();
320 int TCPSocket::SetOptionNoDelay() {
321 return SetOption(IPPROTO_TCP
, TCP_NODELAY
, 1);
324 int TCPSocket::SetOptionReuseAddress() {
325 return SetOption(SOL_SOCKET
, SO_REUSEADDR
, 1);