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 3330fdc8d8SChris Lattner rnb_err_t 348b82f087SGreg Clayton RNBSocket::Listen (in_port_t port, PortBoundCallback callback, const void *callback_baton) 3530fdc8d8SChris Lattner { 3630fdc8d8SChris Lattner //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); 3730fdc8d8SChris Lattner // Disconnect without saving errno 3830fdc8d8SChris Lattner Disconnect (false); 3930fdc8d8SChris Lattner 4030fdc8d8SChris Lattner DNBError err; 418b82f087SGreg Clayton int listen_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 428b82f087SGreg Clayton if (listen_fd == -1) 4330fdc8d8SChris Lattner err.SetError(errno, DNBError::POSIX); 4430fdc8d8SChris Lattner 4530fdc8d8SChris Lattner if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) 468b82f087SGreg Clayton err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_fd); 4730fdc8d8SChris Lattner 4830fdc8d8SChris Lattner if (err.Fail()) 4930fdc8d8SChris Lattner return rnb_err; 5030fdc8d8SChris Lattner 5130fdc8d8SChris Lattner // enable local address reuse 528b82f087SGreg Clayton SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1); 5330fdc8d8SChris Lattner 5430fdc8d8SChris Lattner struct sockaddr_in sa; 5530fdc8d8SChris Lattner ::memset (&sa, 0, sizeof sa); 5630fdc8d8SChris Lattner sa.sin_len = sizeof sa; 5730fdc8d8SChris Lattner sa.sin_family = AF_INET; 588b82f087SGreg Clayton sa.sin_port = htons (port); 5930fdc8d8SChris Lattner sa.sin_addr.s_addr = htonl (INADDR_ANY); 6030fdc8d8SChris Lattner 618b82f087SGreg Clayton int error = ::bind (listen_fd, (struct sockaddr *) &sa, sizeof(sa)); 6230fdc8d8SChris Lattner if (error == -1) 6330fdc8d8SChris Lattner err.SetError(errno, DNBError::POSIX); 6430fdc8d8SChris Lattner 6530fdc8d8SChris Lattner if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) 668b82f087SGreg Clayton err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_fd); 6730fdc8d8SChris Lattner 6830fdc8d8SChris Lattner if (err.Fail()) 6930fdc8d8SChris Lattner { 708b82f087SGreg Clayton ClosePort (listen_fd, false); 7130fdc8d8SChris Lattner return rnb_err; 7230fdc8d8SChris Lattner } 7330fdc8d8SChris Lattner 748b82f087SGreg Clayton if (callback && port == 0) 758b82f087SGreg Clayton { 768b82f087SGreg Clayton // We were asked to listen on port zero which means we 778b82f087SGreg Clayton // must now read the actual port that was given to us 788b82f087SGreg Clayton // as port zero is a special code for "find an open port 798b82f087SGreg Clayton // for me". 808b82f087SGreg Clayton socklen_t sa_len = sizeof (sa); 818b82f087SGreg Clayton if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0) 828b82f087SGreg Clayton { 838b82f087SGreg Clayton port = ntohs (sa.sin_port); 848b82f087SGreg Clayton callback (callback_baton, port); 858b82f087SGreg Clayton } 868b82f087SGreg Clayton } 878b82f087SGreg Clayton 888b82f087SGreg Clayton error = ::listen (listen_fd, 1); 8930fdc8d8SChris Lattner if (error == -1) 9030fdc8d8SChris Lattner err.SetError(errno, DNBError::POSIX); 9130fdc8d8SChris Lattner 9230fdc8d8SChris Lattner if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) 938b82f087SGreg Clayton err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd); 9430fdc8d8SChris Lattner 9530fdc8d8SChris Lattner if (err.Fail()) 9630fdc8d8SChris Lattner { 978b82f087SGreg Clayton ClosePort (listen_fd, false); 9830fdc8d8SChris Lattner return rnb_err; 9930fdc8d8SChris Lattner } 10030fdc8d8SChris Lattner 1018b82f087SGreg Clayton m_fd = ::accept (listen_fd, NULL, 0); 1028b82f087SGreg Clayton if (m_fd == -1) 10330fdc8d8SChris Lattner err.SetError(errno, DNBError::POSIX); 10430fdc8d8SChris Lattner 10530fdc8d8SChris Lattner if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) 1068b82f087SGreg Clayton err.LogThreaded("::accept ( socket = %i, address = NULL, address_len = 0 )", listen_fd); 1078b82f087SGreg Clayton 1088b82f087SGreg Clayton ClosePort (listen_fd, false); 10930fdc8d8SChris Lattner 11030fdc8d8SChris Lattner if (err.Fail()) 11130fdc8d8SChris Lattner { 11230fdc8d8SChris Lattner return rnb_err; 11330fdc8d8SChris Lattner } 11430fdc8d8SChris Lattner else 11530fdc8d8SChris Lattner { 11630fdc8d8SChris Lattner // Keep our TCP packets coming without any delays. 1178b82f087SGreg Clayton SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); 11830fdc8d8SChris Lattner } 11930fdc8d8SChris Lattner 12030fdc8d8SChris Lattner return rnb_success; 12130fdc8d8SChris Lattner } 12230fdc8d8SChris Lattner 12395bf0fd3SGreg Clayton rnb_err_t 12495bf0fd3SGreg Clayton RNBSocket::Connect (const char *host, uint16_t port) 12595bf0fd3SGreg Clayton { 12695bf0fd3SGreg Clayton Disconnect (false); 12795bf0fd3SGreg Clayton 12895bf0fd3SGreg Clayton // Create the socket 1298b82f087SGreg Clayton m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 1308b82f087SGreg Clayton if (m_fd == -1) 13195bf0fd3SGreg Clayton return rnb_err; 13295bf0fd3SGreg Clayton 13395bf0fd3SGreg Clayton // Enable local address reuse 1348b82f087SGreg Clayton SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1); 13595bf0fd3SGreg Clayton 13695bf0fd3SGreg Clayton struct sockaddr_in sa; 13795bf0fd3SGreg Clayton ::memset (&sa, 0, sizeof (sa)); 13895bf0fd3SGreg Clayton sa.sin_family = AF_INET; 13995bf0fd3SGreg Clayton sa.sin_port = htons (port); 14095bf0fd3SGreg Clayton 14195bf0fd3SGreg Clayton if (host == NULL) 14295bf0fd3SGreg Clayton host = "localhost"; 14395bf0fd3SGreg Clayton 14495bf0fd3SGreg Clayton int inet_pton_result = ::inet_pton (AF_INET, host, &sa.sin_addr); 14595bf0fd3SGreg Clayton 14695bf0fd3SGreg Clayton if (inet_pton_result <= 0) 14795bf0fd3SGreg Clayton { 14895bf0fd3SGreg Clayton struct hostent *host_entry = gethostbyname (host); 14995bf0fd3SGreg Clayton if (host_entry) 15095bf0fd3SGreg Clayton { 15195bf0fd3SGreg Clayton std::string host_str (::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list)); 15295bf0fd3SGreg Clayton inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); 15395bf0fd3SGreg Clayton if (inet_pton_result <= 0) 15495bf0fd3SGreg Clayton { 15595bf0fd3SGreg Clayton Disconnect (false); 15695bf0fd3SGreg Clayton return rnb_err; 15795bf0fd3SGreg Clayton } 15895bf0fd3SGreg Clayton } 15995bf0fd3SGreg Clayton } 16095bf0fd3SGreg Clayton 1618b82f087SGreg Clayton if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa))) 16295bf0fd3SGreg Clayton { 16395bf0fd3SGreg Clayton Disconnect (false); 16495bf0fd3SGreg Clayton return rnb_err; 16595bf0fd3SGreg Clayton } 16695bf0fd3SGreg Clayton 16795bf0fd3SGreg Clayton // Keep our TCP packets coming without any delays. 1688b82f087SGreg Clayton SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); 16995bf0fd3SGreg Clayton return rnb_success; 17095bf0fd3SGreg Clayton } 17195bf0fd3SGreg Clayton 17242999a48SJason Molenda rnb_err_t 17342999a48SJason Molenda RNBSocket::useFD(int fd) 17442999a48SJason Molenda { 17542999a48SJason Molenda if (fd < 0) { 17642999a48SJason Molenda DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in."); 17742999a48SJason Molenda return rnb_err; 17842999a48SJason Molenda } 17942999a48SJason Molenda 18042999a48SJason Molenda m_fd = fd; 18142999a48SJason Molenda return rnb_success; 18242999a48SJason Molenda } 18342999a48SJason Molenda 18442999a48SJason Molenda #ifdef WITH_LOCKDOWN 18530fdc8d8SChris Lattner rnb_err_t 18630fdc8d8SChris Lattner RNBSocket::ConnectToService() 18730fdc8d8SChris Lattner { 18830fdc8d8SChris Lattner DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME); 18930fdc8d8SChris Lattner // Disconnect from any previous connections 19030fdc8d8SChris Lattner Disconnect(false); 19130fdc8d8SChris Lattner 19294379541SJason Molenda if (::lockdown_secure_checkin (&m_fd, NULL, NULL, NULL) != kLDESuccess) 19330fdc8d8SChris Lattner { 19494379541SJason Molenda DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_secure_checkin(&m_fd, NULL, NULL, NULL) failed"); 19594379541SJason Molenda m_fd = -1; 19630fdc8d8SChris Lattner return rnb_not_connected; 19730fdc8d8SChris Lattner } 1988b82f087SGreg Clayton m_fd_from_lockdown = true; 19930fdc8d8SChris Lattner return rnb_success; 20030fdc8d8SChris Lattner } 20130fdc8d8SChris Lattner #endif 20230fdc8d8SChris Lattner 20330fdc8d8SChris Lattner rnb_err_t 20430fdc8d8SChris Lattner RNBSocket::OpenFile (const char *path) 20530fdc8d8SChris Lattner { 20630fdc8d8SChris Lattner DNBError err; 2078b82f087SGreg Clayton m_fd = open (path, O_RDWR); 2088b82f087SGreg Clayton if (m_fd == -1) 20930fdc8d8SChris Lattner { 21030fdc8d8SChris Lattner err.SetError(errno, DNBError::POSIX); 21130fdc8d8SChris Lattner err.LogThreaded ("can't open file '%s'", path); 21230fdc8d8SChris Lattner return rnb_not_connected; 21330fdc8d8SChris Lattner } 21430fdc8d8SChris Lattner else 21530fdc8d8SChris Lattner { 21630fdc8d8SChris Lattner struct termios stdin_termios; 21730fdc8d8SChris Lattner 2188b82f087SGreg Clayton if (::tcgetattr (m_fd, &stdin_termios) == 0) 21930fdc8d8SChris Lattner { 22030fdc8d8SChris Lattner stdin_termios.c_lflag &= ~ECHO; // Turn off echoing 22130fdc8d8SChris Lattner stdin_termios.c_lflag &= ~ICANON; // Get one char at a time 2228b82f087SGreg Clayton ::tcsetattr (m_fd, TCSANOW, &stdin_termios); 22330fdc8d8SChris Lattner } 22430fdc8d8SChris Lattner } 22530fdc8d8SChris Lattner return rnb_success; 22630fdc8d8SChris Lattner } 22730fdc8d8SChris Lattner 22830fdc8d8SChris Lattner int 22930fdc8d8SChris Lattner RNBSocket::SetSocketOption(int fd, int level, int option_name, int option_value) 23030fdc8d8SChris Lattner { 23130fdc8d8SChris Lattner return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value)); 23230fdc8d8SChris Lattner } 23330fdc8d8SChris Lattner 23430fdc8d8SChris Lattner rnb_err_t 23530fdc8d8SChris Lattner RNBSocket::Disconnect (bool save_errno) 23630fdc8d8SChris Lattner { 23742999a48SJason Molenda #ifdef WITH_LOCKDOWN 2388b82f087SGreg Clayton if (m_fd_from_lockdown) 2398b82f087SGreg Clayton m_fd_from_lockdown = false; 24042999a48SJason Molenda #endif 2418b82f087SGreg Clayton return ClosePort (m_fd, save_errno); 24230fdc8d8SChris Lattner } 24330fdc8d8SChris Lattner 24430fdc8d8SChris Lattner 24530fdc8d8SChris Lattner rnb_err_t 24630fdc8d8SChris Lattner RNBSocket::Read (std::string &p) 24730fdc8d8SChris Lattner { 24830fdc8d8SChris Lattner char buf[1024]; 24930fdc8d8SChris Lattner p.clear(); 25030fdc8d8SChris Lattner 25130fdc8d8SChris Lattner // Note that BUF is on the stack so we must be careful to keep any 25230fdc8d8SChris Lattner // writes to BUF from overflowing or we'll have security issues. 25330fdc8d8SChris Lattner 2548b82f087SGreg Clayton if (m_fd == -1) 25530fdc8d8SChris Lattner return rnb_err; 25630fdc8d8SChris Lattner 25730fdc8d8SChris Lattner //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); 25830fdc8d8SChris Lattner DNBError err; 2598b82f087SGreg Clayton int bytesread = read (m_fd, buf, sizeof (buf)); 26030fdc8d8SChris Lattner if (bytesread <= 0) 26130fdc8d8SChris Lattner err.SetError(errno, DNBError::POSIX); 26230fdc8d8SChris Lattner else 26330fdc8d8SChris Lattner p.append(buf, bytesread); 26430fdc8d8SChris Lattner 26530fdc8d8SChris Lattner if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) 266*43e0af06SGreg Clayton err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof (buf), (uint64_t)bytesread); 26730fdc8d8SChris Lattner 26830fdc8d8SChris Lattner // Our port went away - we have to mark this so IsConnected will return the truth. 26930fdc8d8SChris Lattner if (bytesread == 0) 27030fdc8d8SChris Lattner { 2718b82f087SGreg Clayton m_fd = -1; 27230fdc8d8SChris Lattner return rnb_not_connected; 27330fdc8d8SChris Lattner } 27430fdc8d8SChris Lattner else if (bytesread == -1) 27530fdc8d8SChris Lattner { 2768b82f087SGreg Clayton m_fd = -1; 27730fdc8d8SChris Lattner return rnb_err; 27830fdc8d8SChris Lattner } 27930fdc8d8SChris Lattner // Strip spaces from the end of the buffer 28030fdc8d8SChris Lattner while (!p.empty() && isspace (p[p.size() - 1])) 28130fdc8d8SChris Lattner p.erase (p.size () - 1); 28230fdc8d8SChris Lattner 28330fdc8d8SChris Lattner // Most data in the debugserver packets valid printable characters... 28430fdc8d8SChris Lattner DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str()); 28530fdc8d8SChris Lattner return rnb_success; 28630fdc8d8SChris Lattner } 28730fdc8d8SChris Lattner 28830fdc8d8SChris Lattner rnb_err_t 28930fdc8d8SChris Lattner RNBSocket::Write (const void *buffer, size_t length) 29030fdc8d8SChris Lattner { 2918b82f087SGreg Clayton if (m_fd == -1) 29230fdc8d8SChris Lattner return rnb_err; 29330fdc8d8SChris Lattner 29430fdc8d8SChris Lattner DNBError err; 29542999a48SJason Molenda int bytessent = write (m_fd, buffer, length); 29630fdc8d8SChris Lattner if (bytessent < 0) 29730fdc8d8SChris Lattner err.SetError(errno, DNBError::POSIX); 29830fdc8d8SChris Lattner 29930fdc8d8SChris Lattner if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) 300*43e0af06SGreg Clayton err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i", m_fd, buffer, length, (uint64_t)bytessent); 30130fdc8d8SChris Lattner 30230fdc8d8SChris Lattner if (bytessent < 0) 30330fdc8d8SChris Lattner return rnb_err; 30430fdc8d8SChris Lattner 30530fdc8d8SChris Lattner if (bytessent != length) 30630fdc8d8SChris Lattner return rnb_err; 30730fdc8d8SChris Lattner 308490fbbe2SGreg Clayton DNBLogThreadedIf(LOG_RNB_PACKETS, "putpkt: %*s", (int)length, (char *)buffer); // All data is string based in debugserver, so this is safe 309490fbbe2SGreg Clayton DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer); 31030fdc8d8SChris Lattner 31130fdc8d8SChris Lattner return rnb_success; 31230fdc8d8SChris Lattner } 31330fdc8d8SChris Lattner 31430fdc8d8SChris Lattner 31530fdc8d8SChris Lattner rnb_err_t 31630fdc8d8SChris Lattner RNBSocket::ClosePort (int& fd, bool save_errno) 31730fdc8d8SChris Lattner { 31830fdc8d8SChris Lattner int close_err = 0; 31930fdc8d8SChris Lattner if (fd > 0) 32030fdc8d8SChris Lattner { 32130fdc8d8SChris Lattner errno = 0; 32230fdc8d8SChris Lattner close_err = close (fd); 32330fdc8d8SChris Lattner fd = -1; 32430fdc8d8SChris Lattner } 32530fdc8d8SChris Lattner return close_err != 0 ? rnb_err : rnb_success; 32630fdc8d8SChris Lattner } 32730fdc8d8SChris Lattner 32830fdc8d8SChris Lattner 329