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