blob: a3e04e9e59a5d10bb6f7393c5bc615c2f0824328 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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"
Kate Stoneb9c1b512016-09-06 20:57:50 +000015#include "DNBError.h"
16#include "DNBLog.h"
Greg Clayton95bf0fd2011-04-01 00:29:43 +000017#include <arpa/inet.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000018#include <errno.h>
19#include <fcntl.h>
Chris Bienemand01a2fa2017-04-18 20:01:59 +000020#include <map>
Greg Clayton95bf0fd2011-04-01 00:29:43 +000021#include <netdb.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000022#include <netinet/in.h>
23#include <netinet/tcp.h>
Chris Bienemand01a2fa2017-04-18 20:01:59 +000024#include <sys/event.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000025#include <termios.h>
Chris Bienemand01a2fa2017-04-18 20:01:59 +000026#include <vector>
27
28#include "lldb/Host/SocketAddress.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000029
Jason Molenda42999a42012-02-22 02:18:59 +000030#ifdef WITH_LOCKDOWN
Chris Lattner30fdc8d2010-06-08 16:52:24 +000031#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
Kate Stoneb9c1b512016-09-06 20:57:50 +000038bool 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)
Greg Claytonfd238892013-06-06 22:44:19 +000060 return true;
61 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000062 }
63 return false;
Greg Claytonfd238892013-06-06 22:44:19 +000064}
65
Kate Stoneb9c1b512016-09-06 20:57:50 +000066rnb_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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000073
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 DNBError err;
Chris Bienemand01a2fa2017-04-18 20:01:59 +000075 int queue_id = kqueue();
76 if (queue_id < 0) {
77 err.SetError(errno, DNBError::MachKernel);
78 err.LogThreaded("error: failed to create kqueue.");
Kate Stoneb9c1b512016-09-06 20:57:50 +000079 return rnb_err;
80 }
81
Chris Bienemand01a2fa2017-04-18 20:01:59 +000082 std::map<int, lldb_private::SocketAddress> sockets;
83 auto addresses =
84 lldb_private::SocketAddress::GetAddressInfo(listen_host, NULL);
Kate Stoneb9c1b512016-09-06 20:57:50 +000085
Chris Bienemand01a2fa2017-04-18 20:01:59 +000086 for (auto address : addresses) {
87 int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
88 if (sock_fd == -1)
89 continue;
Kate Stoneb9c1b512016-09-06 20:57:50 +000090
Chris Bienemand01a2fa2017-04-18 20:01:59 +000091 SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +000092
Chris Bienemand01a2fa2017-04-18 20:01:59 +000093 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;
Greg Claytonfd238892013-06-06 22:44:19 +000099 }
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000100
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;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000119
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000120 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 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000135
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136 bool accept_connection = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000137
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138 // Loop until we are happy with our connection
139 while (!accept_connection) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000140
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000141 struct kevent event_list[4];
142 int num_events =
143 kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000144
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000145 if (num_events < 0) {
146 err.SetError(errno, DNBError::MachKernel);
147 err.LogThreaded("error: kevent() failed.");
148 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000150 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;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000155
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000156 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())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 accept_connection = true;
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000168 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 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000183 }
Greg Clayton95bf0fd2011-04-01 00:29:43 +0000184 }
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000185 if (err.Fail())
186 break;
187 }
188 for (auto socket : sockets) {
189 int ListenFd = socket.first;
190 ClosePort(ListenFd, false);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191 }
192
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000193 if (err.Fail())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194 return rnb_err;
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000195
196 // Keep our TCP packets coming without any delays.
197 SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000198
199 return rnb_success;
Greg Clayton95bf0fd2011-04-01 00:29:43 +0000200}
201
Kate Stoneb9c1b512016-09-06 20:57:50 +0000202rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) {
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000203 auto result = rnb_err;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000204 Disconnect(false);
Jason Molenda42999a42012-02-22 02:18:59 +0000205
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000206 auto addresses = lldb_private::SocketAddress::GetAddressInfo(host, NULL);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000207
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000208 for (auto address : addresses) {
209 m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
210 if (m_fd == -1)
211 continue;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000213 // Enable local address reuse
214 SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000215
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000216 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;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000226 }
Chris Bienemand01a2fa2017-04-18 20:01:59 +0000227 return result;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000228}
229
Kate Stoneb9c1b512016-09-06 20:57:50 +0000230rnb_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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000238}
239
Jason Molenda42999a42012-02-22 02:18:59 +0000240#ifdef WITH_LOCKDOWN
Kate Stoneb9c1b512016-09-06 20:57:50 +0000241rnb_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}
Jason Molenda42999a42012-02-22 02:18:59 +0000259#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000260
261rnb_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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000278}
279
Kate Stoneb9c1b512016-09-06 20:57:50 +0000280int 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}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000285
Kate Stoneb9c1b512016-09-06 20:57:50 +0000286rnb_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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000292 return rnb_success;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000293 }
294#endif
295 return ClosePort(m_fd, save_errno);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000296}
297
Kate Stoneb9c1b512016-09-06 20:57:50 +0000298rnb_err_t RNBSocket::Read(std::string &p) {
299 char buf[1024];
300 p.clear();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000301
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302 // 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.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000304
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305 if (m_fd == -1)
306 return rnb_err;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000307
Kate Stoneb9c1b512016-09-06 20:57:50 +0000308 // 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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000316
Kate Stoneb9c1b512016-09-06 20:57:50 +0000317 if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
318 err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof(buf),
319 (uint64_t)bytesread);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000320
Kate Stoneb9c1b512016-09-06 20:57:50 +0000321 // 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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000333
Kate Stoneb9c1b512016-09-06 20:57:50 +0000334 // Most data in the debugserver packets valid printable characters...
335 DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
336 return rnb_success;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000337}
338
Kate Stoneb9c1b512016-09-06 20:57:50 +0000339rnb_err_t RNBSocket::Write(const void *buffer, size_t length) {
340 if (m_fd == -1)
341 return rnb_err;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000342
Kate Stoneb9c1b512016-09-06 20:57:50 +0000343 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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000365}
366
Kate Stoneb9c1b512016-09-06 20:57:50 +0000367rnb_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}