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