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