xref: /llvm-project/lldb/tools/debugserver/source/RNBSocket.cpp (revision d01a2fa38d728d0190e3a802d665726787a88b9c)
1 //===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Created by Greg Clayton on 12/12/07.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "RNBSocket.h"
15 #include "DNBError.h"
16 #include "DNBLog.h"
17 #include <arpa/inet.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <map>
21 #include <netdb.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <sys/event.h>
25 #include <termios.h>
26 #include <vector>
27 
28 #include "lldb/Host/SocketAddress.h"
29 
30 #ifdef WITH_LOCKDOWN
31 #include "lockdown.h"
32 #endif
33 
34 /* Once we have a RNBSocket object with a port # specified,
35    this function is called to wait for an incoming connection.
36    This function blocks while waiting for that connection.  */
37 
38 bool ResolveIPV4HostName(const char *hostname, in_addr_t &addr) {
39   if (hostname == NULL || hostname[0] == '\0' ||
40       strcmp(hostname, "localhost") == 0 ||
41       strcmp(hostname, "127.0.0.1") == 0) {
42     addr = htonl(INADDR_LOOPBACK);
43     return true;
44   } else if (strcmp(hostname, "*") == 0) {
45     addr = htonl(INADDR_ANY);
46     return true;
47   } else {
48     // See if an IP address was specified as numbers
49     int inet_pton_result = ::inet_pton(AF_INET, hostname, &addr);
50 
51     if (inet_pton_result == 1)
52       return true;
53 
54     struct hostent *host_entry = gethostbyname(hostname);
55     if (host_entry) {
56       std::string ip_str(
57           ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
58       inet_pton_result = ::inet_pton(AF_INET, ip_str.c_str(), &addr);
59       if (inet_pton_result == 1)
60         return true;
61     }
62   }
63   return false;
64 }
65 
66 rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port,
67                             PortBoundCallback callback,
68                             const void *callback_baton) {
69   // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called",
70   // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
71   // Disconnect without saving errno
72   Disconnect(false);
73 
74   DNBError err;
75   int queue_id = kqueue();
76   if (queue_id < 0) {
77     err.SetError(errno, DNBError::MachKernel);
78     err.LogThreaded("error: failed to create kqueue.");
79     return rnb_err;
80   }
81 
82   std::map<int, lldb_private::SocketAddress> sockets;
83   auto addresses =
84       lldb_private::SocketAddress::GetAddressInfo(listen_host, NULL);
85 
86   for (auto address : addresses) {
87     int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
88     if (sock_fd == -1)
89       continue;
90 
91     SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1);
92 
93     address.SetPort(port);
94 
95     int error = ::bind(sock_fd, &address.sockaddr(), address.GetLength());
96     if (error == -1) {
97       ClosePort(sock_fd, false);
98       continue;
99     }
100 
101     error = ::listen(sock_fd, 5);
102     if (error == -1) {
103       ClosePort(sock_fd, false);
104       continue;
105     }
106 
107     // We were asked to listen on port zero which means we must now read the
108     // actual port that was given to us as port zero is a special code for "find
109     // an open port for me". This will only execute on the first socket created,
110     // subesquent sockets will reuse this port number.
111     if (port == 0) {
112       socklen_t sa_len = address.GetLength();
113       if (getsockname(sock_fd, &address.sockaddr(), &sa_len) == 0)
114         port = address.GetPort();
115     }
116 
117     sockets[sock_fd] = address;
118   }
119 
120   if (sockets.size() == 0) {
121     err.SetError(errno, DNBError::POSIX);
122     err.LogThreaded("::listen or ::bind failed");
123     return rnb_err;
124   }
125 
126   if (callback)
127     callback(callback_baton, port);
128 
129   std::vector<struct kevent> events;
130   events.resize(sockets.size());
131   int i = 0;
132   for (auto socket : sockets) {
133     EV_SET(&events[i++], socket.first, EVFILT_READ, EV_ADD, 0, 0, 0);
134   }
135 
136   bool accept_connection = false;
137 
138   // Loop until we are happy with our connection
139   while (!accept_connection) {
140 
141     struct kevent event_list[4];
142     int num_events =
143         kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
144 
145     if (num_events < 0) {
146       err.SetError(errno, DNBError::MachKernel);
147       err.LogThreaded("error: kevent() failed.");
148     }
149 
150     for (int i = 0; i < num_events; ++i) {
151       auto sock_fd = event_list[i].ident;
152       auto socket_pair = sockets.find(sock_fd);
153       if (socket_pair == sockets.end())
154         continue;
155 
156       lldb_private::SocketAddress &addr_in = socket_pair->second;
157       lldb_private::SocketAddress accept_addr;
158       socklen_t sa_len = accept_addr.GetMaxLength();
159       m_fd = ::accept(sock_fd, &accept_addr.sockaddr(), &sa_len);
160 
161       if (m_fd == -1) {
162         err.SetError(errno, DNBError::POSIX);
163         err.LogThreaded("error: Socket accept failed.");
164       }
165 
166       if (addr_in.IsAnyAddr())
167         accept_connection = true;
168       else {
169         if (accept_addr == addr_in)
170           accept_connection = true;
171         else {
172           ::close(m_fd);
173           m_fd = -1;
174           ::fprintf(
175               stderr,
176               "error: rejecting incoming connection from %s (expecting %s)\n",
177               accept_addr.GetIPAddress().c_str(),
178               addr_in.GetIPAddress().c_str());
179           DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n",
180                          accept_addr.GetIPAddress().c_str(),
181                          addr_in.GetIPAddress().c_str());
182         }
183       }
184     }
185     if (err.Fail())
186       break;
187   }
188   for (auto socket : sockets) {
189     int ListenFd = socket.first;
190     ClosePort(ListenFd, false);
191   }
192 
193   if (err.Fail())
194     return rnb_err;
195 
196   // Keep our TCP packets coming without any delays.
197   SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
198 
199   return rnb_success;
200 }
201 
202 rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) {
203   auto result = rnb_err;
204   Disconnect(false);
205 
206   auto addresses = lldb_private::SocketAddress::GetAddressInfo(host, NULL);
207 
208   for (auto address : addresses) {
209     m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
210     if (m_fd == -1)
211       continue;
212 
213     // Enable local address reuse
214     SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
215 
216     address.SetPort(port);
217 
218     if (-1 == ::connect(m_fd, &address.sockaddr(), address.GetLength())) {
219       Disconnect(false);
220       continue;
221     }
222     SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
223 
224     result = rnb_success;
225     break;
226   }
227   return result;
228 }
229 
230 rnb_err_t RNBSocket::useFD(int fd) {
231   if (fd < 0) {
232     DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in.");
233     return rnb_err;
234   }
235 
236   m_fd = fd;
237   return rnb_success;
238 }
239 
240 #ifdef WITH_LOCKDOWN
241 rnb_err_t RNBSocket::ConnectToService() {
242   DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
243   // Disconnect from any previous connections
244   Disconnect(false);
245   if (::secure_lockdown_checkin(&m_ld_conn, NULL, NULL) != kLDESuccess) {
246     DNBLogThreadedIf(LOG_RNB_COMM,
247                      "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed");
248     m_fd = -1;
249     return rnb_not_connected;
250   }
251   m_fd = ::lockdown_get_socket(m_ld_conn);
252   if (m_fd == -1) {
253     DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed");
254     return rnb_not_connected;
255   }
256   m_fd_from_lockdown = true;
257   return rnb_success;
258 }
259 #endif
260 
261 rnb_err_t RNBSocket::OpenFile(const char *path) {
262   DNBError err;
263   m_fd = open(path, O_RDWR);
264   if (m_fd == -1) {
265     err.SetError(errno, DNBError::POSIX);
266     err.LogThreaded("can't open file '%s'", path);
267     return rnb_not_connected;
268   } else {
269     struct termios stdin_termios;
270 
271     if (::tcgetattr(m_fd, &stdin_termios) == 0) {
272       stdin_termios.c_lflag &= ~ECHO;   // Turn off echoing
273       stdin_termios.c_lflag &= ~ICANON; // Get one char at a time
274       ::tcsetattr(m_fd, TCSANOW, &stdin_termios);
275     }
276   }
277   return rnb_success;
278 }
279 
280 int RNBSocket::SetSocketOption(int fd, int level, int option_name,
281                                int option_value) {
282   return ::setsockopt(fd, level, option_name, &option_value,
283                       sizeof(option_value));
284 }
285 
286 rnb_err_t RNBSocket::Disconnect(bool save_errno) {
287 #ifdef WITH_LOCKDOWN
288   if (m_fd_from_lockdown) {
289     m_fd_from_lockdown = false;
290     m_fd = -1;
291     lockdown_disconnect(m_ld_conn);
292     return rnb_success;
293   }
294 #endif
295   return ClosePort(m_fd, save_errno);
296 }
297 
298 rnb_err_t RNBSocket::Read(std::string &p) {
299   char buf[1024];
300   p.clear();
301 
302   // Note that BUF is on the stack so we must be careful to keep any
303   // writes to BUF from overflowing or we'll have security issues.
304 
305   if (m_fd == -1)
306     return rnb_err;
307 
308   // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()",
309   // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
310   DNBError err;
311   ssize_t bytesread = read(m_fd, buf, sizeof(buf));
312   if (bytesread <= 0)
313     err.SetError(errno, DNBError::POSIX);
314   else
315     p.append(buf, bytesread);
316 
317   if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
318     err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof(buf),
319                     (uint64_t)bytesread);
320 
321   // Our port went away - we have to mark this so IsConnected will return the
322   // truth.
323   if (bytesread == 0) {
324     m_fd = -1;
325     return rnb_not_connected;
326   } else if (bytesread == -1) {
327     m_fd = -1;
328     return rnb_err;
329   }
330   // Strip spaces from the end of the buffer
331   while (!p.empty() && isspace(p[p.size() - 1]))
332     p.erase(p.size() - 1);
333 
334   // Most data in the debugserver packets valid printable characters...
335   DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
336   return rnb_success;
337 }
338 
339 rnb_err_t RNBSocket::Write(const void *buffer, size_t length) {
340   if (m_fd == -1)
341     return rnb_err;
342 
343   DNBError err;
344   ssize_t bytessent = write(m_fd, buffer, length);
345   if (bytessent < 0)
346     err.SetError(errno, DNBError::POSIX);
347 
348   if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
349     err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i",
350                     m_fd, buffer, length, (uint64_t)bytessent);
351 
352   if (bytessent < 0)
353     return rnb_err;
354 
355   if ((size_t)bytessent != length)
356     return rnb_err;
357 
358   DNBLogThreadedIf(
359       LOG_RNB_PACKETS, "putpkt: %*s", (int)length,
360       (char *)
361           buffer); // All data is string based in debugserver, so this is safe
362   DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer);
363 
364   return rnb_success;
365 }
366 
367 rnb_err_t RNBSocket::ClosePort(int &fd, bool save_errno) {
368   int close_err = 0;
369   if (fd > 0) {
370     errno = 0;
371     close_err = close(fd);
372     fd = -1;
373   }
374   return close_err != 0 ? rnb_err : rnb_success;
375 }
376