1 | //===-- TCPSocket.cpp -----------------------------------------------------===// |
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/LLDBLog.h" |
18 | #include "lldb/Utility/Log.h" |
19 | |
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" |
25 | |
26 | #if LLDB_ENABLE_POSIX |
27 | #include <arpa/inet.h> |
28 | #include <netinet/tcp.h> |
29 | #include <sys/socket.h> |
30 | #endif |
31 | |
32 | #if defined(_WIN32) |
33 | #include <winsock2.h> |
34 | #endif |
35 | |
36 | using namespace lldb; |
37 | using namespace lldb_private; |
38 | |
39 | static const int kType = SOCK_STREAM; |
40 | |
41 | TCPSocket::TCPSocket(bool should_close) : Socket(ProtocolTcp, should_close) {} |
42 | |
43 | TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket) |
44 | : Socket(ProtocolTcp, listen_socket.m_should_close_fd) { |
45 | m_socket = socket; |
46 | } |
47 | |
48 | TCPSocket::TCPSocket(NativeSocket socket, bool should_close) |
49 | : Socket(ProtocolTcp, should_close) { |
50 | m_socket = socket; |
51 | } |
52 | |
53 | TCPSocket::~TCPSocket() { CloseListenSockets(); } |
54 | |
55 | bool TCPSocket::IsValid() const { |
56 | return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0; |
57 | } |
58 | |
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(fd: m_socket, addr: sock_addr, len: &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(fd: m_listen_sockets.begin()->first, addr: sock_addr, |
70 | len: &sock_addr_len) == 0) |
71 | return sock_addr.GetPort(); |
72 | } |
73 | return 0; |
74 | } |
75 | |
76 | std::string TCPSocket::GetLocalIPAddress() const { |
77 | // We bound to port zero, so we need to figure out which port we actually |
78 | // bound to |
79 | if (m_socket != kInvalidSocketValue) { |
80 | SocketAddress sock_addr; |
81 | socklen_t sock_addr_len = sock_addr.GetMaxLength(); |
82 | if (::getsockname(fd: m_socket, addr: sock_addr, len: &sock_addr_len) == 0) |
83 | return sock_addr.GetIPAddress(); |
84 | } |
85 | return "" ; |
86 | } |
87 | |
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(fd: m_socket, addr: sock_addr, len: &sock_addr_len) == 0) |
93 | return sock_addr.GetPort(); |
94 | } |
95 | return 0; |
96 | } |
97 | |
98 | std::string TCPSocket::GetRemoteIPAddress() const { |
99 | // We bound to port zero, so we need to figure out which port we actually |
100 | // bound to |
101 | if (m_socket != kInvalidSocketValue) { |
102 | SocketAddress sock_addr; |
103 | socklen_t sock_addr_len = sock_addr.GetMaxLength(); |
104 | if (::getpeername(fd: m_socket, addr: sock_addr, len: &sock_addr_len) == 0) |
105 | return sock_addr.GetIPAddress(); |
106 | } |
107 | return "" ; |
108 | } |
109 | |
110 | std::string TCPSocket::GetRemoteConnectionURI() const { |
111 | if (m_socket != kInvalidSocketValue) { |
112 | return std::string(llvm::formatv( |
113 | Fmt: "connect://[{0}]:{1}" , Vals: GetRemoteIPAddress(), Vals: GetRemotePortNumber())); |
114 | } |
115 | return "" ; |
116 | } |
117 | |
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(args: llvm::formatv(Fmt: "connection://[{0}]:{1}" , |
122 | Vals: addr.GetIPAddress(), Vals: addr.GetPort())); |
123 | return URIs; |
124 | } |
125 | |
126 | Status TCPSocket::CreateSocket(int domain) { |
127 | Status error; |
128 | if (IsValid()) |
129 | error = Close(); |
130 | if (error.Fail()) |
131 | return error; |
132 | m_socket = Socket::CreateSocket(domain, type: kType, IPPROTO_TCP, error); |
133 | return error; |
134 | } |
135 | |
136 | Status TCPSocket::Connect(llvm::StringRef name) { |
137 | |
138 | Log *log = GetLog(mask: LLDBLog::Communication); |
139 | LLDB_LOG(log, "Connect to host/port {0}" , name); |
140 | |
141 | Status error; |
142 | llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(host_and_port: name); |
143 | if (!host_port) |
144 | return Status::FromError(error: host_port.takeError()); |
145 | |
146 | std::vector<SocketAddress> addresses = |
147 | SocketAddress::GetAddressInfo(hostname: host_port->hostname.c_str(), servname: nullptr, |
148 | AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); |
149 | for (SocketAddress &address : addresses) { |
150 | error = CreateSocket(domain: address.GetFamily()); |
151 | if (error.Fail()) |
152 | continue; |
153 | |
154 | address.SetPort(host_port->port); |
155 | |
156 | if (llvm::sys::RetryAfterSignal(Fail: -1, F&: ::connect, As: GetNativeSocket(), |
157 | As: &address.sockaddr(), |
158 | As: address.GetLength()) == -1) { |
159 | Close(); |
160 | continue; |
161 | } |
162 | |
163 | if (SetOptionNoDelay() == -1) { |
164 | Close(); |
165 | continue; |
166 | } |
167 | |
168 | error.Clear(); |
169 | return error; |
170 | } |
171 | |
172 | error = Status::FromErrorStringWithFormatv( |
173 | format: "Failed to connect to {0}:{1}" , args&: host_port->hostname, args&: host_port->port); |
174 | return error; |
175 | } |
176 | |
177 | Status TCPSocket::Listen(llvm::StringRef name, int backlog) { |
178 | Log *log = GetLog(mask: LLDBLog::Connection); |
179 | LLDB_LOG(log, "Listen to {0}" , name); |
180 | |
181 | Status error; |
182 | llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(host_and_port: name); |
183 | if (!host_port) |
184 | return Status::FromError(error: host_port.takeError()); |
185 | |
186 | if (host_port->hostname == "*" ) |
187 | host_port->hostname = "0.0.0.0" ; |
188 | std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo( |
189 | hostname: host_port->hostname.c_str(), servname: nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); |
190 | for (SocketAddress &address : addresses) { |
191 | int fd = |
192 | Socket::CreateSocket(domain: address.GetFamily(), type: kType, IPPROTO_TCP, error); |
193 | if (error.Fail() || fd < 0) |
194 | continue; |
195 | |
196 | // enable local address reuse |
197 | if (SetOption(sockfd: fd, SOL_SOCKET, SO_REUSEADDR, option_value: 1) == -1) { |
198 | CloseSocket(sockfd: fd); |
199 | continue; |
200 | } |
201 | |
202 | SocketAddress listen_address = address; |
203 | if(!listen_address.IsLocalhost()) |
204 | listen_address.SetToAnyAddress(family: address.GetFamily(), port: host_port->port); |
205 | else |
206 | listen_address.SetPort(host_port->port); |
207 | |
208 | int err = |
209 | ::bind(fd: fd, addr: &listen_address.sockaddr(), len: listen_address.GetLength()); |
210 | if (err != -1) |
211 | err = ::listen(fd: fd, n: backlog); |
212 | |
213 | if (err == -1) { |
214 | error = GetLastError(); |
215 | CloseSocket(sockfd: fd); |
216 | continue; |
217 | } |
218 | |
219 | if (host_port->port == 0) { |
220 | socklen_t sa_len = listen_address.GetLength(); |
221 | if (getsockname(fd: fd, addr: &listen_address.sockaddr(), len: &sa_len) == 0) |
222 | host_port->port = listen_address.GetPort(); |
223 | } |
224 | m_listen_sockets[fd] = listen_address; |
225 | } |
226 | |
227 | if (m_listen_sockets.empty()) { |
228 | assert(error.Fail()); |
229 | return error; |
230 | } |
231 | return Status(); |
232 | } |
233 | |
234 | void TCPSocket::CloseListenSockets() { |
235 | for (auto socket : m_listen_sockets) |
236 | CloseSocket(sockfd: socket.first); |
237 | m_listen_sockets.clear(); |
238 | } |
239 | |
240 | llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> |
241 | TCPSocket::Accept(MainLoopBase &loop, |
242 | std::function<void(std::unique_ptr<Socket> socket)> sock_cb) { |
243 | if (m_listen_sockets.size() == 0) |
244 | return llvm::createStringError(Fmt: "No open listening sockets!" ); |
245 | |
246 | std::vector<MainLoopBase::ReadHandleUP> handles; |
247 | for (auto socket : m_listen_sockets) { |
248 | auto fd = socket.first; |
249 | auto io_sp = std::make_shared<TCPSocket>(args&: fd, args: false); |
250 | auto cb = [this, fd, sock_cb](MainLoopBase &loop) { |
251 | lldb_private::SocketAddress AcceptAddr; |
252 | socklen_t sa_len = AcceptAddr.GetMaxLength(); |
253 | Status error; |
254 | NativeSocket sock = |
255 | AcceptSocket(sockfd: fd, addr: &AcceptAddr.sockaddr(), addrlen: &sa_len, error); |
256 | Log *log = GetLog(mask: LLDBLog::Host); |
257 | if (error.Fail()) { |
258 | LLDB_LOG(log, "AcceptSocket({0}): {1}" , fd, error); |
259 | return; |
260 | } |
261 | |
262 | const lldb_private::SocketAddress &AddrIn = m_listen_sockets[fd]; |
263 | if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) { |
264 | CloseSocket(sockfd: sock); |
265 | LLDB_LOG(log, "rejecting incoming connection from {0} (expecting {1})" , |
266 | AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress()); |
267 | return; |
268 | } |
269 | std::unique_ptr<TCPSocket> sock_up(new TCPSocket(sock, *this)); |
270 | |
271 | // Keep our TCP packets coming without any delays. |
272 | sock_up->SetOptionNoDelay(); |
273 | |
274 | sock_cb(std::move(sock_up)); |
275 | }; |
276 | Status error; |
277 | handles.emplace_back(args: loop.RegisterReadObject(object_sp: io_sp, callback: cb, error)); |
278 | if (error.Fail()) |
279 | return error.ToError(); |
280 | } |
281 | |
282 | return handles; |
283 | } |
284 | |
285 | int TCPSocket::SetOptionNoDelay() { |
286 | return SetOption(IPPROTO_TCP, TCP_NODELAY, option_value: 1); |
287 | } |
288 | |
289 | int TCPSocket::SetOptionReuseAddress() { |
290 | return SetOption(SOL_SOCKET, SO_REUSEADDR, option_value: 1); |
291 | } |
292 | |