diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 18:01:57 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 18:01:57 +0000 |
commit | 88c643b6fec27eec436c8d138fee6346e92337d6 (patch) | |
tree | 82cd13b2f3cde1c9e5f79689ba4e6ba67694843f /tools/debugserver/source/RNBSocket.cpp | |
parent | 94994d372d014ce4c8758b9605d63fae651bd8aa (diff) |
Notes
Diffstat (limited to 'tools/debugserver/source/RNBSocket.cpp')
-rw-r--r-- | tools/debugserver/source/RNBSocket.cpp | 392 |
1 files changed, 0 insertions, 392 deletions
diff --git a/tools/debugserver/source/RNBSocket.cpp b/tools/debugserver/source/RNBSocket.cpp deleted file mode 100644 index 88136c210acc..000000000000 --- a/tools/debugserver/source/RNBSocket.cpp +++ /dev/null @@ -1,392 +0,0 @@ -//===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 12/12/07. -// -//===----------------------------------------------------------------------===// - -#include "RNBSocket.h" -#include "DNBError.h" -#include "DNBLog.h" -#include <arpa/inet.h> -#include <errno.h> -#include <fcntl.h> -#include <map> -#include <netdb.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <sys/event.h> -#include <termios.h> -#include <vector> - -#include "lldb/Host/SocketAddress.h" - -#ifdef WITH_LOCKDOWN -#include "lockdown.h" -#endif - -/* Once we have a RNBSocket object with a port # specified, - this function is called to wait for an incoming connection. - This function blocks while waiting for that connection. */ - -bool ResolveIPV4HostName(const char *hostname, in_addr_t &addr) { - if (hostname == NULL || hostname[0] == '\0' || - strcmp(hostname, "localhost") == 0 || - strcmp(hostname, "127.0.0.1") == 0) { - addr = htonl(INADDR_LOOPBACK); - return true; - } else if (strcmp(hostname, "*") == 0) { - addr = htonl(INADDR_ANY); - return true; - } else { - // See if an IP address was specified as numbers - int inet_pton_result = ::inet_pton(AF_INET, hostname, &addr); - - if (inet_pton_result == 1) - return true; - - struct hostent *host_entry = gethostbyname(hostname); - if (host_entry) { - std::string ip_str( - ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list)); - inet_pton_result = ::inet_pton(AF_INET, ip_str.c_str(), &addr); - if (inet_pton_result == 1) - return true; - } - } - return false; -} - -rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port, - PortBoundCallback callback, - const void *callback_baton) { - // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", - // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); - // Disconnect without saving errno - Disconnect(false); - - DNBError err; - int queue_id = kqueue(); - if (queue_id < 0) { - err.SetError(errno, DNBError::MachKernel); - err.LogThreaded("error: failed to create kqueue."); - return rnb_err; - } - - bool any_addr = (strcmp(listen_host, "*") == 0); - - // If the user wants to allow connections from any address we should create - // sockets on all families that can resolve localhost. This will allow us to - // listen for IPv6 and IPv4 connections from all addresses if those interfaces - // are available. - const char *local_addr = any_addr ? "localhost" : listen_host; - - std::map<int, lldb_private::SocketAddress> sockets; - auto addresses = lldb_private::SocketAddress::GetAddressInfo( - local_addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); - - for (auto address : addresses) { - int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP); - if (sock_fd == -1) - continue; - - SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1); - - lldb_private::SocketAddress bind_address = address; - - if(any_addr || !bind_address.IsLocalhost()) - bind_address.SetToAnyAddress(bind_address.GetFamily(), port); - else - bind_address.SetPort(port); - - int error = - ::bind(sock_fd, &bind_address.sockaddr(), bind_address.GetLength()); - if (error == -1) { - ClosePort(sock_fd, false); - continue; - } - - error = ::listen(sock_fd, 5); - if (error == -1) { - ClosePort(sock_fd, false); - continue; - } - - // We were asked to listen on port zero which means we must now read the - // actual port that was given to us as port zero is a special code for "find - // an open port for me". This will only execute on the first socket created, - // subesquent sockets will reuse this port number. - if (port == 0) { - socklen_t sa_len = address.GetLength(); - if (getsockname(sock_fd, &address.sockaddr(), &sa_len) == 0) - port = address.GetPort(); - } - - sockets[sock_fd] = address; - } - - if (sockets.size() == 0) { - err.SetError(errno, DNBError::POSIX); - err.LogThreaded("::listen or ::bind failed"); - return rnb_err; - } - - if (callback) - callback(callback_baton, port); - - std::vector<struct kevent> events; - events.resize(sockets.size()); - int i = 0; - for (auto socket : sockets) { - EV_SET(&events[i++], socket.first, EVFILT_READ, EV_ADD, 0, 0, 0); - } - - bool accept_connection = false; - - // Loop until we are happy with our connection - while (!accept_connection) { - - struct kevent event_list[4]; - int num_events = - kevent(queue_id, events.data(), events.size(), event_list, 4, NULL); - - if (num_events < 0) { - err.SetError(errno, DNBError::MachKernel); - err.LogThreaded("error: kevent() failed."); - } - - for (int i = 0; i < num_events; ++i) { - auto sock_fd = event_list[i].ident; - auto socket_pair = sockets.find(sock_fd); - if (socket_pair == sockets.end()) - continue; - - lldb_private::SocketAddress &addr_in = socket_pair->second; - lldb_private::SocketAddress accept_addr; - socklen_t sa_len = accept_addr.GetMaxLength(); - m_fd = ::accept(sock_fd, &accept_addr.sockaddr(), &sa_len); - - if (m_fd == -1) { - err.SetError(errno, DNBError::POSIX); - err.LogThreaded("error: Socket accept failed."); - } - - if (addr_in.IsAnyAddr()) - accept_connection = true; - else { - if (accept_addr == addr_in) - accept_connection = true; - else { - ::close(m_fd); - m_fd = -1; - ::fprintf( - stderr, - "error: rejecting incoming connection from %s (expecting %s)\n", - accept_addr.GetIPAddress().c_str(), - addr_in.GetIPAddress().c_str()); - DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n", - accept_addr.GetIPAddress().c_str(), - addr_in.GetIPAddress().c_str()); - err.Clear(); - } - } - } - if (err.Fail()) - break; - } - for (auto socket : sockets) { - int ListenFd = socket.first; - ClosePort(ListenFd, false); - } - - if (err.Fail()) - return rnb_err; - - // Keep our TCP packets coming without any delays. - SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1); - - return rnb_success; -} - -rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) { - auto result = rnb_err; - Disconnect(false); - - auto addresses = lldb_private::SocketAddress::GetAddressInfo( - host, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); - - for (auto address : addresses) { - m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP); - if (m_fd == -1) - continue; - - // Enable local address reuse - SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1); - - address.SetPort(port); - - if (-1 == ::connect(m_fd, &address.sockaddr(), address.GetLength())) { - Disconnect(false); - continue; - } - SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1); - - result = rnb_success; - break; - } - return result; -} - -rnb_err_t RNBSocket::useFD(int fd) { - if (fd < 0) { - DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in."); - return rnb_err; - } - - m_fd = fd; - return rnb_success; -} - -#ifdef WITH_LOCKDOWN -rnb_err_t RNBSocket::ConnectToService() { - DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME); - // Disconnect from any previous connections - Disconnect(false); - if (::secure_lockdown_checkin(&m_ld_conn, NULL, NULL) != kLDESuccess) { - DNBLogThreadedIf(LOG_RNB_COMM, - "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed"); - m_fd = -1; - return rnb_not_connected; - } - m_fd = ::lockdown_get_socket(m_ld_conn); - if (m_fd == -1) { - DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed"); - return rnb_not_connected; - } - m_fd_from_lockdown = true; - return rnb_success; -} -#endif - -rnb_err_t RNBSocket::OpenFile(const char *path) { - DNBError err; - m_fd = open(path, O_RDWR); - if (m_fd == -1) { - err.SetError(errno, DNBError::POSIX); - err.LogThreaded("can't open file '%s'", path); - return rnb_not_connected; - } else { - struct termios stdin_termios; - - if (::tcgetattr(m_fd, &stdin_termios) == 0) { - stdin_termios.c_lflag &= ~ECHO; // Turn off echoing - stdin_termios.c_lflag &= ~ICANON; // Get one char at a time - ::tcsetattr(m_fd, TCSANOW, &stdin_termios); - } - } - return rnb_success; -} - -int RNBSocket::SetSocketOption(int fd, int level, int option_name, - int option_value) { - return ::setsockopt(fd, level, option_name, &option_value, - sizeof(option_value)); -} - -rnb_err_t RNBSocket::Disconnect(bool save_errno) { -#ifdef WITH_LOCKDOWN - if (m_fd_from_lockdown) { - m_fd_from_lockdown = false; - m_fd = -1; - lockdown_disconnect(m_ld_conn); - return rnb_success; - } -#endif - return ClosePort(m_fd, save_errno); -} - -rnb_err_t RNBSocket::Read(std::string &p) { - char buf[1024]; - p.clear(); - - // Note that BUF is on the stack so we must be careful to keep any - // writes to BUF from overflowing or we'll have security issues. - - if (m_fd == -1) - return rnb_err; - - // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", - // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); - DNBError err; - ssize_t bytesread = read(m_fd, buf, sizeof(buf)); - if (bytesread <= 0) - err.SetError(errno, DNBError::POSIX); - else - p.append(buf, bytesread); - - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof(buf), - (uint64_t)bytesread); - - // Our port went away - we have to mark this so IsConnected will return the - // truth. - if (bytesread == 0) { - m_fd = -1; - return rnb_not_connected; - } else if (bytesread == -1) { - m_fd = -1; - return rnb_err; - } - // Strip spaces from the end of the buffer - while (!p.empty() && isspace(p[p.size() - 1])) - p.erase(p.size() - 1); - - // Most data in the debugserver packets valid printable characters... - DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str()); - return rnb_success; -} - -rnb_err_t RNBSocket::Write(const void *buffer, size_t length) { - if (m_fd == -1) - return rnb_err; - - DNBError err; - ssize_t bytessent = write(m_fd, buffer, length); - if (bytessent < 0) - err.SetError(errno, DNBError::POSIX); - - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i", - m_fd, buffer, length, (uint64_t)bytessent); - - if (bytessent < 0) - return rnb_err; - - if ((size_t)bytessent != length) - return rnb_err; - - DNBLogThreadedIf( - LOG_RNB_PACKETS, "putpkt: %*s", (int)length, - (const char *) - buffer); // All data is string based in debugserver, so this is safe - DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, - (const char *)buffer); - - return rnb_success; -} - -rnb_err_t RNBSocket::ClosePort(int &fd, bool save_errno) { - int close_err = 0; - if (fd > 0) { - errno = 0; - close_err = close(fd); - fd = -1; - } - return close_err != 0 ? rnb_err : rnb_success; -} |