13#define _DARWIN_UNLIMITED_SELECT
17#include "lldb/Host/Config.h"
38#include "llvm/Support/Errno.h"
39#include "llvm/Support/ErrorHandling.h"
41#include "llvm/ADT/SmallVector.h"
55 :
Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
57 m_child_processes_inherit(child_processes_inherit) {
59 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
60 static_cast<void *
>(
this));
64 :
Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
65 m_child_processes_inherit(false) {
71 "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = "
73 static_cast<void *
>(
this), fd, owns_fd);
78 :
Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
79 m_child_processes_inherit(false) {
85 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
86 static_cast<void *
>(
this));
99 "%p ConnectionFileDescriptor::OpenCommandPipe () - could not "
101 static_cast<void *
>(
this), result.
AsCString());
104 "%p ConnectionFileDescriptor::OpenCommandPipe() - success "
105 "readfd=%d writefd=%d",
106 static_cast<void *
>(
this),
m_pipe.GetReadFileDescriptor(),
107 m_pipe.GetWriteFileDescriptor());
113 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::CloseCommandPipe()",
114 static_cast<void *
>(
this));
126 path, [](llvm::StringRef) {}, error_ptr);
133 std::lock_guard<std::recursive_mutex> guard(
m_mutex);
135 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::Connect (url = '%s')",
136 static_cast<void *
>(
this), path.str().c_str());
146 llvm::StringRef scheme;
147 std::tie(scheme, path) = path.split(
"://");
154 .Cases(
"accept",
"unix-accept",
156 .Case(
"unix-abstract-accept",
158 .Cases(
"connect",
"tcp-connect",
162 .Case(
"unix-abstract-connect",
174 return (this->*method)(path, socket_id_callback, error_ptr);
185 size_t bytes_written = 0;
192 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::Disconnect ()",
193 static_cast<void *
>(
this));
199 log,
"%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
200 static_cast<void *
>(
this));
212 std::unique_lock<std::recursive_mutex> locker(
m_mutex, std::defer_lock);
213 if (!locker.try_lock()) {
215 size_t bytes_written = 0;
218 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get "
219 "the lock, sent 'q' to %d, error = '%s'.",
220 static_cast<void *
>(
this),
m_pipe.GetWriteFileDescriptor(),
224 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get the "
225 "lock, but no command pipe is available.",
226 static_cast<void *
>(
this));
254 std::unique_lock<std::recursive_mutex> locker(
m_mutex, std::defer_lock);
255 if (!locker.try_lock()) {
257 "%p ConnectionFileDescriptor::Read () failed to get the "
259 static_cast<void *
>(
this));
261 error_ptr->
SetErrorString(
"failed to get the connection lock for read.");
279 size_t bytes_read = dst_len;
284 "%p ConnectionFileDescriptor::Read() fd = %" PRIu64
285 ", dst = %p, dst_len = %" PRIu64
") => %" PRIu64
", error = %s",
286 static_cast<void *
>(
this),
287 static_cast<uint64_t
>(
m_io_sp->GetWaitableHandle()),
288 static_cast<void *
>(dst),
static_cast<uint64_t
>(dst_len),
289 static_cast<uint64_t
>(bytes_read),
error.AsCString());
292 if (bytes_read == 0) {
303 switch (error_value) {
346 LLDB_LOG(log,
"this = {0}, unexpected error: {1}",
this,
347 llvm::sys::StrError(error_value));
362 "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64
364 static_cast<void *
>(
this),
static_cast<const void *
>(src),
365 static_cast<uint64_t
>(src_len));
383 size_t bytes_sent = src_len;
388 "%p ConnectionFileDescriptor::Write(fd = %" PRIu64
389 ", src = %p, src_len = %" PRIu64
") => %" PRIu64
" (error = %s)",
390 static_cast<void *
>(
this),
391 static_cast<uint64_t
>(
m_io_sp->GetWaitableHandle()),
392 static_cast<const void *
>(src),
static_cast<uint64_t
>(src_len),
393 static_cast<uint64_t
>(bytes_sent),
error.AsCString());
400 switch (
error.GetError()) {
449 LLDB_LOG(log,
"this = {0}, timeout = {1}",
this, timeout);
455 const int pipe_fd =
m_pipe.GetReadFileDescriptor();
468 const bool have_pipe_fd =
false;
470 const bool have_pipe_fd = pipe_fd >= 0;
475 while (handle ==
m_io_sp->GetWaitableHandle()) {
483 switch (
error.GetError()) {
513 llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1);
514 assert(bytes_read == 1);
519 "%p ConnectionFileDescriptor::BytesAvailable() "
520 "got data: %c from the command channel.",
521 static_cast<void *
>(
this), c);
539 llvm::function_ref<
void(
Socket &)> post_listen_callback,
542 std::unique_ptr<Socket> listening_socket =
547 error = listening_socket->Listen(socket_name, 5);
550 post_listen_callback(*listening_socket);
551 error = listening_socket->Accept(accepted_socket);
555 m_io_sp.reset(accepted_socket);
556 m_uri.assign(socket_name.str());
567 llvm::StringRef socket_name,
570 std::unique_ptr<Socket> socket =
574 error = socket->Connect(socket_name);
578 m_uri.assign(socket_name.str());
592 [socket_id_callback, socket_name](
Socket &listening_socket) {
593 socket_id_callback(socket_name);
609 [socket_id_callback, socket_name](
Socket &listening_socket) {
610 socket_id_callback(socket_name);
627 [socket_id_callback](
Socket &listening_socket) {
629 static_cast<TCPSocket &
>(listening_socket).GetLocalPortNumber();
630 socket_id_callback(std::to_string(port));
652 llvm::Expected<std::unique_ptr<UDPSocket>> socket =
656 *error_ptr = socket.takeError();
659 "tcp connect failed: {0}");
663 m_uri.assign(std::string(s));
676 if (!s.getAsInteger(0, fd)) {
681 int flags = ::fcntl(fd, F_GETFL, 0);
682 if (flags == -1 || errno == EBADF) {
697 std::unique_ptr<TCPSocket> tcp_socket;
698 tcp_socket = std::make_unique<TCPSocket>(fd,
false,
false);
703 !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
705 m_io_sp = std::move(tcp_socket);
720 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
727 std::string addr_str = s.str();
729 int fd = llvm::sys::RetryAfterSignal(-1, ::open, addr_str.c_str(), O_RDWR);
738 struct termios options;
739 ::tcgetattr(fd, &options);
742 ::cfsetospeed(&options, B115200);
743 ::cfsetispeed(&options, B115200);
746 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
749 options.c_cc[VMIN] = 1;
750 options.c_cc[VTIME] = 0;
752 llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW, &options);
758 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
765 llvm::StringRef path, qs;
767 std::tie(path, qs) = s.split(
'?');
769 llvm::Expected<SerialPort::Options> serial_options =
771 if (!serial_options) {
773 *error_ptr = serial_options.takeError();
775 llvm::consumeError(serial_options.takeError());
779 int fd = llvm::sys::RetryAfterSignal(-1, ::open, path.str().c_str(), O_RDWR);
790 *error_ptr = serial_sp.takeError();
792 llvm::consumeError(serial_sp.takeError());
795 m_io_sp = std::move(serial_sp.get());
799 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
807 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.
static const WaitableHandle kInvalidHandleValue
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
virtual Status PreDisconnect()
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
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.