diff options
Diffstat (limited to 'lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp')
| -rw-r--r-- | lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp | 544 |
1 files changed, 287 insertions, 257 deletions
diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 2f4cc960f02d..b3140f7b0fd7 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -13,10 +13,10 @@ #define _DARWIN_UNLIMITED_SELECT #endif -#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" #include "lldb/Host/Config.h" #include "lldb/Host/Socket.h" #include "lldb/Host/SocketAddress.h" +#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" #include "lldb/Utility/SelectHelper.h" #include "lldb/Utility/Timeout.h" @@ -50,30 +50,6 @@ using namespace lldb; using namespace lldb_private; -const char *ConnectionFileDescriptor::LISTEN_SCHEME = "listen"; -const char *ConnectionFileDescriptor::ACCEPT_SCHEME = "accept"; -const char *ConnectionFileDescriptor::UNIX_ACCEPT_SCHEME = "unix-accept"; -const char *ConnectionFileDescriptor::CONNECT_SCHEME = "connect"; -const char *ConnectionFileDescriptor::TCP_CONNECT_SCHEME = "tcp-connect"; -const char *ConnectionFileDescriptor::UDP_SCHEME = "udp"; -const char *ConnectionFileDescriptor::UNIX_CONNECT_SCHEME = "unix-connect"; -const char *ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME = - "unix-abstract-connect"; -const char *ConnectionFileDescriptor::FD_SCHEME = "fd"; -const char *ConnectionFileDescriptor::FILE_SCHEME = "file"; - -namespace { - -llvm::Optional<llvm::StringRef> GetURLAddress(llvm::StringRef url, - llvm::StringRef scheme) { - if (!url.consume_front(scheme)) - return llvm::None; - if (!url.consume_front("://")) - return llvm::None; - return url; -} -} - ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit) : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), @@ -86,9 +62,9 @@ ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit) ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd) : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), - m_waiting_for_accept(false), m_child_processes_inherit(false) { - m_write_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionWrite, owns_fd); - m_read_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionRead, false); + m_child_processes_inherit(false) { + m_io_sp = + std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, owns_fd); Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); @@ -101,7 +77,7 @@ ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd) ConnectionFileDescriptor::ConnectionFileDescriptor(Socket *socket) : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), - m_waiting_for_accept(false), m_child_processes_inherit(false) { + m_child_processes_inherit(false) { InitializeSocket(socket); } @@ -143,12 +119,18 @@ void ConnectionFileDescriptor::CloseCommandPipe() { } bool ConnectionFileDescriptor::IsConnected() const { - return (m_read_sp && m_read_sp->IsValid()) || - (m_write_sp && m_write_sp->IsValid()); + return m_io_sp && m_io_sp->IsValid(); } ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, Status *error_ptr) { + return Connect(path, nullptr, error_ptr); +} + +ConnectionStatus +ConnectionFileDescriptor::Connect(llvm::StringRef path, + socket_id_callback_type socket_id_callback, + Status *error_ptr) { std::lock_guard<std::recursive_mutex> guard(m_mutex); Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); LLDB_LOGF(log, "%p ConnectionFileDescriptor::Connect (url = '%s')", @@ -156,133 +138,47 @@ ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, OpenCommandPipe(); - if (!path.empty()) { - llvm::Optional<llvm::StringRef> addr; - if ((addr = GetURLAddress(path, LISTEN_SCHEME))) { - // listen://HOST:PORT - return SocketListenAndAccept(*addr, error_ptr); - } else if ((addr = GetURLAddress(path, ACCEPT_SCHEME))) { - // unix://SOCKNAME - return NamedSocketAccept(*addr, error_ptr); - } else if ((addr = GetURLAddress(path, UNIX_ACCEPT_SCHEME))) { - // unix://SOCKNAME - return NamedSocketAccept(*addr, error_ptr); - } else if ((addr = GetURLAddress(path, CONNECT_SCHEME))) { - return ConnectTCP(*addr, error_ptr); - } else if ((addr = GetURLAddress(path, TCP_CONNECT_SCHEME))) { - return ConnectTCP(*addr, error_ptr); - } else if ((addr = GetURLAddress(path, UDP_SCHEME))) { - return ConnectUDP(*addr, error_ptr); - } else if ((addr = GetURLAddress(path, UNIX_CONNECT_SCHEME))) { - // unix-connect://SOCKNAME - return NamedSocketConnect(*addr, error_ptr); - } else if ((addr = GetURLAddress(path, UNIX_ABSTRACT_CONNECT_SCHEME))) { - // unix-abstract-connect://SOCKNAME - return UnixAbstractSocketConnect(*addr, error_ptr); - } -#if LLDB_ENABLE_POSIX - else if ((addr = GetURLAddress(path, FD_SCHEME))) { - // Just passing a native file descriptor within this current process that - // is already opened (possibly from a service or other source). - int fd = -1; + if (path.empty()) { + if (error_ptr) + error_ptr->SetErrorString("invalid connect arguments"); + return eConnectionStatusError; + } - if (!addr->getAsInteger(0, fd)) { - // We have what looks to be a valid file descriptor, but we should make - // sure it is. We currently are doing this by trying to get the flags - // from the file descriptor and making sure it isn't a bad fd. - errno = 0; - int flags = ::fcntl(fd, F_GETFL, 0); - if (flags == -1 || errno == EBADF) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", - path.str().c_str()); - m_read_sp.reset(); - m_write_sp.reset(); - return eConnectionStatusError; - } else { - // Don't take ownership of a file descriptor that gets passed to us - // since someone else opened the file descriptor and handed it to us. - // TODO: Since are using a URL to open connection we should - // eventually parse options using the web standard where we have - // "fd://123?opt1=value;opt2=value" and we can have an option be - // "owns=1" or "owns=0" or something like this to allow us to specify - // this. For now, we assume we must assume we don't own it. + llvm::StringRef scheme; + std::tie(scheme, path) = path.split("://"); - std::unique_ptr<TCPSocket> tcp_socket; - tcp_socket = std::make_unique<TCPSocket>(fd, false, false); - // Try and get a socket option from this file descriptor to see if - // this is a socket and set m_is_socket accordingly. - int resuse; - bool is_socket = - !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse); - if (is_socket) { - m_read_sp = std::move(tcp_socket); - m_write_sp = m_read_sp; - } else { - m_read_sp = - std::make_shared<NativeFile>(fd, File::eOpenOptionRead, false); - m_write_sp = - std::make_shared<NativeFile>(fd, File::eOpenOptionWrite, false); - } - m_uri = std::string(*addr); - return eConnectionStatusSuccess; - } - } + if (!path.empty()) { + auto method = + llvm::StringSwitch<ConnectionStatus (ConnectionFileDescriptor::*)( + llvm::StringRef, socket_id_callback_type, Status *)>(scheme) + .Case("listen", &ConnectionFileDescriptor::AcceptTCP) + .Cases("accept", "unix-accept", + &ConnectionFileDescriptor::AcceptNamedSocket) + .Case("unix-abstract-accept", + &ConnectionFileDescriptor::AcceptAbstractSocket) + .Cases("connect", "tcp-connect", + &ConnectionFileDescriptor::ConnectTCP) + .Case("udp", &ConnectionFileDescriptor::ConnectUDP) + .Case("unix-connect", &ConnectionFileDescriptor::ConnectNamedSocket) + .Case("unix-abstract-connect", + &ConnectionFileDescriptor::ConnectAbstractSocket) +#if LLDB_ENABLE_POSIX + .Case("fd", &ConnectionFileDescriptor::ConnectFD) + .Case("file", &ConnectionFileDescriptor::ConnectFile) + .Case("serial", &ConnectionFileDescriptor::ConnectSerialPort) +#endif + .Default(nullptr); + if (method) { if (error_ptr) - error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"", - path.str().c_str()); - m_read_sp.reset(); - m_write_sp.reset(); - return eConnectionStatusError; - } else if ((addr = GetURLAddress(path, FILE_SCHEME))) { - std::string addr_str = addr->str(); - // file:///PATH - int fd = llvm::sys::RetryAfterSignal(-1, ::open, addr_str.c_str(), O_RDWR); - if (fd == -1) { - if (error_ptr) - error_ptr->SetErrorToErrno(); - return eConnectionStatusError; - } - - if (::isatty(fd)) { - // Set up serial terminal emulation - struct termios options; - ::tcgetattr(fd, &options); - - // Set port speed to maximum - ::cfsetospeed(&options, B115200); - ::cfsetispeed(&options, B115200); - - // Raw input, disable echo and signals - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - - // Make sure only one character is needed to return from a read - options.c_cc[VMIN] = 1; - options.c_cc[VTIME] = 0; - - llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW, &options); - } - - int flags = ::fcntl(fd, F_GETFL, 0); - if (flags >= 0) { - if ((flags & O_NONBLOCK) == 0) { - flags |= O_NONBLOCK; - ::fcntl(fd, F_SETFL, flags); - } - } - m_read_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionRead, true); - m_write_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionWrite, false); - return eConnectionStatusSuccess; + *error_ptr = Status(); + return (this->*method)(path, socket_id_callback, error_ptr); } -#endif - if (error_ptr) - error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", - path.str().c_str()); - return eConnectionStatusError; } + if (error_ptr) - error_ptr->SetErrorString("invalid connect arguments"); + error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", + path.str().c_str()); return eConnectionStatusError; } @@ -306,9 +202,8 @@ ConnectionStatus ConnectionFileDescriptor::Disconnect(Status *error_ptr) { return eConnectionStatusSuccess; } - if (m_read_sp && m_read_sp->IsValid() && - m_read_sp->GetFdType() == IOObject::eFDTypeSocket) - static_cast<Socket &>(*m_read_sp).PreDisconnect(); + if (m_io_sp->GetFdType() == IOObject::eFDTypeSocket) + static_cast<Socket &>(*m_io_sp).PreDisconnect(); // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is // quite likely because somebody is doing a blocking read on our file @@ -337,12 +232,11 @@ ConnectionStatus ConnectionFileDescriptor::Disconnect(Status *error_ptr) { // Prevents reads and writes during shutdown. m_shutting_down = true; - Status error = m_read_sp->Close(); - Status error2 = m_write_sp->Close(); - if (error.Fail() || error2.Fail()) + Status error = m_io_sp->Close(); + if (error.Fail()) status = eConnectionStatusError; if (error_ptr) - *error_ptr = error.Fail() ? error : error2; + *error_ptr = error; // Close any pipes we were using for async interrupts m_pipe.Close(); @@ -384,14 +278,14 @@ size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len, Status error; size_t bytes_read = dst_len; - error = m_read_sp->Read(dst, bytes_read); + error = m_io_sp->Read(dst, bytes_read); if (log) { LLDB_LOGF(log, "%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s", static_cast<void *>(this), - static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), + static_cast<uint64_t>(m_io_sp->GetWaitableHandle()), static_cast<void *>(dst), static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString()); } @@ -410,7 +304,7 @@ size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len, switch (error_value) { case EAGAIN: // The file was marked for non-blocking I/O, and no data were // ready to be read. - if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket) + if (m_io_sp->GetFdType() == IOObject::eFDTypeSocket) status = eConnectionStatusTimedOut; else status = eConnectionStatusSuccess; @@ -488,14 +382,14 @@ size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len, Status error; size_t bytes_sent = src_len; - error = m_write_sp->Write(src, bytes_sent); + error = m_io_sp->Write(src, bytes_sent); if (log) { LLDB_LOGF(log, "%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)", static_cast<void *>(this), - static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), + static_cast<uint64_t>(m_io_sp->GetWaitableHandle()), static_cast<const void *>(src), static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString()); } @@ -558,7 +452,7 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout, // Make a copy of the file descriptors to make sure we don't have another // thread change these values out from under us and cause problems in the // loop below where like in FS_SET() - const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle(); + const IOObject::WaitableHandle handle = m_io_sp->GetWaitableHandle(); const int pipe_fd = m_pipe.GetReadFileDescriptor(); if (handle != IOObject::kInvalidHandleValue) { @@ -579,7 +473,7 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout, if (have_pipe_fd) select_helper.FDSetRead(pipe_fd); - while (handle == m_read_sp->GetWaitableHandle()) { + while (handle == m_io_sp->GetWaitableHandle()) { Status error = select_helper.Select(); @@ -616,7 +510,8 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout, // data from that pipe: char c; - ssize_t bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1); + ssize_t bytes_read = + llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1); assert(bytes_read == 1); (void)bytes_read; switch (c) { @@ -640,95 +535,123 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout, return eConnectionStatusLostConnection; } -ConnectionStatus -ConnectionFileDescriptor::NamedSocketAccept(llvm::StringRef socket_name, - Status *error_ptr) { - Socket *socket = nullptr; - Status error = - Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket); - if (error_ptr) - *error_ptr = error; - m_write_sp.reset(socket); - m_read_sp = m_write_sp; - if (error.Fail()) { - return eConnectionStatusError; +lldb::ConnectionStatus ConnectionFileDescriptor::AcceptSocket( + Socket::SocketProtocol socket_protocol, llvm::StringRef socket_name, + llvm::function_ref<void(Socket &)> post_listen_callback, + Status *error_ptr) { + Status error; + std::unique_ptr<Socket> listening_socket = + Socket::Create(socket_protocol, m_child_processes_inherit, error); + Socket *accepted_socket; + + if (!error.Fail()) + error = listening_socket->Listen(socket_name, 5); + + if (!error.Fail()) { + post_listen_callback(*listening_socket); + error = listening_socket->Accept(accepted_socket); + } + + if (!error.Fail()) { + m_io_sp.reset(accepted_socket); + m_uri.assign(socket_name.str()); + return eConnectionStatusSuccess; } - m_uri.assign(std::string(socket_name)); - return eConnectionStatusSuccess; -} -ConnectionStatus -ConnectionFileDescriptor::NamedSocketConnect(llvm::StringRef socket_name, - Status *error_ptr) { - Socket *socket = nullptr; - Status error = - Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket); if (error_ptr) *error_ptr = error; - m_write_sp.reset(socket); - m_read_sp = m_write_sp; - if (error.Fail()) { - return eConnectionStatusError; - } - m_uri.assign(std::string(socket_name)); - return eConnectionStatusSuccess; + return eConnectionStatusError; } lldb::ConnectionStatus -ConnectionFileDescriptor::UnixAbstractSocketConnect(llvm::StringRef socket_name, - Status *error_ptr) { - Socket *socket = nullptr; - Status error = Socket::UnixAbstractConnect(socket_name, - m_child_processes_inherit, socket); +ConnectionFileDescriptor::ConnectSocket(Socket::SocketProtocol socket_protocol, + llvm::StringRef socket_name, + Status *error_ptr) { + Status error; + std::unique_ptr<Socket> socket = + Socket::Create(socket_protocol, m_child_processes_inherit, error); + + if (!error.Fail()) + error = socket->Connect(socket_name); + + if (!error.Fail()) { + m_io_sp = std::move(socket); + m_uri.assign(socket_name.str()); + return eConnectionStatusSuccess; + } + if (error_ptr) *error_ptr = error; - m_write_sp.reset(socket); - m_read_sp = m_write_sp; - if (error.Fail()) { - return eConnectionStatusError; - } - m_uri.assign(std::string(socket_name)); - return eConnectionStatusSuccess; + return eConnectionStatusError; } -ConnectionStatus -ConnectionFileDescriptor::SocketListenAndAccept(llvm::StringRef s, - Status *error_ptr) { - if (error_ptr) - *error_ptr = Status(); - m_port_predicate.SetValue(0, eBroadcastNever); +ConnectionStatus ConnectionFileDescriptor::AcceptNamedSocket( + llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, + Status *error_ptr) { + return AcceptSocket( + Socket::ProtocolUnixDomain, socket_name, + [socket_id_callback, socket_name](Socket &listening_socket) { + socket_id_callback(socket_name); + }, + error_ptr); +} - m_waiting_for_accept = true; - llvm::Expected<std::unique_ptr<TCPSocket>> listening_socket = - Socket::TcpListen(s, m_child_processes_inherit, &m_port_predicate); - if (!listening_socket) { - if (error_ptr) - *error_ptr = listening_socket.takeError(); - else - LLDB_LOG_ERROR(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION), - listening_socket.takeError(), "tcp listen failed: {0}"); - return eConnectionStatusError; - } +ConnectionStatus ConnectionFileDescriptor::ConnectNamedSocket( + llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, + Status *error_ptr) { + return ConnectSocket(Socket::ProtocolUnixDomain, socket_name, error_ptr); +} +ConnectionStatus ConnectionFileDescriptor::AcceptAbstractSocket( + llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, + Status *error_ptr) { + return AcceptSocket( + Socket::ProtocolUnixAbstract, socket_name, + [socket_id_callback, socket_name](Socket &listening_socket) { + socket_id_callback(socket_name); + }, + error_ptr); +} - Socket *accepted_socket; - Status error = listening_socket.get()->Accept(accepted_socket); - if (error_ptr) - *error_ptr = error; - if (error.Fail()) - return eConnectionStatusError; +lldb::ConnectionStatus ConnectionFileDescriptor::ConnectAbstractSocket( + llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, + Status *error_ptr) { + return ConnectSocket(Socket::ProtocolUnixAbstract, socket_name, error_ptr); +} - InitializeSocket(accepted_socket); - return eConnectionStatusSuccess; +ConnectionStatus +ConnectionFileDescriptor::AcceptTCP(llvm::StringRef socket_name, + socket_id_callback_type socket_id_callback, + Status *error_ptr) { + ConnectionStatus ret = AcceptSocket( + Socket::ProtocolTcp, socket_name, + [socket_id_callback](Socket &listening_socket) { + uint16_t port = + static_cast<TCPSocket &>(listening_socket).GetLocalPortNumber(); + socket_id_callback(std::to_string(port)); + }, + error_ptr); + if (ret == eConnectionStatusSuccess) + m_uri.assign( + static_cast<TCPSocket *>(m_io_sp.get())->GetRemoteConnectionURI()); + return ret; } -ConnectionStatus ConnectionFileDescriptor::ConnectTCP(llvm::StringRef s, - Status *error_ptr) { +ConnectionStatus +ConnectionFileDescriptor::ConnectTCP(llvm::StringRef socket_name, + socket_id_callback_type socket_id_callback, + Status *error_ptr) { + return ConnectSocket(Socket::ProtocolTcp, socket_name, error_ptr); +} + +ConnectionStatus +ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s, + socket_id_callback_type socket_id_callback, + Status *error_ptr) { if (error_ptr) *error_ptr = Status(); - - llvm::Expected<std::unique_ptr<Socket>> socket = - Socket::TcpConnect(s, m_child_processes_inherit); + llvm::Expected<std::unique_ptr<UDPSocket>> socket = + Socket::UdpConnect(s, m_child_processes_inherit); if (!socket) { if (error_ptr) *error_ptr = socket.takeError(); @@ -737,36 +660,144 @@ ConnectionStatus ConnectionFileDescriptor::ConnectTCP(llvm::StringRef s, socket.takeError(), "tcp connect failed: {0}"); return eConnectionStatusError; } - m_write_sp = std::move(*socket); - m_read_sp = m_write_sp; + m_io_sp = std::move(*socket); m_uri.assign(std::string(s)); return eConnectionStatusSuccess; } -ConnectionStatus ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s, - Status *error_ptr) { +ConnectionStatus +ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, + socket_id_callback_type socket_id_callback, + Status *error_ptr) { +#if LLDB_ENABLE_POSIX + // Just passing a native file descriptor within this current process that + // is already opened (possibly from a service or other source). + int fd = -1; + + if (!s.getAsInteger(0, fd)) { + // We have what looks to be a valid file descriptor, but we should make + // sure it is. We currently are doing this by trying to get the flags + // from the file descriptor and making sure it isn't a bad fd. + errno = 0; + int flags = ::fcntl(fd, F_GETFL, 0); + if (flags == -1 || errno == EBADF) { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", + s.str().c_str()); + m_io_sp.reset(); + return eConnectionStatusError; + } else { + // Don't take ownership of a file descriptor that gets passed to us + // since someone else opened the file descriptor and handed it to us. + // TODO: Since are using a URL to open connection we should + // eventually parse options using the web standard where we have + // "fd://123?opt1=value;opt2=value" and we can have an option be + // "owns=1" or "owns=0" or something like this to allow us to specify + // this. For now, we assume we must assume we don't own it. + + std::unique_ptr<TCPSocket> tcp_socket; + tcp_socket = std::make_unique<TCPSocket>(fd, false, false); + // Try and get a socket option from this file descriptor to see if + // this is a socket and set m_is_socket accordingly. + int resuse; + bool is_socket = + !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse); + if (is_socket) + m_io_sp = std::move(tcp_socket); + else + m_io_sp = + std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, false); + m_uri = s.str(); + return eConnectionStatusSuccess; + } + } + if (error_ptr) - *error_ptr = Status(); - llvm::Expected<std::unique_ptr<UDPSocket>> socket = - Socket::UdpConnect(s, m_child_processes_inherit); - if (!socket) { + error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"", + s.str().c_str()); + m_io_sp.reset(); + return eConnectionStatusError; +#endif // LLDB_ENABLE_POSIX + llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); +} + +ConnectionStatus ConnectionFileDescriptor::ConnectFile( + llvm::StringRef s, socket_id_callback_type socket_id_callback, + Status *error_ptr) { +#if LLDB_ENABLE_POSIX + std::string addr_str = s.str(); + // file:///PATH + int fd = llvm::sys::RetryAfterSignal(-1, ::open, addr_str.c_str(), O_RDWR); + if (fd == -1) { if (error_ptr) - *error_ptr = socket.takeError(); - else - LLDB_LOG_ERROR(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION), - socket.takeError(), "tcp connect failed: {0}"); + error_ptr->SetErrorToErrno(); return eConnectionStatusError; } - m_write_sp = std::move(*socket); - m_read_sp = m_write_sp; - m_uri.assign(std::string(s)); + + if (::isatty(fd)) { + // Set up serial terminal emulation + struct termios options; + ::tcgetattr(fd, &options); + + // Set port speed to maximum + ::cfsetospeed(&options, B115200); + ::cfsetispeed(&options, B115200); + + // Raw input, disable echo and signals + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + + // Make sure only one character is needed to return from a read + options.c_cc[VMIN] = 1; + options.c_cc[VTIME] = 0; + + llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW, &options); + } + + m_io_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, true); return eConnectionStatusSuccess; +#endif // LLDB_ENABLE_POSIX + llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } -uint16_t -ConnectionFileDescriptor::GetListeningPort(const Timeout<std::micro> &timeout) { - auto Result = m_port_predicate.WaitForValueNotEqualTo(0, timeout); - return Result ? *Result : 0; +ConnectionStatus ConnectionFileDescriptor::ConnectSerialPort( + llvm::StringRef s, socket_id_callback_type socket_id_callback, + Status *error_ptr) { +#if LLDB_ENABLE_POSIX + llvm::StringRef path, qs; + // serial:///PATH?k1=v1&k2=v2... + std::tie(path, qs) = s.split('?'); + + llvm::Expected<SerialPort::Options> serial_options = + SerialPort::OptionsFromURL(qs); + if (!serial_options) { + if (error_ptr) + *error_ptr = serial_options.takeError(); + else + llvm::consumeError(serial_options.takeError()); + return eConnectionStatusError; + } + + int fd = llvm::sys::RetryAfterSignal(-1, ::open, path.str().c_str(), O_RDWR); + if (fd == -1) { + if (error_ptr) + error_ptr->SetErrorToErrno(); + return eConnectionStatusError; + } + + llvm::Expected<std::unique_ptr<SerialPort>> serial_sp = SerialPort::Create( + fd, File::eOpenOptionReadWrite, serial_options.get(), true); + if (!serial_sp) { + if (error_ptr) + *error_ptr = serial_sp.takeError(); + else + llvm::consumeError(serial_sp.takeError()); + return eConnectionStatusError; + } + m_io_sp = std::move(serial_sp.get()); + + return eConnectionStatusSuccess; +#endif // LLDB_ENABLE_POSIX + llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX"); } bool ConnectionFileDescriptor::GetChildProcessesInherit() const { @@ -779,7 +810,6 @@ void ConnectionFileDescriptor::SetChildProcessesInherit( } void ConnectionFileDescriptor::InitializeSocket(Socket *socket) { - m_write_sp.reset(socket); - m_read_sp = m_write_sp; + m_io_sp.reset(socket); m_uri = socket->GetRemoteConnectionURI(); } |
