1 | //===-- Socket.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 | #include "lldb/Host/Socket.h" |
10 | |
11 | #include "lldb/Host/Config.h" |
12 | #include "lldb/Host/Host.h" |
13 | #include "lldb/Host/SocketAddress.h" |
14 | #include "lldb/Host/common/TCPSocket.h" |
15 | #include "lldb/Host/common/UDPSocket.h" |
16 | #include "lldb/Utility/LLDBLog.h" |
17 | #include "lldb/Utility/Log.h" |
18 | |
19 | #include "llvm/ADT/STLExtras.h" |
20 | #include "llvm/ADT/StringExtras.h" |
21 | #include "llvm/Support/Errno.h" |
22 | #include "llvm/Support/Error.h" |
23 | #include "llvm/Support/Regex.h" |
24 | #include "llvm/Support/WindowsError.h" |
25 | |
26 | #if LLDB_ENABLE_POSIX |
27 | #include "lldb/Host/posix/DomainSocket.h" |
28 | |
29 | #include <arpa/inet.h> |
30 | #include <netdb.h> |
31 | #include <netinet/in.h> |
32 | #include <netinet/tcp.h> |
33 | #include <sys/socket.h> |
34 | #include <sys/un.h> |
35 | #include <unistd.h> |
36 | #endif |
37 | |
38 | #ifdef __linux__ |
39 | #include "lldb/Host/linux/AbstractSocket.h" |
40 | #endif |
41 | |
42 | #ifdef __ANDROID__ |
43 | #include <arpa/inet.h> |
44 | #include <asm-generic/errno-base.h> |
45 | #include <cerrno> |
46 | #include <fcntl.h> |
47 | #include <linux/tcp.h> |
48 | #include <sys/syscall.h> |
49 | #include <unistd.h> |
50 | #endif // __ANDROID__ |
51 | |
52 | using namespace lldb; |
53 | using namespace lldb_private; |
54 | |
55 | #if defined(_WIN32) |
56 | typedef const char *set_socket_option_arg_type; |
57 | typedef char *get_socket_option_arg_type; |
58 | const NativeSocket Socket::kInvalidSocketValue = INVALID_SOCKET; |
59 | #else // #if defined(_WIN32) |
60 | typedef const void *set_socket_option_arg_type; |
61 | typedef void *get_socket_option_arg_type; |
62 | const NativeSocket Socket::kInvalidSocketValue = -1; |
63 | #endif // #if defined(_WIN32) |
64 | |
65 | static bool IsInterrupted() { |
66 | #if defined(_WIN32) |
67 | return ::WSAGetLastError() == WSAEINTR; |
68 | #else |
69 | return errno == EINTR; |
70 | #endif |
71 | } |
72 | |
73 | Socket::Socket(SocketProtocol protocol, bool should_close, |
74 | bool child_processes_inherit) |
75 | : IOObject(eFDTypeSocket), m_protocol(protocol), |
76 | m_socket(kInvalidSocketValue), |
77 | m_child_processes_inherit(child_processes_inherit), |
78 | m_should_close_fd(should_close) {} |
79 | |
80 | Socket::~Socket() { Close(); } |
81 | |
82 | llvm::Error Socket::Initialize() { |
83 | #if defined(_WIN32) |
84 | auto wVersion = WINSOCK_VERSION; |
85 | WSADATA wsaData; |
86 | int err = ::WSAStartup(wVersion, &wsaData); |
87 | if (err == 0) { |
88 | if (wsaData.wVersion < wVersion) { |
89 | WSACleanup(); |
90 | return llvm::make_error<llvm::StringError>( |
91 | "WSASock version is not expected." , llvm::inconvertibleErrorCode()); |
92 | } |
93 | } else { |
94 | return llvm::errorCodeToError(llvm::mapWindowsError(::WSAGetLastError())); |
95 | } |
96 | #endif |
97 | |
98 | return llvm::Error::success(); |
99 | } |
100 | |
101 | void Socket::Terminate() { |
102 | #if defined(_WIN32) |
103 | ::WSACleanup(); |
104 | #endif |
105 | } |
106 | |
107 | std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, |
108 | bool child_processes_inherit, |
109 | Status &error) { |
110 | error.Clear(); |
111 | |
112 | std::unique_ptr<Socket> socket_up; |
113 | switch (protocol) { |
114 | case ProtocolTcp: |
115 | socket_up = |
116 | std::make_unique<TCPSocket>(args: true, args&: child_processes_inherit); |
117 | break; |
118 | case ProtocolUdp: |
119 | socket_up = |
120 | std::make_unique<UDPSocket>(args: true, args&: child_processes_inherit); |
121 | break; |
122 | case ProtocolUnixDomain: |
123 | #if LLDB_ENABLE_POSIX |
124 | socket_up = |
125 | std::make_unique<DomainSocket>(args: true, args&: child_processes_inherit); |
126 | #else |
127 | error.SetErrorString( |
128 | "Unix domain sockets are not supported on this platform." ); |
129 | #endif |
130 | break; |
131 | case ProtocolUnixAbstract: |
132 | #ifdef __linux__ |
133 | socket_up = |
134 | std::make_unique<AbstractSocket>(args&: child_processes_inherit); |
135 | #else |
136 | error.SetErrorString( |
137 | "Abstract domain sockets are not supported on this platform." ); |
138 | #endif |
139 | break; |
140 | } |
141 | |
142 | if (error.Fail()) |
143 | socket_up.reset(); |
144 | |
145 | return socket_up; |
146 | } |
147 | |
148 | llvm::Expected<std::unique_ptr<Socket>> |
149 | Socket::TcpConnect(llvm::StringRef host_and_port, |
150 | bool child_processes_inherit) { |
151 | Log *log = GetLog(mask: LLDBLog::Connection); |
152 | LLDB_LOG(log, "host_and_port = {0}" , host_and_port); |
153 | |
154 | Status error; |
155 | std::unique_ptr<Socket> connect_socket( |
156 | Create(protocol: ProtocolTcp, child_processes_inherit, error)); |
157 | if (error.Fail()) |
158 | return error.ToError(); |
159 | |
160 | error = connect_socket->Connect(name: host_and_port); |
161 | if (error.Success()) |
162 | return std::move(connect_socket); |
163 | |
164 | return error.ToError(); |
165 | } |
166 | |
167 | llvm::Expected<std::unique_ptr<TCPSocket>> |
168 | Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inherit, |
169 | int backlog) { |
170 | Log *log = GetLog(mask: LLDBLog::Connection); |
171 | LLDB_LOG(log, "host_and_port = {0}" , host_and_port); |
172 | |
173 | std::unique_ptr<TCPSocket> listen_socket( |
174 | new TCPSocket(true, child_processes_inherit)); |
175 | |
176 | Status error = listen_socket->Listen(name: host_and_port, backlog); |
177 | if (error.Fail()) |
178 | return error.ToError(); |
179 | |
180 | return std::move(listen_socket); |
181 | } |
182 | |
183 | llvm::Expected<std::unique_ptr<UDPSocket>> |
184 | Socket::UdpConnect(llvm::StringRef host_and_port, |
185 | bool child_processes_inherit) { |
186 | return UDPSocket::Connect(name: host_and_port, child_processes_inherit); |
187 | } |
188 | |
189 | llvm::Expected<Socket::HostAndPort> Socket::DecodeHostAndPort(llvm::StringRef host_and_port) { |
190 | static llvm::Regex g_regex("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)" ); |
191 | HostAndPort ret; |
192 | llvm::SmallVector<llvm::StringRef, 3> matches; |
193 | if (g_regex.match(String: host_and_port, Matches: &matches)) { |
194 | ret.hostname = matches[1].str(); |
195 | // IPv6 addresses are wrapped in [] when specified with ports |
196 | if (ret.hostname.front() == '[' && ret.hostname.back() == ']') |
197 | ret.hostname = ret.hostname.substr(pos: 1, n: ret.hostname.size() - 2); |
198 | if (to_integer(S: matches[2], Num&: ret.port, Base: 10)) |
199 | return ret; |
200 | } else { |
201 | // If this was unsuccessful, then check if it's simply an unsigned 16-bit |
202 | // integer, representing a port with an empty host. |
203 | if (to_integer(S: host_and_port, Num&: ret.port, Base: 10)) |
204 | return ret; |
205 | } |
206 | |
207 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
208 | Fmt: "invalid host:port specification: '%s'" , |
209 | Vals: host_and_port.str().c_str()); |
210 | } |
211 | |
212 | IOObject::WaitableHandle Socket::GetWaitableHandle() { |
213 | // TODO: On Windows, use WSAEventSelect |
214 | return m_socket; |
215 | } |
216 | |
217 | Status Socket::Read(void *buf, size_t &num_bytes) { |
218 | Status error; |
219 | int bytes_received = 0; |
220 | do { |
221 | bytes_received = ::recv(fd: m_socket, buf: static_cast<char *>(buf), n: num_bytes, flags: 0); |
222 | } while (bytes_received < 0 && IsInterrupted()); |
223 | |
224 | if (bytes_received < 0) { |
225 | SetLastError(error); |
226 | num_bytes = 0; |
227 | } else |
228 | num_bytes = bytes_received; |
229 | |
230 | Log *log = GetLog(mask: LLDBLog::Communication); |
231 | if (log) { |
232 | LLDB_LOGF(log, |
233 | "%p Socket::Read() (socket = %" PRIu64 |
234 | ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 |
235 | " (error = %s)" , |
236 | static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf, |
237 | static_cast<uint64_t>(num_bytes), |
238 | static_cast<int64_t>(bytes_received), error.AsCString()); |
239 | } |
240 | |
241 | return error; |
242 | } |
243 | |
244 | Status Socket::Write(const void *buf, size_t &num_bytes) { |
245 | const size_t src_len = num_bytes; |
246 | Status error; |
247 | int bytes_sent = 0; |
248 | do { |
249 | bytes_sent = Send(buf, num_bytes); |
250 | } while (bytes_sent < 0 && IsInterrupted()); |
251 | |
252 | if (bytes_sent < 0) { |
253 | SetLastError(error); |
254 | num_bytes = 0; |
255 | } else |
256 | num_bytes = bytes_sent; |
257 | |
258 | Log *log = GetLog(mask: LLDBLog::Communication); |
259 | if (log) { |
260 | LLDB_LOGF(log, |
261 | "%p Socket::Write() (socket = %" PRIu64 |
262 | ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 |
263 | " (error = %s)" , |
264 | static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf, |
265 | static_cast<uint64_t>(src_len), |
266 | static_cast<int64_t>(bytes_sent), error.AsCString()); |
267 | } |
268 | |
269 | return error; |
270 | } |
271 | |
272 | Status Socket::Close() { |
273 | Status error; |
274 | if (!IsValid() || !m_should_close_fd) |
275 | return error; |
276 | |
277 | Log *log = GetLog(mask: LLDBLog::Connection); |
278 | LLDB_LOGF(log, "%p Socket::Close (fd = %" PRIu64 ")" , |
279 | static_cast<void *>(this), static_cast<uint64_t>(m_socket)); |
280 | |
281 | #if defined(_WIN32) |
282 | bool success = closesocket(m_socket) == 0; |
283 | #else |
284 | bool success = ::close(fd: m_socket) == 0; |
285 | #endif |
286 | // A reference to a FD was passed in, set it to an invalid value |
287 | m_socket = kInvalidSocketValue; |
288 | if (!success) { |
289 | SetLastError(error); |
290 | } |
291 | |
292 | return error; |
293 | } |
294 | |
295 | int Socket::GetOption(int level, int option_name, int &option_value) { |
296 | get_socket_option_arg_type option_value_p = |
297 | reinterpret_cast<get_socket_option_arg_type>(&option_value); |
298 | socklen_t option_value_size = sizeof(int); |
299 | return ::getsockopt(fd: m_socket, level: level, optname: option_name, optval: option_value_p, |
300 | optlen: &option_value_size); |
301 | } |
302 | |
303 | int Socket::SetOption(int level, int option_name, int option_value) { |
304 | set_socket_option_arg_type option_value_p = |
305 | reinterpret_cast<get_socket_option_arg_type>(&option_value); |
306 | return ::setsockopt(fd: m_socket, level: level, optname: option_name, optval: option_value_p, |
307 | optlen: sizeof(option_value)); |
308 | } |
309 | |
310 | size_t Socket::Send(const void *buf, const size_t num_bytes) { |
311 | return ::send(fd: m_socket, buf: static_cast<const char *>(buf), n: num_bytes, flags: 0); |
312 | } |
313 | |
314 | void Socket::SetLastError(Status &error) { |
315 | #if defined(_WIN32) |
316 | error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32); |
317 | #else |
318 | error.SetErrorToErrno(); |
319 | #endif |
320 | } |
321 | |
322 | NativeSocket Socket::CreateSocket(const int domain, const int type, |
323 | const int protocol, |
324 | bool child_processes_inherit, Status &error) { |
325 | error.Clear(); |
326 | auto socket_type = type; |
327 | #ifdef SOCK_CLOEXEC |
328 | if (!child_processes_inherit) |
329 | socket_type |= SOCK_CLOEXEC; |
330 | #endif |
331 | auto sock = ::socket(domain: domain, type: socket_type, protocol: protocol); |
332 | if (sock == kInvalidSocketValue) |
333 | SetLastError(error); |
334 | |
335 | return sock; |
336 | } |
337 | |
338 | NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, |
339 | socklen_t *addrlen, |
340 | bool child_processes_inherit, Status &error) { |
341 | error.Clear(); |
342 | #if defined(ANDROID_USE_ACCEPT_WORKAROUND) |
343 | // Hack: |
344 | // This enables static linking lldb-server to an API 21 libc, but still |
345 | // having it run on older devices. It is necessary because API 21 libc's |
346 | // implementation of accept() uses the accept4 syscall(), which is not |
347 | // available in older kernels. Using an older libc would fix this issue, but |
348 | // introduce other ones, as the old libraries were quite buggy. |
349 | int fd = syscall(__NR_accept, sockfd, addr, addrlen); |
350 | if (fd >= 0 && !child_processes_inherit) { |
351 | int flags = ::fcntl(fd, F_GETFD); |
352 | if (flags != -1 && ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1) |
353 | return fd; |
354 | SetLastError(error); |
355 | close(fd); |
356 | } |
357 | return fd; |
358 | #elif defined(SOCK_CLOEXEC) && defined(HAVE_ACCEPT4) |
359 | int flags = 0; |
360 | if (!child_processes_inherit) { |
361 | flags |= SOCK_CLOEXEC; |
362 | } |
363 | NativeSocket fd = llvm::sys::RetryAfterSignal( |
364 | static_cast<NativeSocket>(-1), ::accept4, sockfd, addr, addrlen, flags); |
365 | #else |
366 | NativeSocket fd = llvm::sys::RetryAfterSignal( |
367 | Fail: static_cast<NativeSocket>(-1), F&: ::accept, As: sockfd, As: addr, As: addrlen); |
368 | #endif |
369 | if (fd == kInvalidSocketValue) |
370 | SetLastError(error); |
371 | return fd; |
372 | } |
373 | |
374 | llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &OS, |
375 | const Socket::HostAndPort &HP) { |
376 | return OS << '[' << HP.hostname << ']' << ':' << HP.port; |
377 | } |
378 | |