brintos

brintos / llvm-project-archived public Read only

0
0
Text · 27.0 KiB · b5831f0 Raw
798 lines · cpp
1//===-- ConnectionFileDescriptorPosix.cpp ---------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#if defined(__APPLE__)10// Enable this special support for Apple builds where we can have unlimited11// select bounds. We tried switching to poll() and kqueue and we were panicing12// the kernel, so we have to stick with select for now.13#define _DARWIN_UNLIMITED_SELECT14#endif15 16#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"17#include "lldb/Host/Config.h"18#include "lldb/Host/FileSystem.h"19#include "lldb/Host/Socket.h"20#include "lldb/Host/SocketAddress.h"21#include "lldb/Utility/LLDBLog.h"22#include "lldb/Utility/SelectHelper.h"23#include "lldb/Utility/Timeout.h"24 25#include <cerrno>26#include <cstdlib>27#include <cstring>28#include <fcntl.h>29#include <sys/types.h>30 31#if LLDB_ENABLE_POSIX32#include <termios.h>33#include <unistd.h>34#endif35 36#include <memory>37#include <sstream>38 39#include "llvm/Support/Errno.h"40#include "llvm/Support/ErrorHandling.h"41#if defined(__APPLE__)42#include "llvm/ADT/SmallVector.h"43#endif44#include "lldb/Host/Host.h"45#include "lldb/Host/Socket.h"46#include "lldb/Host/common/TCPSocket.h"47#include "lldb/Host/common/UDPSocket.h"48#include "lldb/Utility/Log.h"49#include "lldb/Utility/StreamString.h"50#include "lldb/Utility/Timer.h"51 52using namespace lldb;53using namespace lldb_private;54 55ConnectionFileDescriptor::ConnectionFileDescriptor()56    : Connection(), m_pipe(), m_mutex(), m_shutting_down(false) {57  Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object));58  LLDB_LOGF(log, "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",59            static_cast<void *>(this));60}61 62ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd)63    : Connection(), m_pipe(), m_mutex(), m_shutting_down(false) {64  m_io_sp =65      std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, owns_fd);66 67  Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object));68  LLDB_LOGF(log,69            "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = "70            "%i, owns_fd = %i)",71            static_cast<void *>(this), fd, owns_fd);72  OpenCommandPipe();73}74 75ConnectionFileDescriptor::ConnectionFileDescriptor(76    std::unique_ptr<Socket> socket_up)77    : m_shutting_down(false) {78  m_uri = socket_up->GetRemoteConnectionURI();79  m_io_sp = std::move(socket_up);80}81 82ConnectionFileDescriptor::~ConnectionFileDescriptor() {83  Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object));84  LLDB_LOGF(log, "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",85            static_cast<void *>(this));86  Disconnect(nullptr);87  CloseCommandPipe();88}89 90void ConnectionFileDescriptor::OpenCommandPipe() {91  CloseCommandPipe();92 93  Log *log = GetLog(LLDBLog::Connection);94  // Make the command file descriptor here:95  Status result = m_pipe.CreateNew();96  if (!result.Success()) {97    LLDB_LOGF(log,98              "%p ConnectionFileDescriptor::OpenCommandPipe () - could not "99              "make pipe: %s",100              static_cast<void *>(this), result.AsCString());101  } else {102    LLDB_LOGF(log,103              "%p ConnectionFileDescriptor::OpenCommandPipe() - success "104              "readfd=%d writefd=%d",105              static_cast<void *>(this), m_pipe.GetReadFileDescriptor(),106              m_pipe.GetWriteFileDescriptor());107  }108}109 110void ConnectionFileDescriptor::CloseCommandPipe() {111  Log *log = GetLog(LLDBLog::Connection);112  LLDB_LOGF(log, "%p ConnectionFileDescriptor::CloseCommandPipe()",113            static_cast<void *>(this));114 115  m_pipe.Close();116}117 118bool ConnectionFileDescriptor::IsConnected() const {119  return m_io_sp && m_io_sp->IsValid();120}121 122ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path,123                                                   Status *error_ptr) {124  return Connect(path, [](llvm::StringRef) {}, error_ptr);125}126 127ConnectionStatus128ConnectionFileDescriptor::Connect(llvm::StringRef path,129                                  socket_id_callback_type socket_id_callback,130                                  Status *error_ptr) {131  std::lock_guard<std::recursive_mutex> guard(m_mutex);132  Log *log = GetLog(LLDBLog::Connection);133  LLDB_LOGF(log, "%p ConnectionFileDescriptor::Connect (url = '%s')",134            static_cast<void *>(this), path.str().c_str());135 136  OpenCommandPipe();137 138  if (path.empty()) {139    if (error_ptr)140      *error_ptr = Status::FromErrorString("invalid connect arguments");141    return eConnectionStatusError;142  }143 144  llvm::StringRef scheme;145  std::tie(scheme, path) = path.split("://");146 147  if (!path.empty()) {148    auto method =149        llvm::StringSwitch<ConnectionStatus (ConnectionFileDescriptor::*)(150            llvm::StringRef, socket_id_callback_type, Status *)>(scheme)151            .Case("listen", &ConnectionFileDescriptor::AcceptTCP)152            .Cases({"accept", "unix-accept"},153                   &ConnectionFileDescriptor::AcceptNamedSocket)154            .Case("unix-abstract-accept",155                  &ConnectionFileDescriptor::AcceptAbstractSocket)156            .Cases({"connect", "tcp-connect"},157                   &ConnectionFileDescriptor::ConnectTCP)158            .Case("udp", &ConnectionFileDescriptor::ConnectUDP)159            .Case("unix-connect", &ConnectionFileDescriptor::ConnectNamedSocket)160            .Case("unix-abstract-connect",161                  &ConnectionFileDescriptor::ConnectAbstractSocket)162#if LLDB_ENABLE_POSIX163            .Case("fd", &ConnectionFileDescriptor::ConnectFD)164            .Case("file", &ConnectionFileDescriptor::ConnectFile)165            .Case("serial", &ConnectionFileDescriptor::ConnectSerialPort)166#endif167            .Default(nullptr);168 169    if (method) {170      if (error_ptr)171        *error_ptr = Status();172      return (this->*method)(path, socket_id_callback, error_ptr);173    }174  }175 176  if (error_ptr)177    *error_ptr = Status::FromErrorStringWithFormat(178        "unsupported connection URL: '%s'", path.str().c_str());179  return eConnectionStatusError;180}181 182bool ConnectionFileDescriptor::InterruptRead() {183  return !errorToBool(m_pipe.Write("i", 1).takeError());184}185 186ConnectionStatus ConnectionFileDescriptor::Disconnect(Status *error_ptr) {187  Log *log = GetLog(LLDBLog::Connection);188  LLDB_LOGF(log, "%p ConnectionFileDescriptor::Disconnect ()",189            static_cast<void *>(this));190 191  ConnectionStatus status = eConnectionStatusSuccess;192 193  if (!IsConnected()) {194    LLDB_LOGF(195        log, "%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",196        static_cast<void *>(this));197    return eConnectionStatusSuccess;198  }199 200  // Try to get the ConnectionFileDescriptor's mutex.  If we fail, that is201  // quite likely because somebody is doing a blocking read on our file202  // descriptor.  If that's the case, then send the "q" char to the command203  // file channel so the read will wake up and the connection will then know to204  // shut down.205  std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);206  if (!locker.try_lock()) {207    if (m_pipe.CanWrite()) {208      llvm::Error err = m_pipe.Write("q", 1).takeError();209      LLDB_LOG(log,210               "{0}: Couldn't get the lock, sent 'q' to {1}, error = '{2}'.",211               this, m_pipe.GetWriteFileDescriptor(), err);212      consumeError(std::move(err));213    } else if (log) {214      LLDB_LOGF(log,215                "%p ConnectionFileDescriptor::Disconnect(): Couldn't get the "216                "lock, but no command pipe is available.",217                static_cast<void *>(this));218    }219    locker.lock();220  }221 222  // Prevents reads and writes during shutdown.223  m_shutting_down = true;224 225  Status error = m_io_sp->Close();226  if (error.Fail())227    status = eConnectionStatusError;228  if (error_ptr)229    *error_ptr = std::move(error);230 231  // Close any pipes we were using for async interrupts232  m_pipe.Close();233 234  m_uri.clear();235  m_shutting_down = false;236  return status;237}238 239size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len,240                                      const Timeout<std::micro> &timeout,241                                      ConnectionStatus &status,242                                      Status *error_ptr) {243  Log *log = GetLog(LLDBLog::Connection);244 245  std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);246  if (!locker.try_lock()) {247    LLDB_LOGF(log,248              "%p ConnectionFileDescriptor::Read () failed to get the "249              "connection lock.",250              static_cast<void *>(this));251    if (error_ptr)252      *error_ptr = Status::FromErrorString(253          "failed to get the connection lock for read.");254 255    status = eConnectionStatusTimedOut;256    return 0;257  }258 259  if (m_shutting_down) {260    if (error_ptr)261      *error_ptr = Status::FromErrorString("shutting down");262    status = eConnectionStatusError;263    return 0;264  }265 266  status = BytesAvailable(timeout, error_ptr);267  if (status != eConnectionStatusSuccess)268    return 0;269 270  Status error;271  size_t bytes_read = dst_len;272  error = m_io_sp->Read(dst, bytes_read);273 274  if (log) {275    LLDB_LOG(log,276             "{0} ConnectionFileDescriptor::Read()  fd = {1}"277             ", dst = {2}, dst_len = {3}) => {4}, error = {5}",278             this, m_io_sp->GetWaitableHandle(), dst, dst_len, bytes_read,279             error.AsCString());280  }281 282  if (bytes_read == 0) {283    error.Clear(); // End-of-file.  Do not automatically close; pass along for284                   // the end-of-file handlers.285    status = eConnectionStatusEndOfFile;286  }287 288  if (error_ptr)289    *error_ptr = error.Clone();290 291  if (error.Fail()) {292    uint32_t error_value = error.GetError();293    switch (error_value) {294    case EAGAIN: // The file was marked for non-blocking I/O, and no data were295                 // ready to be read.296      if (m_io_sp->GetFdType() == IOObject::eFDTypeSocket)297        status = eConnectionStatusTimedOut;298      else299        status = eConnectionStatusSuccess;300      return 0;301 302    case EFAULT:  // Buf points outside the allocated address space.303    case EINTR:   // A read from a slow device was interrupted before any data304                  // arrived by the delivery of a signal.305    case EINVAL:  // The pointer associated with fildes was negative.306    case EIO:     // An I/O error occurred while reading from the file system.307                  // The process group is orphaned.308                  // The file is a regular file, nbyte is greater than 0, the309                  // starting position is before the end-of-file, and the310                  // starting position is greater than or equal to the offset311                  // maximum established for the open file descriptor312                  // associated with fildes.313    case EISDIR:  // An attempt is made to read a directory.314    case ENOBUFS: // An attempt to allocate a memory buffer fails.315    case ENOMEM:  // Insufficient memory is available.316      status = eConnectionStatusError;317      break; // Break to close....318 319    case ENOENT:     // no such file or directory320    case EBADF:      // fildes is not a valid file or socket descriptor open for321                     // reading.322    case ENXIO:      // An action is requested of a device that does not exist..323                     // A requested action cannot be performed by the device.324    case ECONNRESET: // The connection is closed by the peer during a read325                     // attempt on a socket.326    case ENOTCONN:   // A read is attempted on an unconnected socket.327      status = eConnectionStatusLostConnection;328      break; // Break to close....329 330    case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a331                    // socket.332      status = eConnectionStatusTimedOut;333      return 0;334 335    default:336      LLDB_LOG(log, "this = {0}, unexpected error: {1}", this,337               llvm::sys::StrError(error_value));338      status = eConnectionStatusError;339      break; // Break to close....340    }341 342    return 0;343  }344  return bytes_read;345}346 347size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len,348                                       ConnectionStatus &status,349                                       Status *error_ptr) {350  Log *log = GetLog(LLDBLog::Connection);351  LLDB_LOGF(log,352            "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64353            ")",354            static_cast<void *>(this), static_cast<const void *>(src),355            static_cast<uint64_t>(src_len));356 357  if (!IsConnected()) {358    if (error_ptr)359      *error_ptr = Status::FromErrorString("not connected");360    status = eConnectionStatusNoConnection;361    return 0;362  }363 364  if (m_shutting_down) {365    if (error_ptr)366      *error_ptr = Status::FromErrorString("shutting down");367    status = eConnectionStatusError;368    return 0;369  }370 371  Status error;372 373  size_t bytes_sent = src_len;374  error = m_io_sp->Write(src, bytes_sent);375 376  if (log) {377    LLDB_LOG(log,378             "{0} ConnectionFileDescriptor::Write(fd = {1}"379             ", src = {2}, src_len = {3}) => {4} (error = {5})",380             this, m_io_sp->GetWaitableHandle(), src, src_len, bytes_sent,381             error.AsCString());382  }383 384  if (error_ptr)385    *error_ptr = error.Clone();386 387  if (error.Fail()) {388    switch (error.GetError()) {389    case EAGAIN:390    case EINTR:391      status = eConnectionStatusSuccess;392      return 0;393 394    case ECONNRESET: // The connection is closed by the peer during a read395                     // attempt on a socket.396    case ENOTCONN:   // A read is attempted on an unconnected socket.397      status = eConnectionStatusLostConnection;398      break; // Break to close....399 400    default:401      status = eConnectionStatusError;402      break; // Break to close....403    }404 405    return 0;406  }407 408  status = eConnectionStatusSuccess;409  return bytes_sent;410}411 412std::string ConnectionFileDescriptor::GetURI() { return m_uri; }413 414// This ConnectionFileDescriptor::BytesAvailable() uses select() via415// SelectHelper416//417// PROS:418//  - select is consistent across most unix platforms419//  - The Apple specific version allows for unlimited fds in the fd_sets by420//    setting the _DARWIN_UNLIMITED_SELECT define prior to including the421//    required header files.422// CONS:423//  - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE.424//     This implementation  will assert if it runs into that hard limit to let425//     users know that another ConnectionFileDescriptor::BytesAvailable() should426//     be used or a new version of ConnectionFileDescriptor::BytesAvailable()427//     should be written for the system that is running into the limitations.428 429ConnectionStatus430ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,431                                         Status *error_ptr) {432  // Don't need to take the mutex here separately since we are only called from433  // Read.  If we ever get used more generally we will need to lock here as434  // well.435 436  Log *log = GetLog(LLDBLog::Connection);437  LLDB_LOG(log, "this = {0}, timeout = {1}", this, timeout);438 439  // Make a copy of the file descriptors to make sure we don't have another440  // thread change these values out from under us and cause problems in the441  // loop below where like in FS_SET()442  const IOObject::WaitableHandle handle = m_io_sp->GetWaitableHandle();443  const int pipe_fd = m_pipe.GetReadFileDescriptor();444 445  if (handle != IOObject::kInvalidHandleValue) {446    SelectHelper select_helper;447    if (timeout)448      select_helper.SetTimeout(*timeout);449 450    // FIXME: Migrate to MainLoop.451    select_helper.FDSetRead(reinterpret_cast<socket_t>(handle));452#if defined(_WIN32)453    // select() won't accept pipes on Windows.  The entire Windows codepath454    // needs to be converted over to using WaitForMultipleObjects and event455    // HANDLEs, but for now at least this will allow ::select() to not return456    // an error.457    const bool have_pipe_fd = false;458#else459    const bool have_pipe_fd = pipe_fd >= 0;460#endif461    if (have_pipe_fd)462      select_helper.FDSetRead(pipe_fd);463 464    while (handle == m_io_sp->GetWaitableHandle()) {465 466      Status error = select_helper.Select();467 468      if (error_ptr)469        *error_ptr = error.Clone();470 471      if (error.Fail()) {472        switch (error.GetError()) {473        case EBADF: // One of the descriptor sets specified an invalid474                    // descriptor.475          return eConnectionStatusLostConnection;476 477        case EINVAL: // The specified time limit is invalid. One of its478                     // components is negative or too large.479        default:     // Other unknown error480          return eConnectionStatusError;481 482        case ETIMEDOUT:483          return eConnectionStatusTimedOut;484 485        case EAGAIN: // The kernel was (perhaps temporarily) unable to486                     // allocate the requested number of file descriptors, or487                     // we have non-blocking IO488        case EINTR:  // A signal was delivered before the time limit489          // expired and before any of the selected events occurred.490          break; // Lets keep reading to until we timeout491        }492      } else {493        if (select_helper.FDIsSetRead((lldb::socket_t)handle))494          return eConnectionStatusSuccess;495 496        if (select_helper.FDIsSetRead(pipe_fd)) {497          // There is an interrupt or exit command in the command pipe Read the498          // data from that pipe:499          char c;500 501          ssize_t bytes_read =502              llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1);503          assert(bytes_read == 1);504          UNUSED_IF_ASSERT_DISABLED(bytes_read);505          switch (c) {506          case 'q':507            LLDB_LOGF(log,508                      "%p ConnectionFileDescriptor::BytesAvailable() "509                      "got data: %c from the command channel.",510                      static_cast<void *>(this), c);511            return eConnectionStatusEndOfFile;512          case 'i':513            // Interrupt the current read514            return eConnectionStatusInterrupted;515          }516        }517      }518    }519  }520 521  if (error_ptr)522    *error_ptr = Status::FromErrorString("not connected");523  return eConnectionStatusLostConnection;524}525 526lldb::ConnectionStatus ConnectionFileDescriptor::AcceptSocket(527    Socket::SocketProtocol socket_protocol, llvm::StringRef socket_name,528    llvm::function_ref<void(Socket &)> post_listen_callback,529    Status *error_ptr) {530  Status error;531  std::unique_ptr<Socket> listening_socket =532      Socket::Create(socket_protocol, error);533  Socket *accepted_socket;534 535  if (!error.Fail())536    error = listening_socket->Listen(socket_name, 5);537 538  if (!error.Fail()) {539    post_listen_callback(*listening_socket);540    error = listening_socket->Accept(/*timeout=*/std::nullopt, accepted_socket);541  }542 543  if (!error.Fail()) {544    m_io_sp.reset(accepted_socket);545    m_uri.assign(socket_name.str());546    return eConnectionStatusSuccess;547  }548 549  if (error_ptr)550    *error_ptr = error.Clone();551  return eConnectionStatusError;552}553 554lldb::ConnectionStatus555ConnectionFileDescriptor::ConnectSocket(Socket::SocketProtocol socket_protocol,556                                        llvm::StringRef socket_name,557                                        Status *error_ptr) {558  Status error;559  std::unique_ptr<Socket> socket = Socket::Create(socket_protocol, error);560 561  if (!error.Fail())562    error = socket->Connect(socket_name);563 564  if (!error.Fail()) {565    m_io_sp = std::move(socket);566    m_uri.assign(socket_name.str());567    return eConnectionStatusSuccess;568  }569 570  if (error_ptr)571    *error_ptr = error.Clone();572  return eConnectionStatusError;573}574 575ConnectionStatus ConnectionFileDescriptor::AcceptNamedSocket(576    llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,577    Status *error_ptr) {578  return AcceptSocket(579      Socket::ProtocolUnixDomain, socket_name,580      [socket_id_callback, socket_name](Socket &listening_socket) {581        socket_id_callback(socket_name);582      },583      error_ptr);584}585 586ConnectionStatus ConnectionFileDescriptor::ConnectNamedSocket(587    llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,588    Status *error_ptr) {589  return ConnectSocket(Socket::ProtocolUnixDomain, socket_name, error_ptr);590}591 592ConnectionStatus ConnectionFileDescriptor::AcceptAbstractSocket(593    llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,594    Status *error_ptr) {595  return AcceptSocket(596      Socket::ProtocolUnixAbstract, socket_name,597      [socket_id_callback, socket_name](Socket &listening_socket) {598        socket_id_callback(socket_name);599      },600      error_ptr);601}602 603lldb::ConnectionStatus ConnectionFileDescriptor::ConnectAbstractSocket(604    llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,605    Status *error_ptr) {606  return ConnectSocket(Socket::ProtocolUnixAbstract, socket_name, error_ptr);607}608 609ConnectionStatus610ConnectionFileDescriptor::AcceptTCP(llvm::StringRef socket_name,611                                    socket_id_callback_type socket_id_callback,612                                    Status *error_ptr) {613  ConnectionStatus ret = AcceptSocket(614      Socket::ProtocolTcp, socket_name,615      [socket_id_callback](Socket &listening_socket) {616        uint16_t port =617            static_cast<TCPSocket &>(listening_socket).GetLocalPortNumber();618        socket_id_callback(std::to_string(port));619      },620      error_ptr);621  if (ret == eConnectionStatusSuccess)622    m_uri.assign(623        static_cast<TCPSocket *>(m_io_sp.get())->GetRemoteConnectionURI());624  return ret;625}626 627ConnectionStatus628ConnectionFileDescriptor::ConnectTCP(llvm::StringRef socket_name,629                                     socket_id_callback_type socket_id_callback,630                                     Status *error_ptr) {631  return ConnectSocket(Socket::ProtocolTcp, socket_name, error_ptr);632}633 634ConnectionStatus635ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s,636                                     socket_id_callback_type socket_id_callback,637                                     Status *error_ptr) {638  if (error_ptr)639    *error_ptr = Status();640  llvm::Expected<std::unique_ptr<UDPSocket>> socket = Socket::UdpConnect(s);641  if (!socket) {642    if (error_ptr)643      *error_ptr = Status::FromError(socket.takeError());644    else645      LLDB_LOG_ERROR(GetLog(LLDBLog::Connection), socket.takeError(),646                     "tcp connect failed: {0}");647    return eConnectionStatusError;648  }649  m_io_sp = std::move(*socket);650  m_uri.assign(std::string(s));651  return eConnectionStatusSuccess;652}653 654ConnectionStatus655ConnectionFileDescriptor::ConnectFD(llvm::StringRef s,656                                    socket_id_callback_type socket_id_callback,657                                    Status *error_ptr) {658#if LLDB_ENABLE_POSIX659  // Just passing a native file descriptor within this current process that660  // is already opened (possibly from a service or other source).661  int fd = -1;662 663  if (!s.getAsInteger(0, fd)) {664    // We have what looks to be a valid file descriptor, but we should make665    // sure it is. We currently are doing this by trying to get the flags666    // from the file descriptor and making sure it isn't a bad fd.667    errno = 0;668    int flags = ::fcntl(fd, F_GETFL, 0);669    if (flags == -1 || errno == EBADF) {670      if (error_ptr)671        *error_ptr = Status::FromErrorStringWithFormat(672            "stale file descriptor: %s", s.str().c_str());673      m_io_sp.reset();674      return eConnectionStatusError;675    } else {676      // Don't take ownership of a file descriptor that gets passed to us677      // since someone else opened the file descriptor and handed it to us.678      // TODO: Since are using a URL to open connection we should679      // eventually parse options using the web standard where we have680      // "fd://123?opt1=value;opt2=value" and we can have an option be681      // "owns=1" or "owns=0" or something like this to allow us to specify682      // this. For now, we assume we must assume we don't own it.683 684      std::unique_ptr<TCPSocket> tcp_socket;685      tcp_socket = std::make_unique<TCPSocket>(fd, /*should_close=*/false);686      // Try and get a socket option from this file descriptor to see if687      // this is a socket and set m_is_socket accordingly.688      int resuse;689      bool is_socket =690          !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);691      if (is_socket)692        m_io_sp = std::move(tcp_socket);693      else694        m_io_sp =695            std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, false);696      m_uri = s.str();697      return eConnectionStatusSuccess;698    }699  }700 701  if (error_ptr)702    *error_ptr = Status::FromErrorStringWithFormat(703        "invalid file descriptor: \"%s\"", s.str().c_str());704  m_io_sp.reset();705  return eConnectionStatusError;706#endif // LLDB_ENABLE_POSIX707  llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");708}709 710ConnectionStatus ConnectionFileDescriptor::ConnectFile(711    llvm::StringRef s, socket_id_callback_type socket_id_callback,712    Status *error_ptr) {713#if LLDB_ENABLE_POSIX714  std::string addr_str = s.str();715  // file:///PATH716  int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR);717  if (fd == -1) {718    if (error_ptr)719      *error_ptr = Status::FromErrno();720    return eConnectionStatusError;721  }722 723  if (::isatty(fd)) {724    // Set up serial terminal emulation725    struct termios options;726    ::tcgetattr(fd, &options);727 728    // Set port speed to the available maximum729#ifdef B115200730    ::cfsetospeed(&options, B115200);731    ::cfsetispeed(&options, B115200);732#elif B57600733    ::cfsetospeed(&options, B57600);734    ::cfsetispeed(&options, B57600);735#elif B38400736    ::cfsetospeed(&options, B38400);737    ::cfsetispeed(&options, B38400);738#else739#error "Maximum Baud rate is Unknown"740#endif741 742    // Raw input, disable echo and signals743    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);744 745    // Make sure only one character is needed to return from a read746    options.c_cc[VMIN] = 1;747    options.c_cc[VTIME] = 0;748 749    llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW, &options);750  }751 752  m_io_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, true);753  return eConnectionStatusSuccess;754#endif // LLDB_ENABLE_POSIX755  llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");756}757 758ConnectionStatus ConnectionFileDescriptor::ConnectSerialPort(759    llvm::StringRef s, socket_id_callback_type socket_id_callback,760    Status *error_ptr) {761#if LLDB_ENABLE_POSIX762  llvm::StringRef path, qs;763  // serial:///PATH?k1=v1&k2=v2...764  std::tie(path, qs) = s.split('?');765 766  llvm::Expected<SerialPort::Options> serial_options =767      SerialPort::OptionsFromURL(qs);768  if (!serial_options) {769    if (error_ptr)770      *error_ptr = Status::FromError(serial_options.takeError());771    else772      llvm::consumeError(serial_options.takeError());773    return eConnectionStatusError;774  }775 776  int fd = FileSystem::Instance().Open(path.str().c_str(), O_RDWR);777  if (fd == -1) {778    if (error_ptr)779      *error_ptr = Status::FromErrno();780    return eConnectionStatusError;781  }782 783  llvm::Expected<std::unique_ptr<SerialPort>> serial_sp = SerialPort::Create(784      fd, File::eOpenOptionReadWrite, serial_options.get(), true);785  if (!serial_sp) {786    if (error_ptr)787      *error_ptr = Status::FromError(serial_sp.takeError());788    else789      llvm::consumeError(serial_sp.takeError());790    return eConnectionStatusError;791  }792  m_io_sp = std::move(serial_sp.get());793 794  return eConnectionStatusSuccess;795#endif // LLDB_ENABLE_POSIX796  llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");797}798