RNBSocket.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
1deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
2deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//
3deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//                     The LLVM Compiler Infrastructure
4deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//
5deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve// This file is distributed under the University of Illinois Open Source
6deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve// License. See LICENSE.TXT for details.
7deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//
8deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//===----------------------------------------------------------------------===//
9deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//
10deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//  Created by Greg Clayton on 12/12/07.
11deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//
12deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve//===----------------------------------------------------------------------===//
13deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
14deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include "RNBSocket.h"
15deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include <errno.h>
16deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include <fcntl.h>
17deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include <netinet/in.h>
18deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include <netinet/tcp.h>
19deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include <termios.h>
20deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include "DNBLog.h"
21deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include "DNBError.h"
22deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
23deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#if defined (__arm__)
24deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include "lockdown.h"
25deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#endif
26deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
27deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve/* Once we have a RNBSocket object with a port # specified,
28deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve   this function is called to wait for an incoming connection.
29deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve   This function blocks while waiting for that connection.  */
30deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
31deb9654056939a12981446f6ed1139dca3412746Vikram S. Advernb_err_t
32deb9654056939a12981446f6ed1139dca3412746Vikram S. AdveRNBSocket::Listen (in_port_t listen_port_num)
33deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve{
34deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
35deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    // Disconnect without saving errno
36deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    Disconnect (false);
37deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
38deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    DNBError err;
39deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
40deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    if (listen_port == -1)
41deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve        err.SetError(errno, DNBError::POSIX);
42deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
43deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
44deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve        err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_port);
45deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
46deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    if (err.Fail())
47deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve        return rnb_err;
48deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
49deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    // enable local address reuse
50deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1);
51deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
52deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    struct sockaddr_in sa;
53deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    ::memset (&sa, 0, sizeof sa);
54deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    sa.sin_len = sizeof sa;
55deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    sa.sin_family = AF_INET;
56deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    sa.sin_port = htons (listen_port_num);
57deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    sa.sin_addr.s_addr = htonl (INADDR_ANY);
58deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
59deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    int error = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa));
60deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    if (error == -1)
61deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve        err.SetError(errno, DNBError::POSIX);
62deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
63deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
64deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve        err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_port);
65deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
66deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    if (err.Fail())
67deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    {
68deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve        ClosePort (listen_port, false);
69deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve        return rnb_err;
70deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    }
71deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve
72deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    error = ::listen (listen_port, 1);
73deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve    if (error == -1)
74deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve        err.SetError(errno, DNBError::POSIX);
75
76    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
77        err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_port);
78
79    if (err.Fail())
80    {
81        ClosePort (listen_port, false);
82        return rnb_err;
83    }
84
85    m_conn_port = ::accept (listen_port, NULL, 0);
86    if (m_conn_port == -1)
87        err.SetError(errno, DNBError::POSIX);
88
89    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
90        err.LogThreaded("::accept ( socket = %i, address = NULL, address_len = 0 )", listen_port);
91
92    if (err.Fail())
93    {
94        ClosePort (listen_port, false);
95        return rnb_err;
96    }
97    else
98    {
99        // We are done with the listen port
100        ClosePort (listen_port, false);
101
102        // Keep our TCP packets coming without any delays.
103        SetSocketOption (m_conn_port, IPPROTO_TCP, TCP_NODELAY, 1);
104    }
105
106    return rnb_success;
107}
108
109#if defined (__arm__)
110rnb_err_t
111RNBSocket::ConnectToService()
112{
113    DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
114    // Disconnect from any previous connections
115    Disconnect(false);
116
117    m_conn_port = ::lockdown_checkin (NULL, NULL);
118    if (m_conn_port == -1)
119    {
120        DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_checkin(NULL, NULL) failed");
121        return rnb_not_connected;
122    }
123    m_conn_port_from_lockdown = true;
124    return rnb_success;
125}
126#endif
127
128rnb_err_t
129RNBSocket::OpenFile (const char *path)
130{
131    DNBError err;
132    m_conn_port = open (path, O_RDWR);
133    if (m_conn_port == -1)
134    {
135        err.SetError(errno, DNBError::POSIX);
136        err.LogThreaded ("can't open file '%s'", path);
137        return rnb_not_connected;
138    }
139    else
140    {
141        struct termios stdin_termios;
142
143        if (::tcgetattr (m_conn_port, &stdin_termios) == 0)
144        {
145            stdin_termios.c_lflag &= ~ECHO;     // Turn off echoing
146            stdin_termios.c_lflag &= ~ICANON;   // Get one char at a time
147            ::tcsetattr (m_conn_port, TCSANOW, &stdin_termios);
148        }
149    }
150    return rnb_success;
151}
152
153int
154RNBSocket::SetSocketOption(int fd, int level, int option_name, int option_value)
155{
156    return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
157}
158
159rnb_err_t
160RNBSocket::Disconnect (bool save_errno)
161{
162    if (m_conn_port_from_lockdown)
163        m_conn_port_from_lockdown = false;
164    return ClosePort (m_conn_port, save_errno);
165}
166
167
168rnb_err_t
169RNBSocket::Read (std::string &p)
170{
171    char buf[1024];
172    p.clear();
173
174    // Note that BUF is on the stack so we must be careful to keep any
175    // writes to BUF from overflowing or we'll have security issues.
176
177    if (m_conn_port == -1)
178        return rnb_err;
179
180    //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
181    DNBError err;
182    int bytesread = read (m_conn_port, buf, sizeof (buf));
183    if (bytesread <= 0)
184        err.SetError(errno, DNBError::POSIX);
185    else
186        p.append(buf, bytesread);
187
188    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
189        err.LogThreaded("::read ( %i, %p, %zu ) => %i", m_conn_port, buf, sizeof (buf), bytesread);
190
191    // Our port went away - we have to mark this so IsConnected will return the truth.
192    if (bytesread == 0)
193    {
194        m_conn_port = -1;
195        return rnb_not_connected;
196    }
197    else if (bytesread == -1)
198    {
199        m_conn_port = -1;
200        return rnb_err;
201    }
202    // Strip spaces from the end of the buffer
203    while (!p.empty() && isspace (p[p.size() - 1]))
204        p.erase (p.size () - 1);
205
206    // Most data in the debugserver packets valid printable characters...
207    DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
208    return rnb_success;
209}
210
211rnb_err_t
212RNBSocket::Write (const void *buffer, size_t length)
213{
214    if (m_conn_port == -1)
215        return rnb_err;
216
217    DNBError err;
218    int bytessent = send (m_conn_port, buffer, length, 0);
219    if (bytessent < 0)
220        err.SetError(errno, DNBError::POSIX);
221
222    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
223        err.LogThreaded("::send ( socket = %i, buffer = %p, length = %zu, flags = 0 ) => %i", m_conn_port, buffer, length, bytessent);
224
225    if (bytessent < 0)
226        return rnb_err;
227
228    if (bytessent != length)
229        return rnb_err;
230
231    DNBLogThreadedIf(LOG_RNB_PACKETS, "putpkt: %*s", length, (char *)buffer);   // All data is string based in debugserver, so this is safe
232    DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", length, (char *)buffer);
233
234    return rnb_success;
235}
236
237
238rnb_err_t
239RNBSocket::ClosePort (int& fd, bool save_errno)
240{
241    int close_err = 0;
242    if (fd > 0)
243    {
244        errno = 0;
245        close_err = close (fd);
246        fd = -1;
247    }
248    return close_err != 0 ? rnb_err : rnb_success;
249}
250
251
252