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 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
59 static_cast<void *
>(
this));
63 :
Connection(), m_pipe(), m_mutex(), m_shutting_down(false) {
69 "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = "
71 static_cast<void *
>(
this), fd, owns_fd);
76 :
Connection(), m_pipe(), m_mutex(), m_shutting_down(false) {
82 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
83 static_cast<void *
>(
this));
96 "%p ConnectionFileDescriptor::OpenCommandPipe () - could not "
98 static_cast<void *
>(
this), result.
AsCString());
101 "%p ConnectionFileDescriptor::OpenCommandPipe() - success "
102 "readfd=%d writefd=%d",
110 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::CloseCommandPipe()",
111 static_cast<void *
>(
this));
123 path, [](llvm::StringRef) {}, error_ptr);
130 std::lock_guard<std::recursive_mutex> guard(
m_mutex);
132 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::Connect (url = '%s')",
133 static_cast<void *
>(
this), path.str().c_str());
143 llvm::StringRef scheme;
144 std::tie(scheme, path) = path.split(
"://");
151 .Cases(
"accept",
"unix-accept",
153 .Case(
"unix-abstract-accept",
155 .Cases(
"connect",
"tcp-connect",
159 .Case(
"unix-abstract-connect",
171 return (this->*method)(path, socket_id_callback, error_ptr);
177 "unsupported connection URL: '%s'", path.str().c_str());
182 size_t bytes_written = 0;
189 LLDB_LOGF(log,
"%p ConnectionFileDescriptor::Disconnect ()",
190 static_cast<void *
>(
this));
196 log,
"%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
197 static_cast<void *
>(
this));
206 std::unique_lock<std::recursive_mutex> locker(
m_mutex, std::defer_lock);
207 if (!locker.try_lock()) {
209 size_t bytes_written = 0;
212 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get "
213 "the lock, sent 'q' to %d, error = '%s'.",
218 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get the "
219 "lock, but no command pipe is available.",
220 static_cast<void *
>(
this));
232 *error_ptr = std::move(
error);
248 std::unique_lock<std::recursive_mutex> locker(
m_mutex, std::defer_lock);
249 if (!locker.try_lock()) {
251 "%p ConnectionFileDescriptor::Read () failed to get the "
253 static_cast<void *
>(
this));
256 "failed to get the connection lock for read.");
274 size_t bytes_read = dst_len;
279 "%p ConnectionFileDescriptor::Read() fd = %" PRIu64
280 ", dst = %p, dst_len = %" PRIu64
") => %" PRIu64
", error = %s",
281 static_cast<void *
>(
this),
282 static_cast<uint64_t
>(
m_io_sp->GetWaitableHandle()),
283 static_cast<void *
>(dst),
static_cast<uint64_t
>(dst_len),
284 static_cast<uint64_t
>(bytes_read),
error.AsCString());
287 if (bytes_read == 0) {
294 *error_ptr =
error.Clone();
297 uint32_t error_value =
error.GetError();
298 switch (error_value) {
341 LLDB_LOG(log,
"this = {0}, unexpected error: {1}",
this,
342 llvm::sys::StrError(error_value));
357 "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64
359 static_cast<void *
>(
this),
static_cast<const void *
>(src),
360 static_cast<uint64_t
>(src_len));
378 size_t bytes_sent = src_len;
383 "%p ConnectionFileDescriptor::Write(fd = %" PRIu64
384 ", src = %p, src_len = %" PRIu64
") => %" PRIu64
" (error = %s)",
385 static_cast<void *
>(
this),
386 static_cast<uint64_t
>(
m_io_sp->GetWaitableHandle()),
387 static_cast<const void *
>(src),
static_cast<uint64_t
>(src_len),
388 static_cast<uint64_t
>(bytes_sent),
error.AsCString());
392 *error_ptr =
error.Clone();
395 switch (
error.GetError()) {
444 LLDB_LOG(log,
"this = {0}, timeout = {1}",
this, timeout);
463 const bool have_pipe_fd =
false;
465 const bool have_pipe_fd = pipe_fd >= 0;
470 while (handle ==
m_io_sp->GetWaitableHandle()) {
475 *error_ptr =
error.Clone();
478 switch (
error.GetError()) {
508 llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1);
509 assert(bytes_read == 1);
514 "%p ConnectionFileDescriptor::BytesAvailable() "
515 "got data: %c from the command channel.",
516 static_cast<void *
>(
this), c);
534 llvm::function_ref<
void(
Socket &)> post_listen_callback,
537 std::unique_ptr<Socket> listening_socket =
542 error = listening_socket->Listen(socket_name, 5);
545 post_listen_callback(*listening_socket);
546 error = listening_socket->Accept(std::nullopt, accepted_socket);
550 m_io_sp.reset(accepted_socket);
551 m_uri.assign(socket_name.str());
556 *error_ptr =
error.Clone();
562 llvm::StringRef socket_name,
568 error = socket->Connect(socket_name);
572 m_uri.assign(socket_name.str());
577 *error_ptr =
error.Clone();
586 [socket_id_callback, socket_name](
Socket &listening_socket) {
587 socket_id_callback(socket_name);
603 [socket_id_callback, socket_name](
Socket &listening_socket) {
604 socket_id_callback(socket_name);
621 [socket_id_callback](
Socket &listening_socket) {
623 static_cast<TCPSocket &
>(listening_socket).GetLocalPortNumber();
624 socket_id_callback(std::to_string(port));
652 "tcp connect failed: {0}");
656 m_uri.assign(std::string(s));
669 if (!s.getAsInteger(0, fd)) {
674 int flags = ::fcntl(fd, F_GETFL, 0);
675 if (flags == -1 || errno == EBADF) {
678 "stale file descriptor: %s", s.str().c_str());
690 std::unique_ptr<TCPSocket> tcp_socket;
691 tcp_socket = std::make_unique<TCPSocket>(fd,
false);
696 !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
698 m_io_sp = std::move(tcp_socket);
709 "invalid file descriptor: \"%s\"", s.str().c_str());
713 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
720 std::string addr_str = s.str();
731 struct termios options;
732 ::tcgetattr(fd, &options);
735 ::cfsetospeed(&options, B115200);
736 ::cfsetispeed(&options, B115200);
739 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
742 options.c_cc[VMIN] = 1;
743 options.c_cc[VTIME] = 0;
745 llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW, &options);
751 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
758 llvm::StringRef path, qs;
760 std::tie(path, qs) = s.split(
'?');
762 llvm::Expected<SerialPort::Options> serial_options =
764 if (!serial_options) {
768 llvm::consumeError(serial_options.takeError());
785 llvm::consumeError(serial_sp.takeError());
788 m_io_sp = std::move(serial_sp.get());
792 llvm_unreachable(
"this function should be only called w/ LLDB_ENABLE_POSIX");
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
lldb::ConnectionStatus AcceptTCP(llvm::StringRef host_and_port, socket_id_callback_type socket_id_callback, Status *error_ptr)
ConnectionFileDescriptor()
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)
lldb::ConnectionStatus ConnectSerialPort(llvm::StringRef args, socket_id_callback_type socket_id_callback, Status *error_ptr)
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 std::unique_ptr< Socket > Create(const SocketProtocol protocol, Status &error)
virtual std::string GetRemoteConnectionURI() const
static llvm::Expected< std::unique_ptr< UDPSocket > > UdpConnect(llvm::StringRef host_and_port)
static Status FromErrno()
Set the current error to errno.
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
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.