/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/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 | 1 | static bool IsInterrupted() { |
66 | | #if defined(_WIN32) |
67 | | return ::WSAGetLastError() == WSAEINTR; |
68 | | #else |
69 | 1 | return errno == EINTR; |
70 | 1 | #endif |
71 | 1 | } |
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 | 459 | m_should_close_fd(should_close) {} |
79 | | |
80 | 459 | Socket::~Socket() { Close(); } |
81 | | |
82 | 3.98k | 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 | 3.98k | return llvm::Error::success(); |
99 | 3.98k | } |
100 | | |
101 | 3.97k | void Socket::Terminate() { |
102 | | #if defined(_WIN32) |
103 | | ::WSACleanup(); |
104 | | #endif |
105 | 3.97k | } |
106 | | |
107 | | std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, |
108 | | bool child_processes_inherit, |
109 | 214 | Status &error) { |
110 | 214 | error.Clear(); |
111 | | |
112 | 214 | std::unique_ptr<Socket> socket_up; |
113 | 214 | switch (protocol) { |
114 | 157 | case ProtocolTcp: |
115 | 157 | socket_up = |
116 | 157 | std::make_unique<TCPSocket>(true, child_processes_inherit); |
117 | 157 | break; |
118 | 0 | case ProtocolUdp: |
119 | 0 | socket_up = |
120 | 0 | std::make_unique<UDPSocket>(true, child_processes_inherit); |
121 | 0 | break; |
122 | 57 | case ProtocolUnixDomain: |
123 | 57 | #if LLDB_ENABLE_POSIX |
124 | 57 | socket_up = |
125 | 57 | std::make_unique<DomainSocket>(true, child_processes_inherit); |
126 | | #else |
127 | | error.SetErrorString( |
128 | | "Unix domain sockets are not supported on this platform."); |
129 | | #endif |
130 | 57 | break; |
131 | 0 | case ProtocolUnixAbstract: |
132 | | #ifdef __linux__ |
133 | | socket_up = |
134 | | std::make_unique<AbstractSocket>(child_processes_inherit); |
135 | | #else |
136 | 0 | error.SetErrorString( |
137 | 0 | "Abstract domain sockets are not supported on this platform."); |
138 | 0 | #endif |
139 | 0 | break; |
140 | 214 | } |
141 | | |
142 | 214 | if (error.Fail()) |
143 | 0 | socket_up.reset(); |
144 | | |
145 | 214 | return socket_up; |
146 | 214 | } |
147 | | |
148 | | llvm::Expected<std::unique_ptr<Socket>> |
149 | | Socket::TcpConnect(llvm::StringRef host_and_port, |
150 | 0 | bool child_processes_inherit) { |
151 | 0 | Log *log = GetLog(LLDBLog::Connection); |
152 | 0 | LLDB_LOG(log, "host_and_port = {0}", host_and_port); |
153 | |
|
154 | 0 | Status error; |
155 | 0 | std::unique_ptr<Socket> connect_socket( |
156 | 0 | Create(ProtocolTcp, child_processes_inherit, error)); |
157 | 0 | if (error.Fail()) |
158 | 0 | return error.ToError(); |
159 | | |
160 | 0 | error = connect_socket->Connect(host_and_port); |
161 | 0 | if (error.Success()) |
162 | 0 | return std::move(connect_socket); |
163 | | |
164 | 0 | return error.ToError(); |
165 | 0 | } |
166 | | |
167 | | llvm::Expected<std::unique_ptr<TCPSocket>> |
168 | | Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inherit, |
169 | 18 | int backlog) { |
170 | 18 | Log *log = GetLog(LLDBLog::Connection); |
171 | 18 | LLDB_LOG(log, "host_and_port = {0}", host_and_port); |
172 | | |
173 | 18 | std::unique_ptr<TCPSocket> listen_socket( |
174 | 18 | new TCPSocket(true, child_processes_inherit)); |
175 | | |
176 | 18 | Status error = listen_socket->Listen(host_and_port, backlog); |
177 | 18 | if (error.Fail()) |
178 | 0 | return error.ToError(); |
179 | | |
180 | 18 | return std::move(listen_socket); |
181 | 18 | } |
182 | | |
183 | | llvm::Expected<std::unique_ptr<UDPSocket>> |
184 | | Socket::UdpConnect(llvm::StringRef host_and_port, |
185 | 0 | bool child_processes_inherit) { |
186 | 0 | return UDPSocket::Connect(host_and_port, child_processes_inherit); |
187 | 0 | } |
188 | | |
189 | 288 | llvm::Expected<Socket::HostAndPort> Socket::DecodeHostAndPort(llvm::StringRef host_and_port) { |
190 | 288 | static llvm::Regex g_regex("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)"); |
191 | 288 | HostAndPort ret; |
192 | 288 | llvm::SmallVector<llvm::StringRef, 3> matches; |
193 | 288 | if (g_regex.match(host_and_port, &matches)) { |
194 | 274 | ret.hostname = matches[1].str(); |
195 | | // IPv6 addresses are wrapped in [] when specified with ports |
196 | 274 | if (ret.hostname.front() == '[' && ret.hostname.back() == ']'161 ) |
197 | 161 | ret.hostname = ret.hostname.substr(1, ret.hostname.size() - 2); |
198 | 274 | if (to_integer(matches[2], ret.port, 10)) |
199 | 270 | return ret; |
200 | 274 | } 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 | 14 | if (to_integer(host_and_port, ret.port, 10)) |
204 | 2 | return ret; |
205 | 14 | } |
206 | | |
207 | 16 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
208 | 16 | "invalid host:port specification: '%s'", |
209 | 16 | host_and_port.str().c_str()); |
210 | 288 | } |
211 | | |
212 | 587k | IOObject::WaitableHandle Socket::GetWaitableHandle() { |
213 | | // TODO: On Windows, use WSAEventSelect |
214 | 587k | return m_socket; |
215 | 587k | } |
216 | | |
217 | 95.8k | Status Socket::Read(void *buf, size_t &num_bytes) { |
218 | 95.8k | Status error; |
219 | 95.8k | int bytes_received = 0; |
220 | 95.8k | do { |
221 | 95.8k | bytes_received = ::recv(m_socket, static_cast<char *>(buf), num_bytes, 0); |
222 | 95.8k | } while (bytes_received < 0 && IsInterrupted()1 ); |
223 | | |
224 | 95.8k | if (bytes_received < 0) { |
225 | 1 | SetLastError(error); |
226 | 1 | num_bytes = 0; |
227 | 1 | } else |
228 | 95.8k | num_bytes = bytes_received; |
229 | | |
230 | 95.8k | Log *log = GetLog(LLDBLog::Communication); |
231 | 95.8k | if (log) { |
232 | 0 | LLDB_LOGF(log, |
233 | 0 | "%p Socket::Read() (socket = %" PRIu64 |
234 | 0 | ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 |
235 | 0 | " (error = %s)", |
236 | 0 | static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf, |
237 | 0 | static_cast<uint64_t>(num_bytes), |
238 | 0 | static_cast<int64_t>(bytes_received), error.AsCString()); |
239 | 0 | } |
240 | | |
241 | 95.8k | return error; |
242 | 95.8k | } |
243 | | |
244 | 96.0k | Status Socket::Write(const void *buf, size_t &num_bytes) { |
245 | 96.0k | const size_t src_len = num_bytes; |
246 | 96.0k | Status error; |
247 | 96.0k | int bytes_sent = 0; |
248 | 96.0k | do { |
249 | 96.0k | bytes_sent = Send(buf, num_bytes); |
250 | 96.0k | } while (bytes_sent < 0 && IsInterrupted()0 ); |
251 | | |
252 | 96.0k | if (bytes_sent < 0) { |
253 | 0 | SetLastError(error); |
254 | 0 | num_bytes = 0; |
255 | 0 | } else |
256 | 96.0k | num_bytes = bytes_sent; |
257 | | |
258 | 96.0k | Log *log = GetLog(LLDBLog::Communication); |
259 | 96.0k | if (log) { |
260 | 0 | LLDB_LOGF(log, |
261 | 0 | "%p Socket::Write() (socket = %" PRIu64 |
262 | 0 | ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 |
263 | 0 | " (error = %s)", |
264 | 0 | static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf, |
265 | 0 | static_cast<uint64_t>(src_len), |
266 | 0 | static_cast<int64_t>(bytes_sent), error.AsCString()); |
267 | 0 | } |
268 | | |
269 | 96.0k | return error; |
270 | 96.0k | } |
271 | | |
272 | 663 | Status Socket::Close() { |
273 | 663 | Status error; |
274 | 663 | if (!IsValid() || !m_should_close_fd393 ) |
275 | 360 | return error; |
276 | | |
277 | 303 | Log *log = GetLog(LLDBLog::Connection); |
278 | 303 | LLDB_LOGF(log, "%p Socket::Close (fd = %" PRIu64 ")", |
279 | 303 | 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 | 303 | bool success = ::close(m_socket) == 0; |
285 | 303 | #endif |
286 | | // A reference to a FD was passed in, set it to an invalid value |
287 | 303 | m_socket = kInvalidSocketValue; |
288 | 303 | if (!success) { |
289 | 0 | SetLastError(error); |
290 | 0 | } |
291 | | |
292 | 303 | return error; |
293 | 663 | } |
294 | | |
295 | 0 | int Socket::GetOption(int level, int option_name, int &option_value) { |
296 | 0 | get_socket_option_arg_type option_value_p = |
297 | 0 | reinterpret_cast<get_socket_option_arg_type>(&option_value); |
298 | 0 | socklen_t option_value_size = sizeof(int); |
299 | 0 | return ::getsockopt(m_socket, level, option_name, option_value_p, |
300 | 0 | &option_value_size); |
301 | 0 | } |
302 | | |
303 | 226 | int Socket::SetOption(int level, int option_name, int option_value) { |
304 | 226 | set_socket_option_arg_type option_value_p = |
305 | 226 | reinterpret_cast<get_socket_option_arg_type>(&option_value); |
306 | 226 | return ::setsockopt(m_socket, level, option_name, option_value_p, |
307 | 226 | sizeof(option_value)); |
308 | 226 | } |
309 | | |
310 | 96.0k | size_t Socket::Send(const void *buf, const size_t num_bytes) { |
311 | 96.0k | return ::send(m_socket, static_cast<const char *>(buf), num_bytes, 0); |
312 | 96.0k | } |
313 | | |
314 | 50 | void Socket::SetLastError(Status &error) { |
315 | | #if defined(_WIN32) |
316 | | error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32); |
317 | | #else |
318 | 50 | error.SetErrorToErrno(); |
319 | 50 | #endif |
320 | 50 | } |
321 | | |
322 | | NativeSocket Socket::CreateSocket(const int domain, const int type, |
323 | | const int protocol, |
324 | 357 | bool child_processes_inherit, Status &error) { |
325 | 357 | error.Clear(); |
326 | 357 | auto socket_type = type; |
327 | | #ifdef SOCK_CLOEXEC |
328 | | if (!child_processes_inherit) |
329 | | socket_type |= SOCK_CLOEXEC; |
330 | | #endif |
331 | 357 | auto sock = ::socket(domain, socket_type, protocol); |
332 | 357 | if (sock == kInvalidSocketValue) |
333 | 0 | SetLastError(error); |
334 | | |
335 | 357 | return sock; |
336 | 357 | } |
337 | | |
338 | | NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, |
339 | | socklen_t *addrlen, |
340 | 54 | bool child_processes_inherit, Status &error) { |
341 | 54 | 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 | 54 | NativeSocket fd = llvm::sys::RetryAfterSignal( |
367 | 54 | static_cast<NativeSocket>(-1), ::accept, sockfd, addr, addrlen); |
368 | 54 | #endif |
369 | 54 | if (fd == kInvalidSocketValue) |
370 | 0 | SetLastError(error); |
371 | 54 | return fd; |
372 | 54 | } |
373 | | |
374 | | llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &OS, |
375 | 0 | const Socket::HostAndPort &HP) { |
376 | 0 | return OS << '[' << HP.hostname << ']' << ':' << HP.port; |
377 | 0 | } |