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"
1595bf0fd3SGreg Clayton #include <arpa/inet.h>
1630fdc8d8SChris Lattner #include <errno.h>
1730fdc8d8SChris Lattner #include <fcntl.h>
1895bf0fd3SGreg Clayton #include <netdb.h>
1930fdc8d8SChris Lattner #include <netinet/in.h>
2030fdc8d8SChris Lattner #include <netinet/tcp.h>
2130fdc8d8SChris Lattner #include <termios.h>
2230fdc8d8SChris Lattner #include "DNBLog.h"
2330fdc8d8SChris Lattner #include "DNBError.h"
2430fdc8d8SChris Lattner 
2542999a48SJason Molenda #ifdef WITH_LOCKDOWN
2630fdc8d8SChris Lattner #include "lockdown.h"
2730fdc8d8SChris Lattner #endif
2830fdc8d8SChris Lattner 
2930fdc8d8SChris Lattner /* Once we have a RNBSocket object with a port # specified,
3030fdc8d8SChris Lattner    this function is called to wait for an incoming connection.
3130fdc8d8SChris Lattner    This function blocks while waiting for that connection.  */
3230fdc8d8SChris Lattner 
33fd23889eSGreg Clayton bool
34fd23889eSGreg Clayton ResolveIPV4HostName (const char *hostname, in_addr_t &addr)
35fd23889eSGreg Clayton {
36fd23889eSGreg Clayton     if (hostname == NULL ||
37fd23889eSGreg Clayton         hostname[0] == '\0' ||
38fd23889eSGreg Clayton         strcmp(hostname, "localhost") == 0 ||
39fd23889eSGreg Clayton         strcmp(hostname, "127.0.0.1") == 0)
40fd23889eSGreg Clayton     {
41fd23889eSGreg Clayton         addr = htonl (INADDR_LOOPBACK);
42fd23889eSGreg Clayton         return true;
43fd23889eSGreg Clayton     }
44fd23889eSGreg Clayton     else if (strcmp(hostname, "*") == 0)
45fd23889eSGreg Clayton     {
46fd23889eSGreg Clayton         addr = htonl (INADDR_ANY);
47fd23889eSGreg Clayton         return true;
48fd23889eSGreg Clayton     }
49fd23889eSGreg Clayton     else
50fd23889eSGreg Clayton     {
51fd23889eSGreg Clayton         // See if an IP address was specified as numbers
52fd23889eSGreg Clayton         int inet_pton_result = ::inet_pton (AF_INET, hostname, &addr);
53fd23889eSGreg Clayton 
54fd23889eSGreg Clayton         if (inet_pton_result == 1)
55fd23889eSGreg Clayton             return true;
56fd23889eSGreg Clayton 
57fd23889eSGreg Clayton         struct hostent *host_entry = gethostbyname (hostname);
58fd23889eSGreg Clayton         if (host_entry)
59fd23889eSGreg Clayton         {
60fd23889eSGreg Clayton             std::string ip_str (::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list));
61fd23889eSGreg Clayton             inet_pton_result = ::inet_pton (AF_INET, ip_str.c_str(), &addr);
62fd23889eSGreg Clayton             if (inet_pton_result == 1)
63fd23889eSGreg Clayton                 return true;
64fd23889eSGreg Clayton         }
65fd23889eSGreg Clayton     }
66fd23889eSGreg Clayton     return false;
67fd23889eSGreg Clayton }
68fd23889eSGreg Clayton 
6930fdc8d8SChris Lattner rnb_err_t
70d629980aSGreg Clayton RNBSocket::Listen (const char *listen_host, uint16_t port, PortBoundCallback callback, const void *callback_baton)
7130fdc8d8SChris Lattner {
7230fdc8d8SChris Lattner     //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
7330fdc8d8SChris Lattner     // Disconnect without saving errno
7430fdc8d8SChris Lattner     Disconnect (false);
7530fdc8d8SChris Lattner 
76fd23889eSGreg Clayton     // Now figure out the hostname that will be attaching and palce it into
77fd23889eSGreg Clayton     struct sockaddr_in listen_addr;
78fd23889eSGreg Clayton     ::memset (&listen_addr, 0, sizeof listen_addr);
79fd23889eSGreg Clayton     listen_addr.sin_len = sizeof listen_addr;
80fd23889eSGreg Clayton     listen_addr.sin_family = AF_INET;
81fd23889eSGreg Clayton     listen_addr.sin_port = htons (port);
82fd23889eSGreg Clayton     listen_addr.sin_addr.s_addr = INADDR_ANY;
83fd23889eSGreg Clayton 
84fd23889eSGreg Clayton     if (!ResolveIPV4HostName(listen_host, listen_addr.sin_addr.s_addr))
85fd23889eSGreg Clayton     {
86fd23889eSGreg Clayton         DNBLogThreaded("error: failed to resolve connecting host '%s'", listen_host);
87fd23889eSGreg Clayton         return rnb_err;
88fd23889eSGreg Clayton     }
89fd23889eSGreg Clayton 
9030fdc8d8SChris Lattner     DNBError err;
918b82f087SGreg Clayton     int listen_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
928b82f087SGreg Clayton     if (listen_fd == -1)
9330fdc8d8SChris Lattner         err.SetError(errno, DNBError::POSIX);
9430fdc8d8SChris Lattner 
9530fdc8d8SChris Lattner     if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
968b82f087SGreg Clayton         err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_fd);
9730fdc8d8SChris Lattner 
9830fdc8d8SChris Lattner     if (err.Fail())
9930fdc8d8SChris Lattner         return rnb_err;
10030fdc8d8SChris Lattner 
10130fdc8d8SChris Lattner     // enable local address reuse
1028b82f087SGreg Clayton     SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1);
10330fdc8d8SChris Lattner 
10430fdc8d8SChris Lattner     struct sockaddr_in sa;
10530fdc8d8SChris Lattner     ::memset (&sa, 0, sizeof sa);
10630fdc8d8SChris Lattner     sa.sin_len = sizeof sa;
10730fdc8d8SChris Lattner     sa.sin_family = AF_INET;
1088b82f087SGreg Clayton     sa.sin_port = htons (port);
109fd23889eSGreg Clayton     sa.sin_addr.s_addr = INADDR_ANY; // Let incoming connections bind to any host network interface (this is NOT who can connect to us)
1108b82f087SGreg Clayton     int error = ::bind (listen_fd, (struct sockaddr *) &sa, sizeof(sa));
11130fdc8d8SChris Lattner     if (error == -1)
11230fdc8d8SChris Lattner         err.SetError(errno, DNBError::POSIX);
11330fdc8d8SChris Lattner 
11430fdc8d8SChris Lattner     if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
1158b82f087SGreg Clayton         err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_fd);
11630fdc8d8SChris Lattner 
11730fdc8d8SChris Lattner     if (err.Fail())
11830fdc8d8SChris Lattner     {
1198b82f087SGreg Clayton         ClosePort (listen_fd, false);
12030fdc8d8SChris Lattner         return rnb_err;
12130fdc8d8SChris Lattner     }
12230fdc8d8SChris Lattner 
123fd23889eSGreg Clayton     error = ::listen (listen_fd, 5);
12430fdc8d8SChris Lattner     if (error == -1)
12530fdc8d8SChris Lattner         err.SetError(errno, DNBError::POSIX);
12630fdc8d8SChris Lattner 
12730fdc8d8SChris Lattner     if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
1288b82f087SGreg Clayton         err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd);
12930fdc8d8SChris Lattner 
13030fdc8d8SChris Lattner     if (err.Fail())
13130fdc8d8SChris Lattner     {
1328b82f087SGreg Clayton         ClosePort (listen_fd, false);
13330fdc8d8SChris Lattner         return rnb_err;
13430fdc8d8SChris Lattner     }
13530fdc8d8SChris Lattner 
13691a9b247SGreg Clayton     if (callback)
13791a9b247SGreg Clayton     {
13891a9b247SGreg Clayton         // We were asked to listen on port zero which means we
13991a9b247SGreg Clayton         // must now read the actual port that was given to us
14091a9b247SGreg Clayton         // as port zero is a special code for "find an open port
14191a9b247SGreg Clayton         // for me".
14291a9b247SGreg Clayton         if (port == 0)
14391a9b247SGreg Clayton         {
14491a9b247SGreg Clayton             socklen_t sa_len = sizeof (sa);
14591a9b247SGreg Clayton             if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0)
14691a9b247SGreg Clayton             {
14791a9b247SGreg Clayton                 port = ntohs (sa.sin_port);
14891a9b247SGreg Clayton                 callback (callback_baton, port);
14991a9b247SGreg Clayton             }
15091a9b247SGreg Clayton         }
15191a9b247SGreg Clayton         else
15291a9b247SGreg Clayton         {
15391a9b247SGreg Clayton             callback (callback_baton, port);
15491a9b247SGreg Clayton         }
15591a9b247SGreg Clayton     }
15691a9b247SGreg Clayton 
157fd23889eSGreg Clayton     struct sockaddr_in accept_addr;
158fd23889eSGreg Clayton     ::memset (&accept_addr, 0, sizeof accept_addr);
159fd23889eSGreg Clayton     accept_addr.sin_len = sizeof accept_addr;
160fd23889eSGreg Clayton 
161fd23889eSGreg Clayton     bool accept_connection = false;
162fd23889eSGreg Clayton 
163fd23889eSGreg Clayton     // Loop until we are happy with our connection
164fd23889eSGreg Clayton     while (!accept_connection)
165fd23889eSGreg Clayton     {
166fd23889eSGreg Clayton         socklen_t accept_addr_len = sizeof accept_addr;
167fd23889eSGreg Clayton         m_fd = ::accept (listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len);
168fd23889eSGreg Clayton 
1698b82f087SGreg Clayton         if (m_fd == -1)
17030fdc8d8SChris Lattner             err.SetError(errno, DNBError::POSIX);
17130fdc8d8SChris Lattner 
17230fdc8d8SChris Lattner         if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
173fd23889eSGreg Clayton             err.LogThreaded("::accept ( socket = %i, address = %p, address_len = %u )", listen_fd, &accept_addr, accept_addr_len);
174fd23889eSGreg Clayton 
175fd23889eSGreg Clayton         if (err.Fail())
176fd23889eSGreg Clayton             break;
177fd23889eSGreg Clayton 
178fd23889eSGreg Clayton         if (listen_addr.sin_addr.s_addr == INADDR_ANY)
179fd23889eSGreg Clayton             accept_connection = true;
180fd23889eSGreg Clayton         else
181fd23889eSGreg Clayton         {
182fd23889eSGreg Clayton             if (accept_addr_len == listen_addr.sin_len &&
183fd23889eSGreg Clayton                 accept_addr.sin_addr.s_addr == listen_addr.sin_addr.s_addr)
184fd23889eSGreg Clayton             {
185fd23889eSGreg Clayton                 accept_connection = true;
186fd23889eSGreg Clayton             }
187fd23889eSGreg Clayton             else
188fd23889eSGreg Clayton             {
189fd23889eSGreg Clayton                 ::close (m_fd);
190fd23889eSGreg Clayton                 m_fd = -1;
191fd23889eSGreg Clayton                 const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
192fd23889eSGreg Clayton                 const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sin_addr.s_addr;
193fd23889eSGreg Clayton                 ::fprintf (stderr,
194fd23889eSGreg Clayton                            "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n",
195fd23889eSGreg Clayton                            accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
196fd23889eSGreg Clayton                            listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
197fd23889eSGreg Clayton                 DNBLogThreaded ("error: rejecting connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)",
198fd23889eSGreg Clayton                                 accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
199fd23889eSGreg Clayton                                 listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
200fd23889eSGreg Clayton             }
201fd23889eSGreg Clayton         }
202fd23889eSGreg Clayton     }
2038b82f087SGreg Clayton 
2048b82f087SGreg Clayton     ClosePort (listen_fd, false);
20530fdc8d8SChris Lattner 
20630fdc8d8SChris Lattner     if (err.Fail())
20730fdc8d8SChris Lattner     {
20830fdc8d8SChris Lattner         return rnb_err;
20930fdc8d8SChris Lattner     }
21030fdc8d8SChris Lattner     else
21130fdc8d8SChris Lattner     {
21230fdc8d8SChris Lattner         // Keep our TCP packets coming without any delays.
2138b82f087SGreg Clayton         SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
21430fdc8d8SChris Lattner     }
21530fdc8d8SChris Lattner 
21630fdc8d8SChris Lattner     return rnb_success;
21730fdc8d8SChris Lattner }
21830fdc8d8SChris Lattner 
21995bf0fd3SGreg Clayton rnb_err_t
22095bf0fd3SGreg Clayton RNBSocket::Connect (const char *host, uint16_t port)
22195bf0fd3SGreg Clayton {
22295bf0fd3SGreg Clayton     Disconnect (false);
22395bf0fd3SGreg Clayton 
22495bf0fd3SGreg Clayton     // Create the socket
2258b82f087SGreg Clayton     m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
2268b82f087SGreg Clayton     if (m_fd == -1)
22795bf0fd3SGreg Clayton         return rnb_err;
22895bf0fd3SGreg Clayton 
22995bf0fd3SGreg Clayton     // Enable local address reuse
2308b82f087SGreg Clayton     SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
23195bf0fd3SGreg Clayton 
23295bf0fd3SGreg Clayton     struct sockaddr_in sa;
23395bf0fd3SGreg Clayton     ::memset (&sa, 0, sizeof (sa));
23495bf0fd3SGreg Clayton     sa.sin_family = AF_INET;
23595bf0fd3SGreg Clayton     sa.sin_port = htons (port);
23695bf0fd3SGreg Clayton 
237fd23889eSGreg Clayton     if (!ResolveIPV4HostName(host, sa.sin_addr.s_addr))
23895bf0fd3SGreg Clayton     {
239fd23889eSGreg Clayton         DNBLogThreaded("error: failed to resolve host '%s'", host);
24095bf0fd3SGreg Clayton         Disconnect (false);
24195bf0fd3SGreg Clayton         return rnb_err;
24295bf0fd3SGreg Clayton     }
24395bf0fd3SGreg Clayton 
2448b82f087SGreg Clayton     if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa)))
24595bf0fd3SGreg Clayton     {
24695bf0fd3SGreg Clayton         Disconnect (false);
24795bf0fd3SGreg Clayton         return rnb_err;
24895bf0fd3SGreg Clayton     }
24995bf0fd3SGreg Clayton 
25095bf0fd3SGreg Clayton     // Keep our TCP packets coming without any delays.
2518b82f087SGreg Clayton     SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
25295bf0fd3SGreg Clayton     return rnb_success;
25395bf0fd3SGreg Clayton }
25495bf0fd3SGreg Clayton 
25542999a48SJason Molenda rnb_err_t
25642999a48SJason Molenda RNBSocket::useFD(int fd)
25742999a48SJason Molenda {
25842999a48SJason Molenda        if (fd < 0) {
25942999a48SJason Molenda                DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in.");
26042999a48SJason Molenda                return rnb_err;
26142999a48SJason Molenda        }
26242999a48SJason Molenda 
26342999a48SJason Molenda        m_fd = fd;
26442999a48SJason Molenda        return rnb_success;
26542999a48SJason Molenda }
26642999a48SJason Molenda 
26742999a48SJason Molenda #ifdef WITH_LOCKDOWN
26830fdc8d8SChris Lattner rnb_err_t
26930fdc8d8SChris Lattner RNBSocket::ConnectToService()
27030fdc8d8SChris Lattner {
27130fdc8d8SChris Lattner     DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
27230fdc8d8SChris Lattner     // Disconnect from any previous connections
27330fdc8d8SChris Lattner     Disconnect(false);
2747eaf54d8SJason Molenda     if (::secure_lockdown_checkin (&m_ld_conn, NULL, NULL) != kLDESuccess)
27530fdc8d8SChris Lattner     {
2767eaf54d8SJason Molenda         DNBLogThreadedIf(LOG_RNB_COMM, "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed");
27794379541SJason Molenda         m_fd = -1;
27830fdc8d8SChris Lattner         return rnb_not_connected;
27930fdc8d8SChris Lattner     }
2807eaf54d8SJason Molenda     m_fd = ::lockdown_get_socket (m_ld_conn);
2817eaf54d8SJason Molenda     if (m_fd == -1)
2827eaf54d8SJason Molenda     {
2837eaf54d8SJason Molenda         DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed");
2847eaf54d8SJason Molenda         return rnb_not_connected;
2857eaf54d8SJason Molenda     }
2868b82f087SGreg Clayton     m_fd_from_lockdown = true;
28730fdc8d8SChris Lattner     return rnb_success;
28830fdc8d8SChris Lattner }
28930fdc8d8SChris Lattner #endif
29030fdc8d8SChris Lattner 
29130fdc8d8SChris Lattner rnb_err_t
29230fdc8d8SChris Lattner RNBSocket::OpenFile (const char *path)
29330fdc8d8SChris Lattner {
29430fdc8d8SChris Lattner     DNBError err;
2958b82f087SGreg Clayton     m_fd = open (path, O_RDWR);
2968b82f087SGreg Clayton     if (m_fd == -1)
29730fdc8d8SChris Lattner     {
29830fdc8d8SChris Lattner         err.SetError(errno, DNBError::POSIX);
29930fdc8d8SChris Lattner         err.LogThreaded ("can't open file '%s'", path);
30030fdc8d8SChris Lattner         return rnb_not_connected;
30130fdc8d8SChris Lattner     }
30230fdc8d8SChris Lattner     else
30330fdc8d8SChris Lattner     {
30430fdc8d8SChris Lattner         struct termios stdin_termios;
30530fdc8d8SChris Lattner 
3068b82f087SGreg Clayton         if (::tcgetattr (m_fd, &stdin_termios) == 0)
30730fdc8d8SChris Lattner         {
30830fdc8d8SChris Lattner             stdin_termios.c_lflag &= ~ECHO;     // Turn off echoing
30930fdc8d8SChris Lattner             stdin_termios.c_lflag &= ~ICANON;   // Get one char at a time
3108b82f087SGreg Clayton             ::tcsetattr (m_fd, TCSANOW, &stdin_termios);
31130fdc8d8SChris Lattner         }
31230fdc8d8SChris Lattner     }
31330fdc8d8SChris Lattner     return rnb_success;
31430fdc8d8SChris Lattner }
31530fdc8d8SChris Lattner 
31630fdc8d8SChris Lattner int
31730fdc8d8SChris Lattner RNBSocket::SetSocketOption(int fd, int level, int option_name, int option_value)
31830fdc8d8SChris Lattner {
31930fdc8d8SChris Lattner     return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
32030fdc8d8SChris Lattner }
32130fdc8d8SChris Lattner 
32230fdc8d8SChris Lattner rnb_err_t
32330fdc8d8SChris Lattner RNBSocket::Disconnect (bool save_errno)
32430fdc8d8SChris Lattner {
32542999a48SJason Molenda #ifdef WITH_LOCKDOWN
3268b82f087SGreg Clayton     if (m_fd_from_lockdown)
3277eaf54d8SJason Molenda     {
3288b82f087SGreg Clayton         m_fd_from_lockdown = false;
3297eaf54d8SJason Molenda         m_fd = -1;
3302d512bcaSJim Ingham         lockdown_disconnect (m_ld_conn);
3317eaf54d8SJason Molenda         return rnb_success;
3327eaf54d8SJason Molenda     }
33342999a48SJason Molenda #endif
3348b82f087SGreg Clayton     return ClosePort (m_fd, save_errno);
33530fdc8d8SChris Lattner }
33630fdc8d8SChris Lattner 
33730fdc8d8SChris Lattner 
33830fdc8d8SChris Lattner rnb_err_t
33930fdc8d8SChris Lattner RNBSocket::Read (std::string &p)
34030fdc8d8SChris Lattner {
34130fdc8d8SChris Lattner     char buf[1024];
34230fdc8d8SChris Lattner     p.clear();
34330fdc8d8SChris Lattner 
34430fdc8d8SChris Lattner     // Note that BUF is on the stack so we must be careful to keep any
34530fdc8d8SChris Lattner     // writes to BUF from overflowing or we'll have security issues.
34630fdc8d8SChris Lattner 
3478b82f087SGreg Clayton     if (m_fd == -1)
34830fdc8d8SChris Lattner         return rnb_err;
34930fdc8d8SChris Lattner 
35030fdc8d8SChris Lattner     //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
35130fdc8d8SChris Lattner     DNBError err;
352*ee2ed525SGreg Clayton     ssize_t bytesread = read (m_fd, buf, sizeof (buf));
35330fdc8d8SChris Lattner     if (bytesread <= 0)
35430fdc8d8SChris Lattner         err.SetError(errno, DNBError::POSIX);
35530fdc8d8SChris Lattner     else
35630fdc8d8SChris Lattner         p.append(buf, bytesread);
35730fdc8d8SChris Lattner 
35830fdc8d8SChris Lattner     if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
35943e0af06SGreg Clayton         err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof (buf), (uint64_t)bytesread);
36030fdc8d8SChris Lattner 
36130fdc8d8SChris Lattner     // Our port went away - we have to mark this so IsConnected will return the truth.
36230fdc8d8SChris Lattner     if (bytesread == 0)
36330fdc8d8SChris Lattner     {
3648b82f087SGreg Clayton         m_fd = -1;
36530fdc8d8SChris Lattner         return rnb_not_connected;
36630fdc8d8SChris Lattner     }
36730fdc8d8SChris Lattner     else if (bytesread == -1)
36830fdc8d8SChris Lattner     {
3698b82f087SGreg Clayton         m_fd = -1;
37030fdc8d8SChris Lattner         return rnb_err;
37130fdc8d8SChris Lattner     }
37230fdc8d8SChris Lattner     // Strip spaces from the end of the buffer
37330fdc8d8SChris Lattner     while (!p.empty() && isspace (p[p.size() - 1]))
37430fdc8d8SChris Lattner         p.erase (p.size () - 1);
37530fdc8d8SChris Lattner 
37630fdc8d8SChris Lattner     // Most data in the debugserver packets valid printable characters...
37730fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
37830fdc8d8SChris Lattner     return rnb_success;
37930fdc8d8SChris Lattner }
38030fdc8d8SChris Lattner 
38130fdc8d8SChris Lattner rnb_err_t
38230fdc8d8SChris Lattner RNBSocket::Write (const void *buffer, size_t length)
38330fdc8d8SChris Lattner {
3848b82f087SGreg Clayton     if (m_fd == -1)
38530fdc8d8SChris Lattner         return rnb_err;
38630fdc8d8SChris Lattner 
38730fdc8d8SChris Lattner     DNBError err;
388*ee2ed525SGreg Clayton     ssize_t bytessent = write (m_fd, buffer, length);
38930fdc8d8SChris Lattner     if (bytessent < 0)
39030fdc8d8SChris Lattner         err.SetError(errno, DNBError::POSIX);
39130fdc8d8SChris Lattner 
39230fdc8d8SChris Lattner     if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
39343e0af06SGreg Clayton         err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i", m_fd, buffer, length, (uint64_t)bytessent);
39430fdc8d8SChris Lattner 
39530fdc8d8SChris Lattner     if (bytessent < 0)
39630fdc8d8SChris Lattner         return rnb_err;
39730fdc8d8SChris Lattner 
39830fdc8d8SChris Lattner     if (bytessent != length)
39930fdc8d8SChris Lattner         return rnb_err;
40030fdc8d8SChris Lattner 
401490fbbe2SGreg Clayton     DNBLogThreadedIf(LOG_RNB_PACKETS, "putpkt: %*s", (int)length, (char *)buffer);   // All data is string based in debugserver, so this is safe
402490fbbe2SGreg Clayton     DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer);
40330fdc8d8SChris Lattner 
40430fdc8d8SChris Lattner     return rnb_success;
40530fdc8d8SChris Lattner }
40630fdc8d8SChris Lattner 
40730fdc8d8SChris Lattner 
40830fdc8d8SChris Lattner rnb_err_t
40930fdc8d8SChris Lattner RNBSocket::ClosePort (int& fd, bool save_errno)
41030fdc8d8SChris Lattner {
41130fdc8d8SChris Lattner     int close_err = 0;
41230fdc8d8SChris Lattner     if (fd > 0)
41330fdc8d8SChris Lattner     {
41430fdc8d8SChris Lattner         errno = 0;
41530fdc8d8SChris Lattner         close_err = close (fd);
41630fdc8d8SChris Lattner         fd = -1;
41730fdc8d8SChris Lattner     }
41830fdc8d8SChris Lattner     return close_err != 0 ? rnb_err : rnb_success;
41930fdc8d8SChris Lattner }
42030fdc8d8SChris Lattner 
42130fdc8d8SChris Lattner 
422