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/Error.h"
23 #include "llvm/Support/WindowsError.h"
24 #include "llvm/Support/raw_ostream.h"
27 #include <arpa/inet.h>
28 #include <netinet/tcp.h>
29 #include <sys/socket.h>
37 using namespace lldb_private
;
39 static const int kType
= SOCK_STREAM
;
41 TCPSocket::TCPSocket(bool should_close
) : Socket(ProtocolTcp
, should_close
) {}
43 TCPSocket::TCPSocket(NativeSocket socket
, const TCPSocket
&listen_socket
)
44 : Socket(ProtocolTcp
, listen_socket
.m_should_close_fd
) {
48 TCPSocket::TCPSocket(NativeSocket socket
, bool should_close
)
49 : Socket(ProtocolTcp
, should_close
) {
53 TCPSocket::~TCPSocket() { CloseListenSockets(); }
55 bool TCPSocket::IsValid() const {
56 return m_socket
!= kInvalidSocketValue
|| m_listen_sockets
.size() != 0;
59 // Return the port number that is being used by the socket.
60 uint16_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(m_socket
, sock_addr
, &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(m_listen_sockets
.begin()->first
, sock_addr
,
71 return sock_addr
.GetPort();
76 std::string
TCPSocket::GetLocalIPAddress() const {
77 // We bound to port zero, so we need to figure out which port we actually
79 if (m_socket
!= kInvalidSocketValue
) {
80 SocketAddress sock_addr
;
81 socklen_t sock_addr_len
= sock_addr
.GetMaxLength();
82 if (::getsockname(m_socket
, sock_addr
, &sock_addr_len
) == 0)
83 return sock_addr
.GetIPAddress();
88 uint16_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(m_socket
, sock_addr
, &sock_addr_len
) == 0)
93 return sock_addr
.GetPort();
98 std::string
TCPSocket::GetRemoteIPAddress() const {
99 // We bound to port zero, so we need to figure out which port we actually
101 if (m_socket
!= kInvalidSocketValue
) {
102 SocketAddress sock_addr
;
103 socklen_t sock_addr_len
= sock_addr
.GetMaxLength();
104 if (::getpeername(m_socket
, sock_addr
, &sock_addr_len
) == 0)
105 return sock_addr
.GetIPAddress();
110 std::string
TCPSocket::GetRemoteConnectionURI() const {
111 if (m_socket
!= kInvalidSocketValue
) {
112 return std::string(llvm::formatv(
113 "connect://[{0}]:{1}", GetRemoteIPAddress(), GetRemotePortNumber()));
118 std::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(llvm::formatv("connection://[{0}]:{1}",
122 addr
.GetIPAddress(), addr
.GetPort()));
126 Status
TCPSocket::CreateSocket(int domain
) {
132 m_socket
= Socket::CreateSocket(domain
, kType
, IPPROTO_TCP
, error
);
136 Status
TCPSocket::Connect(llvm::StringRef name
) {
138 Log
*log
= GetLog(LLDBLog::Communication
);
139 LLDB_LOG(log
, "Connect to host/port {0}", name
);
142 llvm::Expected
<HostAndPort
> host_port
= DecodeHostAndPort(name
);
144 return Status::FromError(host_port
.takeError());
146 std::vector
<SocketAddress
> addresses
=
147 SocketAddress::GetAddressInfo(host_port
->hostname
.c_str(), nullptr,
148 AF_UNSPEC
, SOCK_STREAM
, IPPROTO_TCP
);
149 for (SocketAddress
&address
: addresses
) {
150 error
= CreateSocket(address
.GetFamily());
154 address
.SetPort(host_port
->port
);
156 if (llvm::sys::RetryAfterSignal(-1, ::connect
, GetNativeSocket(),
158 address
.GetLength()) == -1) {
163 if (SetOptionNoDelay() == -1) {
172 error
= Status::FromErrorString("Failed to connect port");
176 Status
TCPSocket::Listen(llvm::StringRef name
, int backlog
) {
177 Log
*log
= GetLog(LLDBLog::Connection
);
178 LLDB_LOG(log
, "Listen to {0}", name
);
181 llvm::Expected
<HostAndPort
> host_port
= DecodeHostAndPort(name
);
183 return Status::FromError(host_port
.takeError());
185 if (host_port
->hostname
== "*")
186 host_port
->hostname
= "0.0.0.0";
187 std::vector
<SocketAddress
> addresses
= SocketAddress::GetAddressInfo(
188 host_port
->hostname
.c_str(), nullptr, AF_UNSPEC
, SOCK_STREAM
, IPPROTO_TCP
);
189 for (SocketAddress
&address
: addresses
) {
191 Socket::CreateSocket(address
.GetFamily(), kType
, IPPROTO_TCP
, error
);
192 if (error
.Fail() || fd
< 0)
195 // enable local address reuse
196 if (SetOption(fd
, SOL_SOCKET
, SO_REUSEADDR
, 1) == -1) {
201 SocketAddress listen_address
= address
;
202 if(!listen_address
.IsLocalhost())
203 listen_address
.SetToAnyAddress(address
.GetFamily(), host_port
->port
);
205 listen_address
.SetPort(host_port
->port
);
208 ::bind(fd
, &listen_address
.sockaddr(), listen_address
.GetLength());
210 err
= ::listen(fd
, backlog
);
213 error
= GetLastError();
218 if (host_port
->port
== 0) {
219 socklen_t sa_len
= listen_address
.GetLength();
220 if (getsockname(fd
, &listen_address
.sockaddr(), &sa_len
) == 0)
221 host_port
->port
= listen_address
.GetPort();
223 m_listen_sockets
[fd
] = listen_address
;
226 if (m_listen_sockets
.empty()) {
227 assert(error
.Fail());
233 void TCPSocket::CloseListenSockets() {
234 for (auto socket
: m_listen_sockets
)
235 CloseSocket(socket
.first
);
236 m_listen_sockets
.clear();
239 llvm::Expected
<std::vector
<MainLoopBase::ReadHandleUP
>>
240 TCPSocket::Accept(MainLoopBase
&loop
,
241 std::function
<void(std::unique_ptr
<Socket
> socket
)> sock_cb
) {
242 if (m_listen_sockets
.size() == 0)
243 return llvm::createStringError("No open listening sockets!");
245 std::vector
<MainLoopBase::ReadHandleUP
> handles
;
246 for (auto socket
: m_listen_sockets
) {
247 auto fd
= socket
.first
;
248 auto io_sp
= std::make_shared
<TCPSocket
>(fd
, false);
249 auto cb
= [this, fd
, sock_cb
](MainLoopBase
&loop
) {
250 lldb_private::SocketAddress AcceptAddr
;
251 socklen_t sa_len
= AcceptAddr
.GetMaxLength();
254 AcceptSocket(fd
, &AcceptAddr
.sockaddr(), &sa_len
, error
);
255 Log
*log
= GetLog(LLDBLog::Host
);
257 LLDB_LOG(log
, "AcceptSocket({0}): {1}", fd
, error
);
261 const lldb_private::SocketAddress
&AddrIn
= m_listen_sockets
[fd
];
262 if (!AddrIn
.IsAnyAddr() && AcceptAddr
!= AddrIn
) {
264 LLDB_LOG(log
, "rejecting incoming connection from {0} (expecting {1})",
265 AcceptAddr
.GetIPAddress(), AddrIn
.GetIPAddress());
268 std::unique_ptr
<TCPSocket
> sock_up(new TCPSocket(sock
, *this));
270 // Keep our TCP packets coming without any delays.
271 sock_up
->SetOptionNoDelay();
273 sock_cb(std::move(sock_up
));
276 handles
.emplace_back(loop
.RegisterReadObject(io_sp
, cb
, error
));
278 return error
.ToError();
284 int TCPSocket::SetOptionNoDelay() {
285 return SetOption(IPPROTO_TCP
, TCP_NODELAY
, 1);
288 int TCPSocket::SetOptionReuseAddress() {
289 return SetOption(SOL_SOCKET
, SO_REUSEADDR
, 1);