124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//                     The LLVM Compiler Infrastructure
424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// This file is distributed under the University of Illinois Open Source
624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// License. See LICENSE.TXT for details.
724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//===----------------------------------------------------------------------===//
924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
1024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//  Created by Greg Clayton on 12/12/07.
1124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
1224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//===----------------------------------------------------------------------===//
1324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
1424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "RNBSocket.h"
15ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton#include <arpa/inet.h>
1624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <errno.h>
1724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <fcntl.h>
18ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton#include <netdb.h>
1924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <netinet/in.h>
2024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <netinet/tcp.h>
2124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <termios.h>
2224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "DNBLog.h"
2324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "DNBError.h"
2424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
259a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda#ifdef WITH_LOCKDOWN
2624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "lockdown.h"
2724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#endif
2824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
2924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner/* Once we have a RNBSocket object with a port # specified,
3024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner   this function is called to wait for an incoming connection.
3124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner   This function blocks while waiting for that connection.  */
3224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
33a619e8ec81ff9c838285105c034ee70a290be904Greg Claytonbool
34a619e8ec81ff9c838285105c034ee70a290be904Greg ClaytonResolveIPV4HostName (const char *hostname, in_addr_t &addr)
35a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton{
36a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    if (hostname == NULL ||
37a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        hostname[0] == '\0' ||
38a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        strcmp(hostname, "localhost") == 0 ||
39a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        strcmp(hostname, "127.0.0.1") == 0)
40a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    {
41a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        addr = htonl (INADDR_LOOPBACK);
42a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        return true;
43a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    }
44a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    else if (strcmp(hostname, "*") == 0)
45a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    {
46a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        addr = htonl (INADDR_ANY);
47a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        return true;
48a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    }
49a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    else
50a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    {
51a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        // See if an IP address was specified as numbers
52a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        int inet_pton_result = ::inet_pton (AF_INET, hostname, &addr);
53a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
54a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        if (inet_pton_result == 1)
55a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            return true;
56a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
57a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        struct hostent *host_entry = gethostbyname (hostname);
58a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        if (host_entry)
59a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        {
60a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            std::string ip_str (::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list));
61a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            inet_pton_result = ::inet_pton (AF_INET, ip_str.c_str(), &addr);
62a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            if (inet_pton_result == 1)
63a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                return true;
64a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        }
65a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    }
66a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    return false;
67a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton}
68a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
6924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerrnb_err_t
70a619e8ec81ff9c838285105c034ee70a290be904Greg ClaytonRNBSocket::Listen (const char *listen_host, in_port_t port, PortBoundCallback callback, const void *callback_baton)
7124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
7224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
7324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Disconnect without saving errno
7424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    Disconnect (false);
7524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
76a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    // Now figure out the hostname that will be attaching and palce it into
77a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    struct sockaddr_in listen_addr;
78a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    ::memset (&listen_addr, 0, sizeof listen_addr);
79a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    listen_addr.sin_len = sizeof listen_addr;
80a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    listen_addr.sin_family = AF_INET;
81a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    listen_addr.sin_port = htons (port);
82a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    listen_addr.sin_addr.s_addr = INADDR_ANY;
83a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
84a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    if (!ResolveIPV4HostName(listen_host, listen_addr.sin_addr.s_addr))
85a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    {
86a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        DNBLogThreaded("error: failed to resolve connecting host '%s'", listen_host);
87a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        return rnb_err;
88a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    }
89a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
9024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    DNBError err;
91b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    int listen_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
92b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    if (listen_fd == -1)
9324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        err.SetError(errno, DNBError::POSIX);
9424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
9524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
96b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_fd);
9724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
9824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail())
9924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
10024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
10124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // enable local address reuse
102b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1);
10324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
10424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    struct sockaddr_in sa;
10524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    ::memset (&sa, 0, sizeof sa);
10624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    sa.sin_len = sizeof sa;
10724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    sa.sin_family = AF_INET;
108b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    sa.sin_port = htons (port);
109a619e8ec81ff9c838285105c034ee70a290be904Greg 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)
110b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    int error = ::bind (listen_fd, (struct sockaddr *) &sa, sizeof(sa));
11124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (error == -1)
11224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        err.SetError(errno, DNBError::POSIX);
11324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
11424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
115b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_fd);
11624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
11724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail())
11824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
119b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        ClosePort (listen_fd, false);
12024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
12124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
12224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
123b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    if (callback && port == 0)
124b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    {
125b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        // We were asked to listen on port zero which means we
126b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        // must now read the actual port that was given to us
127b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        // as port zero is a special code for "find an open port
128b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        // for me".
129b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        socklen_t sa_len = sizeof (sa);
130b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0)
131b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        {
132b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton            port = ntohs (sa.sin_port);
133b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton            callback (callback_baton, port);
134b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        }
135b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    }
136b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton
137a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    error = ::listen (listen_fd, 5);
13824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (error == -1)
13924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        err.SetError(errno, DNBError::POSIX);
14024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
14124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
142b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd);
14324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
14424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail())
14524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
146b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        ClosePort (listen_fd, false);
14724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
14824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
14924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
150a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    struct sockaddr_in accept_addr;
151a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    ::memset (&accept_addr, 0, sizeof accept_addr);
152a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    accept_addr.sin_len = sizeof accept_addr;
15324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
154a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    bool accept_connection = false;
155a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
156a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    // Loop until we are happy with our connection
157a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    while (!accept_connection)
158a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    {
159a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        socklen_t accept_addr_len = sizeof accept_addr;
160a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        m_fd = ::accept (listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len);
161a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
162a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        if (m_fd == -1)
163a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            err.SetError(errno, DNBError::POSIX);
164a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
165a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
166a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            err.LogThreaded("::accept ( socket = %i, address = %p, address_len = %u )", listen_fd, &accept_addr, accept_addr_len);
167a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
168a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        if (err.Fail())
169a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            break;
170a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton
171a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        if (listen_addr.sin_addr.s_addr == INADDR_ANY)
172a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            accept_connection = true;
173a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        else
174a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        {
175a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            if (accept_addr_len == listen_addr.sin_len &&
176a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                accept_addr.sin_addr.s_addr == listen_addr.sin_addr.s_addr)
177a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            {
178a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                accept_connection = true;
179a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            }
180a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            else
181a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            {
182a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                ::close (m_fd);
183a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                m_fd = -1;
184a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
185a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sin_addr.s_addr;
186a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                ::fprintf (stderr,
187a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                           "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n",
188a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                           accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
189a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                           listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
190a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                DNBLogThreaded ("error: rejecting connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)",
191a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                                accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
192a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton                                listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
193a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton            }
194a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        }
195a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    }
196b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton
197b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    ClosePort (listen_fd, false);
19824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
19924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail())
20024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
20124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
20224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
20324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    else
20424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
20524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        // Keep our TCP packets coming without any delays.
206b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
20724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
20824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
20924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return rnb_success;
21024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
21124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
212ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Claytonrnb_err_t
213ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg ClaytonRNBSocket::Connect (const char *host, uint16_t port)
214ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton{
215ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    Disconnect (false);
216ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton
217ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    // Create the socket
218b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
219b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    if (m_fd == -1)
220ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton        return rnb_err;
221ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton
222ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    // Enable local address reuse
223b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
224ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton
225ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    struct sockaddr_in sa;
226ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    ::memset (&sa, 0, sizeof (sa));
227ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    sa.sin_family = AF_INET;
228ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    sa.sin_port = htons (port);
229ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton
230a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton    if (!ResolveIPV4HostName(host, sa.sin_addr.s_addr))
231ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    {
232a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        DNBLogThreaded("error: failed to resolve host '%s'", host);
233a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        Disconnect (false);
234a619e8ec81ff9c838285105c034ee70a290be904Greg Clayton        return rnb_err;
235ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    }
236ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton
237b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa)))
238ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    {
239ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton        Disconnect (false);
240ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton        return rnb_err;
241ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    }
242ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton
243ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    // Keep our TCP packets coming without any delays.
244b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
245ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton    return rnb_success;
246ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton}
247ff39f746ebaa3710c44ba49bd9b0a6cf05f60a3fGreg Clayton
2489a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molendarnb_err_t
2499a5bbd2a14cacac731424f7a253f6cc16b22c10aJason MolendaRNBSocket::useFD(int fd)
2509a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda{
2519a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda       if (fd < 0) {
2529a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda               DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in.");
2539a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda               return rnb_err;
2549a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda       }
2559a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda
2569a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda       m_fd = fd;
2579a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda       return rnb_success;
2589a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda}
2599a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda
2609a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda#ifdef WITH_LOCKDOWN
26124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerrnb_err_t
26224943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerRNBSocket::ConnectToService()
26324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
26424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
26524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Disconnect from any previous connections
26624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    Disconnect(false);
2677d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda    if (::secure_lockdown_checkin (&m_ld_conn, NULL, NULL) != kLDESuccess)
26824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
2697d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda        DNBLogThreadedIf(LOG_RNB_COMM, "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed");
27070eddebd1c5868a87a3ba9ddf717fc964a257f66Jason Molenda        m_fd = -1;
27124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_not_connected;
27224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
2737d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda    m_fd = ::lockdown_get_socket (m_ld_conn);
2747d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda    if (m_fd == -1)
2757d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda    {
2767d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda        DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed");
2777d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda        return rnb_not_connected;
2787d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda    }
279b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    m_fd_from_lockdown = true;
28024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return rnb_success;
28124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
28224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#endif
28324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
28424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerrnb_err_t
28524943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerRNBSocket::OpenFile (const char *path)
28624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
28724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    DNBError err;
288b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    m_fd = open (path, O_RDWR);
289b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    if (m_fd == -1)
29024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
29124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        err.SetError(errno, DNBError::POSIX);
29224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        err.LogThreaded ("can't open file '%s'", path);
29324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_not_connected;
29424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
29524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    else
29624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
29724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        struct termios stdin_termios;
29824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
299b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        if (::tcgetattr (m_fd, &stdin_termios) == 0)
30024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
30124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            stdin_termios.c_lflag &= ~ECHO;     // Turn off echoing
30224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            stdin_termios.c_lflag &= ~ICANON;   // Get one char at a time
303b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton            ::tcsetattr (m_fd, TCSANOW, &stdin_termios);
30424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
30524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
30624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return rnb_success;
30724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
30824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
30924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerint
31024943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerRNBSocket::SetSocketOption(int fd, int level, int option_name, int option_value)
31124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
31224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
31324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
31424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
31524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerrnb_err_t
31624943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerRNBSocket::Disconnect (bool save_errno)
31724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
3189a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda#ifdef WITH_LOCKDOWN
319b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    if (m_fd_from_lockdown)
3207d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda    {
321b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        m_fd_from_lockdown = false;
3227d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda        m_fd = -1;
3233138ad6178b98337ea875e30e7c808e35eae734dJim Ingham        lockdown_disconnect (m_ld_conn);
3243138ad6178b98337ea875e30e7c808e35eae734dJim Ingham        return rnb_success;
3257d96ecc2fe57d7d7289bed7fc633154a310979c7Jason Molenda    }
3269a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda#endif
327b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    return ClosePort (m_fd, save_errno);
32824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
32924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
33024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
33124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerrnb_err_t
33224943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerRNBSocket::Read (std::string &p)
33324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
33424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    char buf[1024];
33524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    p.clear();
33624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
33724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Note that BUF is on the stack so we must be careful to keep any
33824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // writes to BUF from overflowing or we'll have security issues.
33924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
340b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    if (m_fd == -1)
34124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
34224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
34324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
34424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    DNBError err;
345b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    int bytesread = read (m_fd, buf, sizeof (buf));
34624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (bytesread <= 0)
34724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        err.SetError(errno, DNBError::POSIX);
34824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    else
34924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        p.append(buf, bytesread);
35024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
35124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
352851e30ec6a1b1d2c154bb7d69ed0d05b5fd14705Greg Clayton        err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof (buf), (uint64_t)bytesread);
35324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
35424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Our port went away - we have to mark this so IsConnected will return the truth.
35524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (bytesread == 0)
35624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
357b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        m_fd = -1;
35824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_not_connected;
35924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
36024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    else if (bytesread == -1)
36124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
362b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton        m_fd = -1;
36324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
36424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
36524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Strip spaces from the end of the buffer
36624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    while (!p.empty() && isspace (p[p.size() - 1]))
36724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        p.erase (p.size () - 1);
36824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
36924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Most data in the debugserver packets valid printable characters...
37024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
37124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return rnb_success;
37224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
37324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
37424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerrnb_err_t
37524943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerRNBSocket::Write (const void *buffer, size_t length)
37624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
377b72d0f098e45936fa72e26b1a026c603e17e2d6cGreg Clayton    if (m_fd == -1)
37824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
37924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
38024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    DNBError err;
3819a5bbd2a14cacac731424f7a253f6cc16b22c10aJason Molenda    int bytessent = write (m_fd, buffer, length);
38224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (bytessent < 0)
38324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        err.SetError(errno, DNBError::POSIX);
38424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
38524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
386851e30ec6a1b1d2c154bb7d69ed0d05b5fd14705Greg Clayton        err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i", m_fd, buffer, length, (uint64_t)bytessent);
38724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
38824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (bytessent < 0)
38924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
39024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
39124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (bytessent != length)
39224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return rnb_err;
39324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
3940e8147bd867e4cdaae9400f56d02c7aacd40a9b3Greg Clayton    DNBLogThreadedIf(LOG_RNB_PACKETS, "putpkt: %*s", (int)length, (char *)buffer);   // All data is string based in debugserver, so this is safe
3950e8147bd867e4cdaae9400f56d02c7aacd40a9b3Greg Clayton    DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer);
39624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
39724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return rnb_success;
39824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
39924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
40024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
40124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerrnb_err_t
40224943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerRNBSocket::ClosePort (int& fd, bool save_errno)
40324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
40424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    int close_err = 0;
40524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (fd > 0)
40624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
40724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        errno = 0;
40824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        close_err = close (fd);
40924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        fd = -1;
41024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
41124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return close_err != 0 ? rnb_err : rnb_success;
41224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
41324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
41424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
415