130fdc8d8SChris Lattner //===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner //
1030fdc8d8SChris Lattner //  Created by Greg Clayton on 12/12/07.
1130fdc8d8SChris Lattner //
1230fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1330fdc8d8SChris Lattner 
1430fdc8d8SChris Lattner #include "RNBSocket.h"
15b9c1b51eSKate Stone #include "DNBError.h"
16b9c1b51eSKate Stone #include "DNBLog.h"
1795bf0fd3SGreg Clayton #include <arpa/inet.h>
1830fdc8d8SChris Lattner #include <errno.h>
1930fdc8d8SChris Lattner #include <fcntl.h>
20*d01a2fa3SChris Bieneman #include <map>
2195bf0fd3SGreg Clayton #include <netdb.h>
2230fdc8d8SChris Lattner #include <netinet/in.h>
2330fdc8d8SChris Lattner #include <netinet/tcp.h>
24*d01a2fa3SChris Bieneman #include <sys/event.h>
2530fdc8d8SChris Lattner #include <termios.h>
26*d01a2fa3SChris Bieneman #include <vector>
27*d01a2fa3SChris Bieneman 
28*d01a2fa3SChris Bieneman #include "lldb/Host/SocketAddress.h"
2930fdc8d8SChris Lattner 
3042999a48SJason Molenda #ifdef WITH_LOCKDOWN
3130fdc8d8SChris Lattner #include "lockdown.h"
3230fdc8d8SChris Lattner #endif
3330fdc8d8SChris Lattner 
3430fdc8d8SChris Lattner /* Once we have a RNBSocket object with a port # specified,
3530fdc8d8SChris Lattner    this function is called to wait for an incoming connection.
3630fdc8d8SChris Lattner    This function blocks while waiting for that connection.  */
3730fdc8d8SChris Lattner 
38b9c1b51eSKate Stone bool ResolveIPV4HostName(const char *hostname, in_addr_t &addr) {
39b9c1b51eSKate Stone   if (hostname == NULL || hostname[0] == '\0' ||
40fd23889eSGreg Clayton       strcmp(hostname, "localhost") == 0 ||
41b9c1b51eSKate Stone       strcmp(hostname, "127.0.0.1") == 0) {
42fd23889eSGreg Clayton     addr = htonl(INADDR_LOOPBACK);
43fd23889eSGreg Clayton     return true;
44b9c1b51eSKate Stone   } else if (strcmp(hostname, "*") == 0) {
45fd23889eSGreg Clayton     addr = htonl(INADDR_ANY);
46fd23889eSGreg Clayton     return true;
47b9c1b51eSKate Stone   } else {
48fd23889eSGreg Clayton     // See if an IP address was specified as numbers
49fd23889eSGreg Clayton     int inet_pton_result = ::inet_pton(AF_INET, hostname, &addr);
50fd23889eSGreg Clayton 
51fd23889eSGreg Clayton     if (inet_pton_result == 1)
52fd23889eSGreg Clayton       return true;
53fd23889eSGreg Clayton 
54fd23889eSGreg Clayton     struct hostent *host_entry = gethostbyname(hostname);
55b9c1b51eSKate Stone     if (host_entry) {
56b9c1b51eSKate Stone       std::string ip_str(
57b9c1b51eSKate Stone           ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
58fd23889eSGreg Clayton       inet_pton_result = ::inet_pton(AF_INET, ip_str.c_str(), &addr);
59fd23889eSGreg Clayton       if (inet_pton_result == 1)
60fd23889eSGreg Clayton         return true;
61fd23889eSGreg Clayton     }
62fd23889eSGreg Clayton   }
63fd23889eSGreg Clayton   return false;
64fd23889eSGreg Clayton }
65fd23889eSGreg Clayton 
66b9c1b51eSKate Stone rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port,
67b9c1b51eSKate Stone                             PortBoundCallback callback,
68b9c1b51eSKate Stone                             const void *callback_baton) {
69b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called",
70b9c1b51eSKate Stone   // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
7130fdc8d8SChris Lattner   // Disconnect without saving errno
7230fdc8d8SChris Lattner   Disconnect(false);
7330fdc8d8SChris Lattner 
7430fdc8d8SChris Lattner   DNBError err;
75*d01a2fa3SChris Bieneman   int queue_id = kqueue();
76*d01a2fa3SChris Bieneman   if (queue_id < 0) {
77*d01a2fa3SChris Bieneman     err.SetError(errno, DNBError::MachKernel);
78*d01a2fa3SChris Bieneman     err.LogThreaded("error: failed to create kqueue.");
7930fdc8d8SChris Lattner     return rnb_err;
8030fdc8d8SChris Lattner   }
8130fdc8d8SChris Lattner 
82*d01a2fa3SChris Bieneman   std::map<int, lldb_private::SocketAddress> sockets;
83*d01a2fa3SChris Bieneman   auto addresses =
84*d01a2fa3SChris Bieneman       lldb_private::SocketAddress::GetAddressInfo(listen_host, NULL);
8530fdc8d8SChris Lattner 
86*d01a2fa3SChris Bieneman   for (auto address : addresses) {
87*d01a2fa3SChris Bieneman     int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
88*d01a2fa3SChris Bieneman     if (sock_fd == -1)
89*d01a2fa3SChris Bieneman       continue;
9030fdc8d8SChris Lattner 
91*d01a2fa3SChris Bieneman     SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1);
92*d01a2fa3SChris Bieneman 
93*d01a2fa3SChris Bieneman     address.SetPort(port);
94*d01a2fa3SChris Bieneman 
95*d01a2fa3SChris Bieneman     int error = ::bind(sock_fd, &address.sockaddr(), address.GetLength());
96*d01a2fa3SChris Bieneman     if (error == -1) {
97*d01a2fa3SChris Bieneman       ClosePort(sock_fd, false);
98*d01a2fa3SChris Bieneman       continue;
9930fdc8d8SChris Lattner     }
10030fdc8d8SChris Lattner 
101*d01a2fa3SChris Bieneman     error = ::listen(sock_fd, 5);
102*d01a2fa3SChris Bieneman     if (error == -1) {
103*d01a2fa3SChris Bieneman       ClosePort(sock_fd, false);
104*d01a2fa3SChris Bieneman       continue;
105*d01a2fa3SChris Bieneman     }
106*d01a2fa3SChris Bieneman 
107*d01a2fa3SChris Bieneman     // We were asked to listen on port zero which means we must now read the
108*d01a2fa3SChris Bieneman     // actual port that was given to us as port zero is a special code for "find
109*d01a2fa3SChris Bieneman     // an open port for me". This will only execute on the first socket created,
110*d01a2fa3SChris Bieneman     // subesquent sockets will reuse this port number.
111b9c1b51eSKate Stone     if (port == 0) {
112*d01a2fa3SChris Bieneman       socklen_t sa_len = address.GetLength();
113*d01a2fa3SChris Bieneman       if (getsockname(sock_fd, &address.sockaddr(), &sa_len) == 0)
114*d01a2fa3SChris Bieneman         port = address.GetPort();
11591a9b247SGreg Clayton     }
11691a9b247SGreg Clayton 
117*d01a2fa3SChris Bieneman     sockets[sock_fd] = address;
118*d01a2fa3SChris Bieneman   }
119*d01a2fa3SChris Bieneman 
120*d01a2fa3SChris Bieneman   if (sockets.size() == 0) {
121*d01a2fa3SChris Bieneman     err.SetError(errno, DNBError::POSIX);
122*d01a2fa3SChris Bieneman     err.LogThreaded("::listen or ::bind failed");
123*d01a2fa3SChris Bieneman     return rnb_err;
124*d01a2fa3SChris Bieneman   }
125*d01a2fa3SChris Bieneman 
126*d01a2fa3SChris Bieneman   if (callback)
127*d01a2fa3SChris Bieneman     callback(callback_baton, port);
128*d01a2fa3SChris Bieneman 
129*d01a2fa3SChris Bieneman   std::vector<struct kevent> events;
130*d01a2fa3SChris Bieneman   events.resize(sockets.size());
131*d01a2fa3SChris Bieneman   int i = 0;
132*d01a2fa3SChris Bieneman   for (auto socket : sockets) {
133*d01a2fa3SChris Bieneman     EV_SET(&events[i++], socket.first, EVFILT_READ, EV_ADD, 0, 0, 0);
134*d01a2fa3SChris Bieneman   }
135fd23889eSGreg Clayton 
136fd23889eSGreg Clayton   bool accept_connection = false;
137fd23889eSGreg Clayton 
138fd23889eSGreg Clayton   // Loop until we are happy with our connection
139b9c1b51eSKate Stone   while (!accept_connection) {
140fd23889eSGreg Clayton 
141*d01a2fa3SChris Bieneman     struct kevent event_list[4];
142*d01a2fa3SChris Bieneman     int num_events =
143*d01a2fa3SChris Bieneman         kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
144*d01a2fa3SChris Bieneman 
145*d01a2fa3SChris Bieneman     if (num_events < 0) {
146*d01a2fa3SChris Bieneman       err.SetError(errno, DNBError::MachKernel);
147*d01a2fa3SChris Bieneman       err.LogThreaded("error: kevent() failed.");
148*d01a2fa3SChris Bieneman     }
149*d01a2fa3SChris Bieneman 
150*d01a2fa3SChris Bieneman     for (int i = 0; i < num_events; ++i) {
151*d01a2fa3SChris Bieneman       auto sock_fd = event_list[i].ident;
152*d01a2fa3SChris Bieneman       auto socket_pair = sockets.find(sock_fd);
153*d01a2fa3SChris Bieneman       if (socket_pair == sockets.end())
154*d01a2fa3SChris Bieneman         continue;
155*d01a2fa3SChris Bieneman 
156*d01a2fa3SChris Bieneman       lldb_private::SocketAddress &addr_in = socket_pair->second;
157*d01a2fa3SChris Bieneman       lldb_private::SocketAddress accept_addr;
158*d01a2fa3SChris Bieneman       socklen_t sa_len = accept_addr.GetMaxLength();
159*d01a2fa3SChris Bieneman       m_fd = ::accept(sock_fd, &accept_addr.sockaddr(), &sa_len);
160*d01a2fa3SChris Bieneman 
161*d01a2fa3SChris Bieneman       if (m_fd == -1) {
16230fdc8d8SChris Lattner         err.SetError(errno, DNBError::POSIX);
163*d01a2fa3SChris Bieneman         err.LogThreaded("error: Socket accept failed.");
164*d01a2fa3SChris Bieneman       }
16530fdc8d8SChris Lattner 
166*d01a2fa3SChris Bieneman       if (addr_in.IsAnyAddr())
167fd23889eSGreg Clayton         accept_connection = true;
168b9c1b51eSKate Stone       else {
169*d01a2fa3SChris Bieneman         if (accept_addr == addr_in)
170fd23889eSGreg Clayton           accept_connection = true;
171*d01a2fa3SChris Bieneman         else {
172fd23889eSGreg Clayton           ::close(m_fd);
173fd23889eSGreg Clayton           m_fd = -1;
174*d01a2fa3SChris Bieneman           ::fprintf(
175*d01a2fa3SChris Bieneman               stderr,
176*d01a2fa3SChris Bieneman               "error: rejecting incoming connection from %s (expecting %s)\n",
177*d01a2fa3SChris Bieneman               accept_addr.GetIPAddress().c_str(),
178*d01a2fa3SChris Bieneman               addr_in.GetIPAddress().c_str());
179*d01a2fa3SChris Bieneman           DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n",
180*d01a2fa3SChris Bieneman                          accept_addr.GetIPAddress().c_str(),
181*d01a2fa3SChris Bieneman                          addr_in.GetIPAddress().c_str());
182fd23889eSGreg Clayton         }
183fd23889eSGreg Clayton       }
184fd23889eSGreg Clayton     }
185*d01a2fa3SChris Bieneman     if (err.Fail())
186*d01a2fa3SChris Bieneman       break;
187*d01a2fa3SChris Bieneman   }
188*d01a2fa3SChris Bieneman   for (auto socket : sockets) {
189*d01a2fa3SChris Bieneman     int ListenFd = socket.first;
190*d01a2fa3SChris Bieneman     ClosePort(ListenFd, false);
191*d01a2fa3SChris Bieneman   }
1928b82f087SGreg Clayton 
193*d01a2fa3SChris Bieneman   if (err.Fail())
19430fdc8d8SChris Lattner     return rnb_err;
195*d01a2fa3SChris Bieneman 
19630fdc8d8SChris Lattner   // Keep our TCP packets coming without any delays.
1978b82f087SGreg Clayton   SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
19830fdc8d8SChris Lattner 
19930fdc8d8SChris Lattner   return rnb_success;
20030fdc8d8SChris Lattner }
20130fdc8d8SChris Lattner 
202b9c1b51eSKate Stone rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) {
203*d01a2fa3SChris Bieneman   auto result = rnb_err;
20495bf0fd3SGreg Clayton   Disconnect(false);
20595bf0fd3SGreg Clayton 
206*d01a2fa3SChris Bieneman   auto addresses = lldb_private::SocketAddress::GetAddressInfo(host, NULL);
207*d01a2fa3SChris Bieneman 
208*d01a2fa3SChris Bieneman   for (auto address : addresses) {
209*d01a2fa3SChris Bieneman     m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
2108b82f087SGreg Clayton     if (m_fd == -1)
211*d01a2fa3SChris Bieneman       continue;
21295bf0fd3SGreg Clayton 
21395bf0fd3SGreg Clayton     // Enable local address reuse
2148b82f087SGreg Clayton     SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
21595bf0fd3SGreg Clayton 
216*d01a2fa3SChris Bieneman     address.SetPort(port);
21795bf0fd3SGreg Clayton 
218*d01a2fa3SChris Bieneman     if (-1 == ::connect(m_fd, &address.sockaddr(), address.GetLength())) {
21995bf0fd3SGreg Clayton       Disconnect(false);
220*d01a2fa3SChris Bieneman       continue;
22195bf0fd3SGreg Clayton     }
2228b82f087SGreg Clayton     SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
223*d01a2fa3SChris Bieneman 
224*d01a2fa3SChris Bieneman     result = rnb_success;
225*d01a2fa3SChris Bieneman     break;
226*d01a2fa3SChris Bieneman   }
227*d01a2fa3SChris Bieneman   return result;
22895bf0fd3SGreg Clayton }
22995bf0fd3SGreg Clayton 
230b9c1b51eSKate Stone rnb_err_t RNBSocket::useFD(int fd) {
23142999a48SJason Molenda   if (fd < 0) {
23242999a48SJason Molenda     DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in.");
23342999a48SJason Molenda     return rnb_err;
23442999a48SJason Molenda   }
23542999a48SJason Molenda 
23642999a48SJason Molenda   m_fd = fd;
23742999a48SJason Molenda   return rnb_success;
23842999a48SJason Molenda }
23942999a48SJason Molenda 
24042999a48SJason Molenda #ifdef WITH_LOCKDOWN
241b9c1b51eSKate Stone rnb_err_t RNBSocket::ConnectToService() {
24230fdc8d8SChris Lattner   DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
24330fdc8d8SChris Lattner   // Disconnect from any previous connections
24430fdc8d8SChris Lattner   Disconnect(false);
245b9c1b51eSKate Stone   if (::secure_lockdown_checkin(&m_ld_conn, NULL, NULL) != kLDESuccess) {
246b9c1b51eSKate Stone     DNBLogThreadedIf(LOG_RNB_COMM,
247b9c1b51eSKate Stone                      "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed");
24894379541SJason Molenda     m_fd = -1;
24930fdc8d8SChris Lattner     return rnb_not_connected;
25030fdc8d8SChris Lattner   }
2517eaf54d8SJason Molenda   m_fd = ::lockdown_get_socket(m_ld_conn);
252b9c1b51eSKate Stone   if (m_fd == -1) {
2537eaf54d8SJason Molenda     DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed");
2547eaf54d8SJason Molenda     return rnb_not_connected;
2557eaf54d8SJason Molenda   }
2568b82f087SGreg Clayton   m_fd_from_lockdown = true;
25730fdc8d8SChris Lattner   return rnb_success;
25830fdc8d8SChris Lattner }
25930fdc8d8SChris Lattner #endif
26030fdc8d8SChris Lattner 
261b9c1b51eSKate Stone rnb_err_t RNBSocket::OpenFile(const char *path) {
26230fdc8d8SChris Lattner   DNBError err;
2638b82f087SGreg Clayton   m_fd = open(path, O_RDWR);
264b9c1b51eSKate Stone   if (m_fd == -1) {
26530fdc8d8SChris Lattner     err.SetError(errno, DNBError::POSIX);
26630fdc8d8SChris Lattner     err.LogThreaded("can't open file '%s'", path);
26730fdc8d8SChris Lattner     return rnb_not_connected;
268b9c1b51eSKate Stone   } else {
26930fdc8d8SChris Lattner     struct termios stdin_termios;
27030fdc8d8SChris Lattner 
271b9c1b51eSKate Stone     if (::tcgetattr(m_fd, &stdin_termios) == 0) {
27230fdc8d8SChris Lattner       stdin_termios.c_lflag &= ~ECHO;   // Turn off echoing
27330fdc8d8SChris Lattner       stdin_termios.c_lflag &= ~ICANON; // Get one char at a time
2748b82f087SGreg Clayton       ::tcsetattr(m_fd, TCSANOW, &stdin_termios);
27530fdc8d8SChris Lattner     }
27630fdc8d8SChris Lattner   }
27730fdc8d8SChris Lattner   return rnb_success;
27830fdc8d8SChris Lattner }
27930fdc8d8SChris Lattner 
280b9c1b51eSKate Stone int RNBSocket::SetSocketOption(int fd, int level, int option_name,
281b9c1b51eSKate Stone                                int option_value) {
282b9c1b51eSKate Stone   return ::setsockopt(fd, level, option_name, &option_value,
283b9c1b51eSKate Stone                       sizeof(option_value));
28430fdc8d8SChris Lattner }
28530fdc8d8SChris Lattner 
286b9c1b51eSKate Stone rnb_err_t RNBSocket::Disconnect(bool save_errno) {
28742999a48SJason Molenda #ifdef WITH_LOCKDOWN
288b9c1b51eSKate Stone   if (m_fd_from_lockdown) {
2898b82f087SGreg Clayton     m_fd_from_lockdown = false;
2907eaf54d8SJason Molenda     m_fd = -1;
2912d512bcaSJim Ingham     lockdown_disconnect(m_ld_conn);
2927eaf54d8SJason Molenda     return rnb_success;
2937eaf54d8SJason Molenda   }
29442999a48SJason Molenda #endif
2958b82f087SGreg Clayton   return ClosePort(m_fd, save_errno);
29630fdc8d8SChris Lattner }
29730fdc8d8SChris Lattner 
298b9c1b51eSKate Stone rnb_err_t RNBSocket::Read(std::string &p) {
29930fdc8d8SChris Lattner   char buf[1024];
30030fdc8d8SChris Lattner   p.clear();
30130fdc8d8SChris Lattner 
30230fdc8d8SChris Lattner   // Note that BUF is on the stack so we must be careful to keep any
30330fdc8d8SChris Lattner   // writes to BUF from overflowing or we'll have security issues.
30430fdc8d8SChris Lattner 
3058b82f087SGreg Clayton   if (m_fd == -1)
30630fdc8d8SChris Lattner     return rnb_err;
30730fdc8d8SChris Lattner 
308b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()",
309b9c1b51eSKate Stone   // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
31030fdc8d8SChris Lattner   DNBError err;
311ee2ed525SGreg Clayton   ssize_t bytesread = read(m_fd, buf, sizeof(buf));
31230fdc8d8SChris Lattner   if (bytesread <= 0)
31330fdc8d8SChris Lattner     err.SetError(errno, DNBError::POSIX);
31430fdc8d8SChris Lattner   else
31530fdc8d8SChris Lattner     p.append(buf, bytesread);
31630fdc8d8SChris Lattner 
31730fdc8d8SChris Lattner   if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
318b9c1b51eSKate Stone     err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof(buf),
319b9c1b51eSKate Stone                     (uint64_t)bytesread);
32030fdc8d8SChris Lattner 
321b9c1b51eSKate Stone   // Our port went away - we have to mark this so IsConnected will return the
322b9c1b51eSKate Stone   // truth.
323b9c1b51eSKate Stone   if (bytesread == 0) {
3248b82f087SGreg Clayton     m_fd = -1;
32530fdc8d8SChris Lattner     return rnb_not_connected;
326b9c1b51eSKate Stone   } else if (bytesread == -1) {
3278b82f087SGreg Clayton     m_fd = -1;
32830fdc8d8SChris Lattner     return rnb_err;
32930fdc8d8SChris Lattner   }
33030fdc8d8SChris Lattner   // Strip spaces from the end of the buffer
33130fdc8d8SChris Lattner   while (!p.empty() && isspace(p[p.size() - 1]))
33230fdc8d8SChris Lattner     p.erase(p.size() - 1);
33330fdc8d8SChris Lattner 
33430fdc8d8SChris Lattner   // Most data in the debugserver packets valid printable characters...
33530fdc8d8SChris Lattner   DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
33630fdc8d8SChris Lattner   return rnb_success;
33730fdc8d8SChris Lattner }
33830fdc8d8SChris Lattner 
339b9c1b51eSKate Stone rnb_err_t RNBSocket::Write(const void *buffer, size_t length) {
3408b82f087SGreg Clayton   if (m_fd == -1)
34130fdc8d8SChris Lattner     return rnb_err;
34230fdc8d8SChris Lattner 
34330fdc8d8SChris Lattner   DNBError err;
344ee2ed525SGreg Clayton   ssize_t bytessent = write(m_fd, buffer, length);
34530fdc8d8SChris Lattner   if (bytessent < 0)
34630fdc8d8SChris Lattner     err.SetError(errno, DNBError::POSIX);
34730fdc8d8SChris Lattner 
34830fdc8d8SChris Lattner   if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
349b9c1b51eSKate Stone     err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i",
350b9c1b51eSKate Stone                     m_fd, buffer, length, (uint64_t)bytessent);
35130fdc8d8SChris Lattner 
35230fdc8d8SChris Lattner   if (bytessent < 0)
35330fdc8d8SChris Lattner     return rnb_err;
35430fdc8d8SChris Lattner 
355a026de05SBruce Mitchener   if ((size_t)bytessent != length)
35630fdc8d8SChris Lattner     return rnb_err;
35730fdc8d8SChris Lattner 
358b9c1b51eSKate Stone   DNBLogThreadedIf(
359b9c1b51eSKate Stone       LOG_RNB_PACKETS, "putpkt: %*s", (int)length,
360b9c1b51eSKate Stone       (char *)
361b9c1b51eSKate Stone           buffer); // All data is string based in debugserver, so this is safe
362490fbbe2SGreg Clayton   DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer);
36330fdc8d8SChris Lattner 
36430fdc8d8SChris Lattner   return rnb_success;
36530fdc8d8SChris Lattner }
36630fdc8d8SChris Lattner 
367b9c1b51eSKate Stone rnb_err_t RNBSocket::ClosePort(int &fd, bool save_errno) {
36830fdc8d8SChris Lattner   int close_err = 0;
369b9c1b51eSKate Stone   if (fd > 0) {
37030fdc8d8SChris Lattner     errno = 0;
37130fdc8d8SChris Lattner     close_err = close(fd);
37230fdc8d8SChris Lattner     fd = -1;
37330fdc8d8SChris Lattner   }
37430fdc8d8SChris Lattner   return close_err != 0 ? rnb_err : rnb_success;
37530fdc8d8SChris Lattner }
376