1 //===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
9 // Created by Greg Clayton on 12/12/07.
11 //===----------------------------------------------------------------------===//
13 #include "RNBSocket.h"
16 #include <arpa/inet.h>
21 #include <netinet/in.h>
22 #include <netinet/tcp.h>
23 #include <sys/event.h>
27 #include "lldb/Host/SocketAddress.h"
33 rnb_err_t
RNBSocket::Listen(const char *listen_host
, uint16_t port
,
34 PortBoundCallback callback
,
35 const void *callback_baton
) {
36 // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called",
37 // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
38 // Disconnect without saving errno
42 int queue_id
= kqueue();
44 err
.SetError(errno
, DNBError::MachKernel
);
45 err
.LogThreaded("error: failed to create kqueue.");
49 bool any_addr
= (strcmp(listen_host
, "*") == 0);
51 // If the user wants to allow connections from any address we should create
52 // sockets on all families that can resolve localhost. This will allow us to
53 // listen for IPv6 and IPv4 connections from all addresses if those interfaces
55 const char *local_addr
= any_addr
? "localhost" : listen_host
;
57 std::map
<int, lldb_private::SocketAddress
> sockets
;
58 auto addresses
= lldb_private::SocketAddress::GetAddressInfo(
59 local_addr
, NULL
, AF_UNSPEC
, SOCK_STREAM
, IPPROTO_TCP
);
61 for (auto address
: addresses
) {
62 int sock_fd
= ::socket(address
.GetFamily(), SOCK_STREAM
, IPPROTO_TCP
);
66 SetSocketOption(sock_fd
, SOL_SOCKET
, SO_REUSEADDR
, 1);
68 lldb_private::SocketAddress bind_address
= address
;
70 if(any_addr
|| !bind_address
.IsLocalhost())
71 bind_address
.SetToAnyAddress(bind_address
.GetFamily(), port
);
73 bind_address
.SetPort(port
);
76 ::bind(sock_fd
, &bind_address
.sockaddr(), bind_address
.GetLength());
78 ClosePort(sock_fd
, false);
82 error
= ::listen(sock_fd
, 5);
84 ClosePort(sock_fd
, false);
88 // We were asked to listen on port zero which means we must now read the
89 // actual port that was given to us as port zero is a special code for "find
90 // an open port for me". This will only execute on the first socket created,
91 // subesquent sockets will reuse this port number.
93 socklen_t sa_len
= address
.GetLength();
94 if (getsockname(sock_fd
, &address
.sockaddr(), &sa_len
) == 0)
95 port
= address
.GetPort();
98 sockets
[sock_fd
] = address
;
101 if (sockets
.size() == 0) {
102 err
.SetError(errno
, DNBError::POSIX
);
103 err
.LogThreaded("::listen or ::bind failed");
108 callback(callback_baton
, port
);
110 std::vector
<struct kevent
> events
;
111 events
.resize(sockets
.size());
113 for (auto socket
: sockets
) {
114 EV_SET(&events
[i
++], socket
.first
, EVFILT_READ
, EV_ADD
, 0, 0, 0);
117 bool accept_connection
= false;
119 // Loop until we are happy with our connection
120 while (!accept_connection
) {
122 struct kevent event_list
[4];
124 kevent(queue_id
, events
.data(), events
.size(), event_list
, 4, NULL
);
126 if (num_events
< 0) {
127 err
.SetError(errno
, DNBError::MachKernel
);
128 err
.LogThreaded("error: kevent() failed.");
131 for (int i
= 0; i
< num_events
; ++i
) {
132 auto sock_fd
= event_list
[i
].ident
;
133 auto socket_pair
= sockets
.find(sock_fd
);
134 if (socket_pair
== sockets
.end())
137 lldb_private::SocketAddress
&addr_in
= socket_pair
->second
;
138 lldb_private::SocketAddress accept_addr
;
139 socklen_t sa_len
= accept_addr
.GetMaxLength();
140 m_fd
= ::accept(sock_fd
, &accept_addr
.sockaddr(), &sa_len
);
143 err
.SetError(errno
, DNBError::POSIX
);
144 err
.LogThreaded("error: Socket accept failed.");
147 if (addr_in
.IsAnyAddr())
148 accept_connection
= true;
150 if (accept_addr
== addr_in
)
151 accept_connection
= true;
157 "error: rejecting incoming connection from %s (expecting %s)\n",
158 accept_addr
.GetIPAddress().c_str(),
159 addr_in
.GetIPAddress().c_str());
160 DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n",
161 accept_addr
.GetIPAddress().c_str(),
162 addr_in
.GetIPAddress().c_str());
170 for (auto socket
: sockets
) {
171 int ListenFd
= socket
.first
;
172 ClosePort(ListenFd
, false);
178 // Keep our TCP packets coming without any delays.
179 SetSocketOption(m_fd
, IPPROTO_TCP
, TCP_NODELAY
, 1);
184 rnb_err_t
RNBSocket::Connect(const char *host
, uint16_t port
) {
185 auto result
= rnb_err
;
188 auto addresses
= lldb_private::SocketAddress::GetAddressInfo(
189 host
, NULL
, AF_UNSPEC
, SOCK_STREAM
, IPPROTO_TCP
);
191 for (auto address
: addresses
) {
192 m_fd
= ::socket(address
.GetFamily(), SOCK_STREAM
, IPPROTO_TCP
);
196 // Enable local address reuse
197 SetSocketOption(m_fd
, SOL_SOCKET
, SO_REUSEADDR
, 1);
199 address
.SetPort(port
);
201 if (-1 == ::connect(m_fd
, &address
.sockaddr(), address
.GetLength())) {
205 SetSocketOption(m_fd
, IPPROTO_TCP
, TCP_NODELAY
, 1);
207 result
= rnb_success
;
213 rnb_err_t
RNBSocket::useFD(int fd
) {
215 DNBLogThreadedIf(LOG_RNB_COMM
, "Bad file descriptor passed in.");
224 rnb_err_t
RNBSocket::ConnectToService() {
225 DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME
);
226 // Disconnect from any previous connections
228 if (::secure_lockdown_checkin(&m_ld_conn
, NULL
, NULL
) != kLDESuccess
) {
229 DNBLogThreadedIf(LOG_RNB_COMM
,
230 "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed");
232 return rnb_not_connected
;
234 m_fd
= ::lockdown_get_socket(m_ld_conn
);
236 DNBLogThreadedIf(LOG_RNB_COMM
, "::lockdown_get_socket() failed");
237 return rnb_not_connected
;
239 m_fd_from_lockdown
= true;
244 rnb_err_t
RNBSocket::OpenFile(const char *path
) {
246 m_fd
= open(path
, O_RDWR
);
248 err
.SetError(errno
, DNBError::POSIX
);
249 err
.LogThreaded("can't open file '%s'", path
);
250 return rnb_not_connected
;
252 struct termios stdin_termios
;
254 if (::tcgetattr(m_fd
, &stdin_termios
) == 0) {
255 stdin_termios
.c_lflag
&= ~ECHO
; // Turn off echoing
256 stdin_termios
.c_lflag
&= ~ICANON
; // Get one char at a time
257 ::tcsetattr(m_fd
, TCSANOW
, &stdin_termios
);
263 int RNBSocket::SetSocketOption(int fd
, int level
, int option_name
,
265 return ::setsockopt(fd
, level
, option_name
, &option_value
,
266 sizeof(option_value
));
269 rnb_err_t
RNBSocket::Disconnect(bool save_errno
) {
271 if (m_fd_from_lockdown
) {
272 m_fd_from_lockdown
= false;
274 lockdown_disconnect(m_ld_conn
);
278 return ClosePort(m_fd
, save_errno
);
281 rnb_err_t
RNBSocket::Read(std::string
&p
) {
285 // Note that BUF is on the stack so we must be careful to keep any
286 // writes to BUF from overflowing or we'll have security issues.
291 // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()",
292 // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
294 ssize_t bytesread
= read(m_fd
, buf
, sizeof(buf
));
296 err
.SetError(errno
, DNBError::POSIX
);
298 p
.append(buf
, bytesread
);
300 if (err
.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM
))
301 err
.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd
, buf
, sizeof(buf
),
302 (uint64_t)bytesread
);
304 // Our port went away - we have to mark this so IsConnected will return the
306 if (bytesread
== 0) {
308 return rnb_not_connected
;
309 } else if (bytesread
== -1) {
313 // Strip spaces from the end of the buffer
314 while (!p
.empty() && isspace(p
[p
.size() - 1]))
315 p
.erase(p
.size() - 1);
317 // Most data in the debugserver packets valid printable characters...
318 DNBLogThreadedIf(LOG_RNB_COMM
, "read: %s", p
.c_str());
322 rnb_err_t
RNBSocket::Write(const void *buffer
, size_t length
) {
327 ssize_t bytessent
= write(m_fd
, buffer
, length
);
329 err
.SetError(errno
, DNBError::POSIX
);
331 if (err
.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM
))
332 err
.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i",
333 m_fd
, buffer
, length
, (uint64_t)bytessent
);
338 if ((size_t)bytessent
!= length
)
342 LOG_RNB_PACKETS
, "putpkt: %*s", (int)length
,
344 buffer
); // All data is string based in debugserver, so this is safe
345 DNBLogThreadedIf(LOG_RNB_COMM
, "sent: %*s", (int)length
,
346 (const char *)buffer
);
351 rnb_err_t
RNBSocket::ClosePort(int &fd
, bool save_errno
) {
355 close_err
= close(fd
);
358 return close_err
!= 0 ? rnb_err
: rnb_success
;