13#define _DARWIN_UNLIMITED_SELECT
17#include "lldb/Host/Config.h"
39#include "llvm/Support/Errno.h"
40#include "llvm/Support/ErrorHandling.h"
42#include "llvm/ADT/SmallVector.h"
56 :
Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
58 m_child_processes_inherit(child_processes_inherit) {
60 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
61 static_cast<void *
>(
this));
65 :
Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
66 m_child_processes_inherit(false) {
72 "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = "
74 static_cast<void *
>(
this), fd, owns_fd);
79 :
Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
80 m_child_processes_inherit(false) {
86 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
87 static_cast<void *
>(
this));
100 "%p ConnectionFileDescriptor::OpenCommandPipe () - could not "
102 static_cast<void *
>(
this), result.
AsCString());
105 "%p ConnectionFileDescriptor::OpenCommandPipe() - success "
106 "readfd=%d writefd=%d",
114 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::CloseCommandPipe()",
115 static_cast<void *
>(
this));
127 path, [](llvm::StringRef) {}, error_ptr);
134 std::lock_guard<std::recursive_mutex> guard(
m_mutex);
136 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::Connect (url = '%s')",
137 static_cast<void *
>(
this), path.str().c_str());
147 llvm::StringRef scheme;
148 std::tie(scheme, path) = path.split(
"://");
155 .Cases(
"accept",
"unix-accept",
157 .Case(
"unix-abstract-accept",
159 .Cases(
"connect",
"tcp-connect",
163 .Case(
"unix-abstract-connect",
175 return (this->*method)(path, socket_id_callback, error_ptr);
186 size_t bytes_written = 0;
193 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::Disconnect ()",
194 static_cast<void *
>(
this));
200 log,
"%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
201 static_cast<void *
>(
this));
210 std::unique_lock<std::recursive_mutex> locker(
m_mutex, std::defer_lock);
211 if (!locker.try_lock()) {
213 size_t bytes_written = 0;
216 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get "
217 "the lock, sent 'q' to %d, error = '%s'.",
222 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get the "
223 "lock, but no command pipe is available.",
224 static_cast<void *
>(
this));
252 std::unique_lock<std::recursive_mutex> locker(
m_mutex, std::defer_lock);
253 if (!locker.try_lock()) {
255 "%p ConnectionFileDescriptor::Read () failed to get the "
257 static_cast<void *
>(
this));
259 error_ptr->
SetErrorString(
"failed to get the connection lock for read.");
277 size_t bytes_read = dst_len;
282 "%p ConnectionFileDescriptor::Read() fd = %" PRIu64
283 ", dst = %p, dst_len = %" PRIu64
") => %" PRIu64
", error = %s",
284 static_cast<void *
>(
this),
285 static_cast<uint64_t
>(
m_io_sp->GetWaitableHandle()),
286 static_cast<void *
>(dst),
static_cast<uint64_t
>(dst_len),
287 static_cast<uint64_t
>(bytes_read),
error.AsCString());
290 if (bytes_read == 0) {
300 uint32_t error_value =
error.GetError();
301 switch (error_value) {
344 LLDB_LOG(log,
"this = {0}, unexpected error: {1}",
this,
345 llvm::sys::StrError(error_value));
360 "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64
362 static_cast<void *
>(
this),
static_cast<const void *
>(src),
363 static_cast<uint64_t
>(src_len));
381 size_t bytes_sent = src_len;
386 "%p ConnectionFileDescriptor::Write(fd = %" PRIu64
387 ", src = %p, src_len = %" PRIu64
") => %" PRIu64
" (error = %s)",
388 static_cast<void *
>(
this),
389 static_cast<uint64_t
>(
m_io_sp->GetWaitableHandle()),
390 static_cast<const void *
>(src),
static_cast<uint64_t
>(src_len),
391 static_cast<uint64_t
>(bytes_sent),
error.AsCString());
398 switch (
error.GetError()) {
447 LLDB_LOG(log,
"this = {0}, timeout = {1}",
this, timeout);
466 const bool have_pipe_fd =
false;
468 const bool have_pipe_fd = pipe_fd >= 0;
473 while (handle ==
m_io_sp->GetWaitableHandle()) {
481 switch (
error.GetError()) {
511 llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1);
512 assert(bytes_read == 1);
517 "%p ConnectionFileDescriptor::BytesAvailable() "
518 "got data: %c from the command channel.",
519 static_cast<void *
>(
this), c);
537 llvm::function_ref<
void(
Socket &)> post_listen_callback,
540 std::unique_ptr<Socket> listening_socket =
545 error = listening_socket->Listen(socket_name, 5);
548 post_listen_callback(*listening_socket);
549 error = listening_socket->Accept(accepted_socket);
553 m_io_sp.reset(accepted_socket);
554 m_uri.assign(socket_name.str());
565 llvm::StringRef socket_name,
568 std::unique_ptr<Socket> socket =
572 error = socket->Connect(socket_name);
576 m_uri.assign(socket_name.str());
590 [socket_id_callback, socket_name](
Socket &listening_socket) {
591 socket_id_callback(socket_name);
607 [socket_id_callback, socket_name](
Socket &listening_socket) {
608 socket_id_callback(socket_name);
625 [socket_id_callback](
Socket &listening_socket) {
627 static_cast<TCPSocket &
>(listening_socket).GetLocalPortNumber();
628 socket_id_callback(std::to_string(port));
650 llvm::Expected<std::unique_ptr<UDPSocket>> socket =
654 *error_ptr = socket.takeError();
657 "tcp connect failed: {0}");
661 m_uri.assign(std::string(s));
674 if (!s.getAsInteger(0, fd)) {
679 int flags = ::fcntl(fd, F_GETFL, 0);
680 if (flags == -1 || errno == EBADF) {
695 std::unique_ptr<TCPSocket> tcp_socket;
696 tcp_socket = std::make_unique<TCPSocket>(fd,
false,
false);
701 !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
703 m_io_sp = std::move(tcp_socket);
718 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
725 std::string addr_str = s.str();
736 struct termios options;
737 ::tcgetattr(fd, &options);
740 ::cfsetospeed(&options, B115200);
741 ::cfsetispeed(&options, B115200);
744 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
747 options.c_cc[VMIN] = 1;
748 options.c_cc[VTIME] = 0;
750 llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW, &options);
756 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
763 llvm::StringRef path, qs;
765 std::tie(path, qs) = s.split(
'?');
767 llvm::Expected<SerialPort::Options> serial_options =
769 if (!serial_options) {
771 *error_ptr = serial_options.takeError();
773 llvm::consumeError(serial_options.takeError());
788 *error_ptr = serial_sp.takeError();
790 llvm::consumeError(serial_sp.takeError());
793 m_io_sp = std::move(serial_sp.get());
797 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
805 bool child_processes_inherit) {
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOGF(log,...)
#define LLDB_LOG_ERROR(log, error,...)
lldb_private::Status Select()
void FDSetRead(lldb::socket_t fd)
void SetTimeout(const std::chrono::microseconds &timeout)
bool FDIsSetRead(lldb::socket_t fd) const
bool GetChildProcessesInherit() const
lldb::ConnectionStatus AcceptTCP(llvm::StringRef host_and_port, socket_id_callback_type socket_id_callback, Status *error_ptr)
lldb::ConnectionStatus ConnectNamedSocket(llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, Status *error_ptr)
~ConnectionFileDescriptor() override
lldb::ConnectionStatus AcceptAbstractSocket(llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, Status *error_ptr)
lldb::ConnectionStatus ConnectUDP(llvm::StringRef args, socket_id_callback_type socket_id_callback, Status *error_ptr)
ConnectionFileDescriptor(bool child_processes_inherit=false)
lldb::ConnectionStatus ConnectSerialPort(llvm::StringRef args, socket_id_callback_type socket_id_callback, Status *error_ptr)
void SetChildProcessesInherit(bool child_processes_inherit)
bool m_child_processes_inherit
std::atomic< bool > m_shutting_down
bool InterruptRead() override
Interrupts an ongoing Read() operation.
lldb::ConnectionStatus Connect(llvm::StringRef url, Status *error_ptr) override
Connect using the connect string url.
bool IsConnected() const override
Check if the connection is valid.
void InitializeSocket(Socket *socket)
lldb::ConnectionStatus AcceptNamedSocket(llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, Status *error_ptr)
size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, Status *error_ptr) override
The actual write function that attempts to write to the communications protocol.
std::recursive_mutex m_mutex
lldb::ConnectionStatus AcceptSocket(Socket::SocketProtocol socket_protocol, llvm::StringRef socket_name, llvm::function_ref< void(Socket &)> post_listen_callback, Status *error_ptr)
lldb::ConnectionStatus ConnectFD(llvm::StringRef args, socket_id_callback_type socket_id_callback, Status *error_ptr)
lldb::ConnectionStatus ConnectAbstractSocket(llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, Status *error_ptr)
lldb::ConnectionStatus Disconnect(Status *error_ptr) override
Disconnect the communications connection if one is currently connected.
lldb::ConnectionStatus BytesAvailable(const Timeout< std::micro > &timeout, Status *error_ptr)
lldb::ConnectionStatus ConnectFile(llvm::StringRef args, socket_id_callback_type socket_id_callback, Status *error_ptr)
lldb::ConnectionStatus ConnectSocket(Socket::SocketProtocol socket_protocol, llvm::StringRef socket_name, Status *error_ptr)
std::string GetURI() override
Returns a URI that describes this connection object.
lldb::ConnectionStatus ConnectTCP(llvm::StringRef host_and_port, socket_id_callback_type socket_id_callback, Status *error_ptr)
size_t Read(void *dst, size_t dst_len, const Timeout< std::micro > &timeout, lldb::ConnectionStatus &status, Status *error_ptr) override
The read function that attempts to read from the connection.
llvm::function_ref< void(llvm::StringRef local_socket_id)> socket_id_callback_type
A communication connection class.
int Open(const char *path, int flags, int mode=0600)
Wraps ::open in a platform-independent way.
static FileSystem & Instance()
static const WaitableHandle kInvalidHandleValue
Status Write(const void *buf, size_t size, size_t &bytes_written)
int GetReadFileDescriptor() const override
bool CanWrite() const override
Status CreateNew(bool child_process_inherit) override
int GetWriteFileDescriptor() const override
static llvm::Expected< std::unique_ptr< SerialPort > > Create(int fd, OpenOptions options, Options serial_options, bool transfer_ownership)
static llvm::Expected< Options > OptionsFromURL(llvm::StringRef urlqs)
static llvm::Expected< std::unique_ptr< UDPSocket > > UdpConnect(llvm::StringRef host_and_port, bool child_processes_inherit)
virtual std::string GetRemoteConnectionURI() const
static std::unique_ptr< Socket > Create(const SocketProtocol protocol, bool child_processes_inherit, Status &error)
void SetErrorToErrno()
Set the current error to errno.
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
bool Success() const
Test for success condition.
std::string GetRemoteConnectionURI() const override
#define UNUSED_IF_ASSERT_DISABLED(x)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
ConnectionStatus
Connection Status Types.
@ eConnectionStatusError
Check GetError() for details.
@ eConnectionStatusInterrupted
Interrupted read.
@ eConnectionStatusTimedOut
Request timed out.
@ eConnectionStatusEndOfFile
End-of-file encountered.
@ eConnectionStatusSuccess
Success.
@ eConnectionStatusLostConnection
Lost connection while connected to a valid connection.
@ eConnectionStatusNoConnection
No connection.