1 //===-- ConnectionFileDescriptorPosix.cpp ---------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
10 // Enable this special support for Apple builds where we can have unlimited
11 // select bounds. We tried switching to poll() and kqueue and we were panicing
12 // the kernel, so we have to stick with select for now.
13 #define _DARWIN_UNLIMITED_SELECT
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"
29 #include <sys/types.h>
39 #include "llvm/Support/Errno.h"
40 #include "llvm/Support/ErrorHandling.h"
41 #if defined(__APPLE__)
42 #include "llvm/ADT/SmallVector.h"
44 #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"
53 using namespace lldb_private
;
55 ConnectionFileDescriptor::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));
62 ConnectionFileDescriptor::ConnectionFileDescriptor(int fd
, bool owns_fd
)
63 : Connection(), m_pipe(), m_mutex(), m_shutting_down(false) {
65 std::make_shared
<NativeFile
>(fd
, File::eOpenOptionReadWrite
, owns_fd
);
67 Log
*log(GetLog(LLDBLog::Connection
| LLDBLog::Object
));
69 "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = "
71 static_cast<void *>(this), fd
, owns_fd
);
75 ConnectionFileDescriptor::ConnectionFileDescriptor(Socket
*socket
)
76 : Connection(), m_pipe(), m_mutex(), m_shutting_down(false) {
77 InitializeSocket(socket
);
80 ConnectionFileDescriptor::~ConnectionFileDescriptor() {
81 Log
*log(GetLog(LLDBLog::Connection
| LLDBLog::Object
));
82 LLDB_LOGF(log
, "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
83 static_cast<void *>(this));
88 void ConnectionFileDescriptor::OpenCommandPipe() {
91 Log
*log
= GetLog(LLDBLog::Connection
);
92 // Make the command file descriptor here:
93 Status result
= m_pipe
.CreateNew(/*child_processes_inherit=*/false);
94 if (!result
.Success()) {
96 "%p ConnectionFileDescriptor::OpenCommandPipe () - could not "
98 static_cast<void *>(this), result
.AsCString());
101 "%p ConnectionFileDescriptor::OpenCommandPipe() - success "
102 "readfd=%d writefd=%d",
103 static_cast<void *>(this), m_pipe
.GetReadFileDescriptor(),
104 m_pipe
.GetWriteFileDescriptor());
108 void ConnectionFileDescriptor::CloseCommandPipe() {
109 Log
*log
= GetLog(LLDBLog::Connection
);
110 LLDB_LOGF(log
, "%p ConnectionFileDescriptor::CloseCommandPipe()",
111 static_cast<void *>(this));
116 bool ConnectionFileDescriptor::IsConnected() const {
117 return m_io_sp
&& m_io_sp
->IsValid();
120 ConnectionStatus
ConnectionFileDescriptor::Connect(llvm::StringRef path
,
122 return Connect(path
, [](llvm::StringRef
) {}, error_ptr
);
126 ConnectionFileDescriptor::Connect(llvm::StringRef path
,
127 socket_id_callback_type socket_id_callback
,
129 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
130 Log
*log
= GetLog(LLDBLog::Connection
);
131 LLDB_LOGF(log
, "%p ConnectionFileDescriptor::Connect (url = '%s')",
132 static_cast<void *>(this), path
.str().c_str());
138 *error_ptr
= Status::FromErrorString("invalid connect arguments");
139 return eConnectionStatusError
;
142 llvm::StringRef scheme
;
143 std::tie(scheme
, path
) = path
.split("://");
147 llvm::StringSwitch
<ConnectionStatus (ConnectionFileDescriptor::*)(
148 llvm::StringRef
, socket_id_callback_type
, Status
*)>(scheme
)
149 .Case("listen", &ConnectionFileDescriptor::AcceptTCP
)
150 .Cases("accept", "unix-accept",
151 &ConnectionFileDescriptor::AcceptNamedSocket
)
152 .Case("unix-abstract-accept",
153 &ConnectionFileDescriptor::AcceptAbstractSocket
)
154 .Cases("connect", "tcp-connect",
155 &ConnectionFileDescriptor::ConnectTCP
)
156 .Case("udp", &ConnectionFileDescriptor::ConnectUDP
)
157 .Case("unix-connect", &ConnectionFileDescriptor::ConnectNamedSocket
)
158 .Case("unix-abstract-connect",
159 &ConnectionFileDescriptor::ConnectAbstractSocket
)
160 #if LLDB_ENABLE_POSIX
161 .Case("fd", &ConnectionFileDescriptor::ConnectFD
)
162 .Case("file", &ConnectionFileDescriptor::ConnectFile
)
163 .Case("serial", &ConnectionFileDescriptor::ConnectSerialPort
)
169 *error_ptr
= Status();
170 return (this->*method
)(path
, socket_id_callback
, error_ptr
);
175 *error_ptr
= Status::FromErrorStringWithFormat(
176 "unsupported connection URL: '%s'", path
.str().c_str());
177 return eConnectionStatusError
;
180 bool ConnectionFileDescriptor::InterruptRead() {
181 size_t bytes_written
= 0;
182 Status result
= m_pipe
.Write("i", 1, bytes_written
);
183 return result
.Success();
186 ConnectionStatus
ConnectionFileDescriptor::Disconnect(Status
*error_ptr
) {
187 Log
*log
= GetLog(LLDBLog::Connection
);
188 LLDB_LOGF(log
, "%p ConnectionFileDescriptor::Disconnect ()",
189 static_cast<void *>(this));
191 ConnectionStatus status
= eConnectionStatusSuccess
;
193 if (!IsConnected()) {
195 log
, "%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
196 static_cast<void *>(this));
197 return eConnectionStatusSuccess
;
200 // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is
201 // quite likely because somebody is doing a blocking read on our file
202 // descriptor. If that's the case, then send the "q" char to the command
203 // file channel so the read will wake up and the connection will then know to
205 std::unique_lock
<std::recursive_mutex
> locker(m_mutex
, std::defer_lock
);
206 if (!locker
.try_lock()) {
207 if (m_pipe
.CanWrite()) {
208 size_t bytes_written
= 0;
209 Status result
= m_pipe
.Write("q", 1, bytes_written
);
211 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get "
212 "the lock, sent 'q' to %d, error = '%s'.",
213 static_cast<void *>(this), m_pipe
.GetWriteFileDescriptor(),
217 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get the "
218 "lock, but no command pipe is available.",
219 static_cast<void *>(this));
224 // Prevents reads and writes during shutdown.
225 m_shutting_down
= true;
227 Status error
= m_io_sp
->Close();
229 status
= eConnectionStatusError
;
231 *error_ptr
= std::move(error
);
233 // Close any pipes we were using for async interrupts
237 m_shutting_down
= false;
241 size_t ConnectionFileDescriptor::Read(void *dst
, size_t dst_len
,
242 const Timeout
<std::micro
> &timeout
,
243 ConnectionStatus
&status
,
245 Log
*log
= GetLog(LLDBLog::Connection
);
247 std::unique_lock
<std::recursive_mutex
> locker(m_mutex
, std::defer_lock
);
248 if (!locker
.try_lock()) {
250 "%p ConnectionFileDescriptor::Read () failed to get the "
252 static_cast<void *>(this));
254 *error_ptr
= Status::FromErrorString(
255 "failed to get the connection lock for read.");
257 status
= eConnectionStatusTimedOut
;
261 if (m_shutting_down
) {
263 *error_ptr
= Status::FromErrorString("shutting down");
264 status
= eConnectionStatusError
;
268 status
= BytesAvailable(timeout
, error_ptr
);
269 if (status
!= eConnectionStatusSuccess
)
273 size_t bytes_read
= dst_len
;
274 error
= m_io_sp
->Read(dst
, bytes_read
);
278 "%p ConnectionFileDescriptor::Read() fd = %" PRIu64
279 ", dst = %p, dst_len = %" PRIu64
") => %" PRIu64
", error = %s",
280 static_cast<void *>(this),
281 static_cast<uint64_t>(m_io_sp
->GetWaitableHandle()),
282 static_cast<void *>(dst
), static_cast<uint64_t>(dst_len
),
283 static_cast<uint64_t>(bytes_read
), error
.AsCString());
286 if (bytes_read
== 0) {
287 error
.Clear(); // End-of-file. Do not automatically close; pass along for
288 // the end-of-file handlers.
289 status
= eConnectionStatusEndOfFile
;
293 *error_ptr
= error
.Clone();
296 uint32_t error_value
= error
.GetError();
297 switch (error_value
) {
298 case EAGAIN
: // The file was marked for non-blocking I/O, and no data were
300 if (m_io_sp
->GetFdType() == IOObject::eFDTypeSocket
)
301 status
= eConnectionStatusTimedOut
;
303 status
= eConnectionStatusSuccess
;
306 case EFAULT
: // Buf points outside the allocated address space.
307 case EINTR
: // A read from a slow device was interrupted before any data
308 // arrived by the delivery of a signal.
309 case EINVAL
: // The pointer associated with fildes was negative.
310 case EIO
: // An I/O error occurred while reading from the file system.
311 // The process group is orphaned.
312 // The file is a regular file, nbyte is greater than 0, the
313 // starting position is before the end-of-file, and the
314 // starting position is greater than or equal to the offset
315 // maximum established for the open file descriptor
316 // associated with fildes.
317 case EISDIR
: // An attempt is made to read a directory.
318 case ENOBUFS
: // An attempt to allocate a memory buffer fails.
319 case ENOMEM
: // Insufficient memory is available.
320 status
= eConnectionStatusError
;
321 break; // Break to close....
323 case ENOENT
: // no such file or directory
324 case EBADF
: // fildes is not a valid file or socket descriptor open for
326 case ENXIO
: // An action is requested of a device that does not exist..
327 // A requested action cannot be performed by the device.
328 case ECONNRESET
: // The connection is closed by the peer during a read
329 // attempt on a socket.
330 case ENOTCONN
: // A read is attempted on an unconnected socket.
331 status
= eConnectionStatusLostConnection
;
332 break; // Break to close....
334 case ETIMEDOUT
: // A transmission timeout occurs during a read attempt on a
336 status
= eConnectionStatusTimedOut
;
340 LLDB_LOG(log
, "this = {0}, unexpected error: {1}", this,
341 llvm::sys::StrError(error_value
));
342 status
= eConnectionStatusError
;
343 break; // Break to close....
351 size_t ConnectionFileDescriptor::Write(const void *src
, size_t src_len
,
352 ConnectionStatus
&status
,
354 Log
*log
= GetLog(LLDBLog::Connection
);
356 "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64
358 static_cast<void *>(this), static_cast<const void *>(src
),
359 static_cast<uint64_t>(src_len
));
361 if (!IsConnected()) {
363 *error_ptr
= Status::FromErrorString("not connected");
364 status
= eConnectionStatusNoConnection
;
368 if (m_shutting_down
) {
370 *error_ptr
= Status::FromErrorString("shutting down");
371 status
= eConnectionStatusError
;
377 size_t bytes_sent
= src_len
;
378 error
= m_io_sp
->Write(src
, bytes_sent
);
382 "%p ConnectionFileDescriptor::Write(fd = %" PRIu64
383 ", src = %p, src_len = %" PRIu64
") => %" PRIu64
" (error = %s)",
384 static_cast<void *>(this),
385 static_cast<uint64_t>(m_io_sp
->GetWaitableHandle()),
386 static_cast<const void *>(src
), static_cast<uint64_t>(src_len
),
387 static_cast<uint64_t>(bytes_sent
), error
.AsCString());
391 *error_ptr
= error
.Clone();
394 switch (error
.GetError()) {
397 status
= eConnectionStatusSuccess
;
400 case ECONNRESET
: // The connection is closed by the peer during a read
401 // attempt on a socket.
402 case ENOTCONN
: // A read is attempted on an unconnected socket.
403 status
= eConnectionStatusLostConnection
;
404 break; // Break to close....
407 status
= eConnectionStatusError
;
408 break; // Break to close....
414 status
= eConnectionStatusSuccess
;
418 std::string
ConnectionFileDescriptor::GetURI() { return m_uri
; }
420 // This ConnectionFileDescriptor::BytesAvailable() uses select() via
424 // - select is consistent across most unix platforms
425 // - The Apple specific version allows for unlimited fds in the fd_sets by
426 // setting the _DARWIN_UNLIMITED_SELECT define prior to including the
427 // required header files.
429 // - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE.
430 // This implementation will assert if it runs into that hard limit to let
431 // users know that another ConnectionFileDescriptor::BytesAvailable() should
432 // be used or a new version of ConnectionFileDescriptor::BytesAvailable()
433 // should be written for the system that is running into the limitations.
436 ConnectionFileDescriptor::BytesAvailable(const Timeout
<std::micro
> &timeout
,
438 // Don't need to take the mutex here separately since we are only called from
439 // Read. If we ever get used more generally we will need to lock here as
442 Log
*log
= GetLog(LLDBLog::Connection
);
443 LLDB_LOG(log
, "this = {0}, timeout = {1}", this, timeout
);
445 // Make a copy of the file descriptors to make sure we don't have another
446 // thread change these values out from under us and cause problems in the
447 // loop below where like in FS_SET()
448 const IOObject::WaitableHandle handle
= m_io_sp
->GetWaitableHandle();
449 const int pipe_fd
= m_pipe
.GetReadFileDescriptor();
451 if (handle
!= IOObject::kInvalidHandleValue
) {
452 SelectHelper select_helper
;
454 select_helper
.SetTimeout(*timeout
);
456 select_helper
.FDSetRead(handle
);
458 // select() won't accept pipes on Windows. The entire Windows codepath
459 // needs to be converted over to using WaitForMultipleObjects and event
460 // HANDLEs, but for now at least this will allow ::select() to not return
462 const bool have_pipe_fd
= false;
464 const bool have_pipe_fd
= pipe_fd
>= 0;
467 select_helper
.FDSetRead(pipe_fd
);
469 while (handle
== m_io_sp
->GetWaitableHandle()) {
471 Status error
= select_helper
.Select();
474 *error_ptr
= error
.Clone();
477 switch (error
.GetError()) {
478 case EBADF
: // One of the descriptor sets specified an invalid
480 return eConnectionStatusLostConnection
;
482 case EINVAL
: // The specified time limit is invalid. One of its
483 // components is negative or too large.
484 default: // Other unknown error
485 return eConnectionStatusError
;
488 return eConnectionStatusTimedOut
;
490 case EAGAIN
: // The kernel was (perhaps temporarily) unable to
491 // allocate the requested number of file descriptors, or
492 // we have non-blocking IO
493 case EINTR
: // A signal was delivered before the time limit
494 // expired and before any of the selected events occurred.
495 break; // Lets keep reading to until we timeout
498 if (select_helper
.FDIsSetRead(handle
))
499 return eConnectionStatusSuccess
;
501 if (select_helper
.FDIsSetRead(pipe_fd
)) {
502 // There is an interrupt or exit command in the command pipe Read the
503 // data from that pipe:
507 llvm::sys::RetryAfterSignal(-1, ::read
, pipe_fd
, &c
, 1);
508 assert(bytes_read
== 1);
509 UNUSED_IF_ASSERT_DISABLED(bytes_read
);
513 "%p ConnectionFileDescriptor::BytesAvailable() "
514 "got data: %c from the command channel.",
515 static_cast<void *>(this), c
);
516 return eConnectionStatusEndOfFile
;
518 // Interrupt the current read
519 return eConnectionStatusInterrupted
;
527 *error_ptr
= Status::FromErrorString("not connected");
528 return eConnectionStatusLostConnection
;
531 lldb::ConnectionStatus
ConnectionFileDescriptor::AcceptSocket(
532 Socket::SocketProtocol socket_protocol
, llvm::StringRef socket_name
,
533 llvm::function_ref
<void(Socket
&)> post_listen_callback
,
536 std::unique_ptr
<Socket
> listening_socket
=
537 Socket::Create(socket_protocol
, error
);
538 Socket
*accepted_socket
;
541 error
= listening_socket
->Listen(socket_name
, 5);
544 post_listen_callback(*listening_socket
);
545 error
= listening_socket
->Accept(/*timeout=*/std::nullopt
, accepted_socket
);
549 m_io_sp
.reset(accepted_socket
);
550 m_uri
.assign(socket_name
.str());
551 return eConnectionStatusSuccess
;
555 *error_ptr
= error
.Clone();
556 return eConnectionStatusError
;
559 lldb::ConnectionStatus
560 ConnectionFileDescriptor::ConnectSocket(Socket::SocketProtocol socket_protocol
,
561 llvm::StringRef socket_name
,
564 std::unique_ptr
<Socket
> socket
= Socket::Create(socket_protocol
, error
);
567 error
= socket
->Connect(socket_name
);
570 m_io_sp
= std::move(socket
);
571 m_uri
.assign(socket_name
.str());
572 return eConnectionStatusSuccess
;
576 *error_ptr
= error
.Clone();
577 return eConnectionStatusError
;
580 ConnectionStatus
ConnectionFileDescriptor::AcceptNamedSocket(
581 llvm::StringRef socket_name
, socket_id_callback_type socket_id_callback
,
584 Socket::ProtocolUnixDomain
, socket_name
,
585 [socket_id_callback
, socket_name
](Socket
&listening_socket
) {
586 socket_id_callback(socket_name
);
591 ConnectionStatus
ConnectionFileDescriptor::ConnectNamedSocket(
592 llvm::StringRef socket_name
, socket_id_callback_type socket_id_callback
,
594 return ConnectSocket(Socket::ProtocolUnixDomain
, socket_name
, error_ptr
);
597 ConnectionStatus
ConnectionFileDescriptor::AcceptAbstractSocket(
598 llvm::StringRef socket_name
, socket_id_callback_type socket_id_callback
,
601 Socket::ProtocolUnixAbstract
, socket_name
,
602 [socket_id_callback
, socket_name
](Socket
&listening_socket
) {
603 socket_id_callback(socket_name
);
608 lldb::ConnectionStatus
ConnectionFileDescriptor::ConnectAbstractSocket(
609 llvm::StringRef socket_name
, socket_id_callback_type socket_id_callback
,
611 return ConnectSocket(Socket::ProtocolUnixAbstract
, socket_name
, error_ptr
);
615 ConnectionFileDescriptor::AcceptTCP(llvm::StringRef socket_name
,
616 socket_id_callback_type socket_id_callback
,
618 ConnectionStatus ret
= AcceptSocket(
619 Socket::ProtocolTcp
, socket_name
,
620 [socket_id_callback
](Socket
&listening_socket
) {
622 static_cast<TCPSocket
&>(listening_socket
).GetLocalPortNumber();
623 socket_id_callback(std::to_string(port
));
626 if (ret
== eConnectionStatusSuccess
)
628 static_cast<TCPSocket
*>(m_io_sp
.get())->GetRemoteConnectionURI());
633 ConnectionFileDescriptor::ConnectTCP(llvm::StringRef socket_name
,
634 socket_id_callback_type socket_id_callback
,
636 return ConnectSocket(Socket::ProtocolTcp
, socket_name
, error_ptr
);
640 ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s
,
641 socket_id_callback_type socket_id_callback
,
644 *error_ptr
= Status();
645 llvm::Expected
<std::unique_ptr
<UDPSocket
>> socket
= Socket::UdpConnect(s
);
648 *error_ptr
= Status::FromError(socket
.takeError());
650 LLDB_LOG_ERROR(GetLog(LLDBLog::Connection
), socket
.takeError(),
651 "tcp connect failed: {0}");
652 return eConnectionStatusError
;
654 m_io_sp
= std::move(*socket
);
655 m_uri
.assign(std::string(s
));
656 return eConnectionStatusSuccess
;
660 ConnectionFileDescriptor::ConnectFD(llvm::StringRef s
,
661 socket_id_callback_type socket_id_callback
,
663 #if LLDB_ENABLE_POSIX
664 // Just passing a native file descriptor within this current process that
665 // is already opened (possibly from a service or other source).
668 if (!s
.getAsInteger(0, fd
)) {
669 // We have what looks to be a valid file descriptor, but we should make
670 // sure it is. We currently are doing this by trying to get the flags
671 // from the file descriptor and making sure it isn't a bad fd.
673 int flags
= ::fcntl(fd
, F_GETFL
, 0);
674 if (flags
== -1 || errno
== EBADF
) {
676 *error_ptr
= Status::FromErrorStringWithFormat(
677 "stale file descriptor: %s", s
.str().c_str());
679 return eConnectionStatusError
;
681 // Don't take ownership of a file descriptor that gets passed to us
682 // since someone else opened the file descriptor and handed it to us.
683 // TODO: Since are using a URL to open connection we should
684 // eventually parse options using the web standard where we have
685 // "fd://123?opt1=value;opt2=value" and we can have an option be
686 // "owns=1" or "owns=0" or something like this to allow us to specify
687 // this. For now, we assume we must assume we don't own it.
689 std::unique_ptr
<TCPSocket
> tcp_socket
;
690 tcp_socket
= std::make_unique
<TCPSocket
>(fd
, /*should_close=*/false);
691 // Try and get a socket option from this file descriptor to see if
692 // this is a socket and set m_is_socket accordingly.
695 !!tcp_socket
->GetOption(SOL_SOCKET
, SO_REUSEADDR
, resuse
);
697 m_io_sp
= std::move(tcp_socket
);
700 std::make_shared
<NativeFile
>(fd
, File::eOpenOptionReadWrite
, false);
702 return eConnectionStatusSuccess
;
707 *error_ptr
= Status::FromErrorStringWithFormat(
708 "invalid file descriptor: \"%s\"", s
.str().c_str());
710 return eConnectionStatusError
;
711 #endif // LLDB_ENABLE_POSIX
712 llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
715 ConnectionStatus
ConnectionFileDescriptor::ConnectFile(
716 llvm::StringRef s
, socket_id_callback_type socket_id_callback
,
718 #if LLDB_ENABLE_POSIX
719 std::string addr_str
= s
.str();
721 int fd
= FileSystem::Instance().Open(addr_str
.c_str(), O_RDWR
);
724 *error_ptr
= Status::FromErrno();
725 return eConnectionStatusError
;
729 // Set up serial terminal emulation
730 struct termios options
;
731 ::tcgetattr(fd
, &options
);
733 // Set port speed to maximum
734 ::cfsetospeed(&options
, B115200
);
735 ::cfsetispeed(&options
, B115200
);
737 // Raw input, disable echo and signals
738 options
.c_lflag
&= ~(ICANON
| ECHO
| ECHOE
| ISIG
);
740 // Make sure only one character is needed to return from a read
741 options
.c_cc
[VMIN
] = 1;
742 options
.c_cc
[VTIME
] = 0;
744 llvm::sys::RetryAfterSignal(-1, ::tcsetattr
, fd
, TCSANOW
, &options
);
747 m_io_sp
= std::make_shared
<NativeFile
>(fd
, File::eOpenOptionReadWrite
, true);
748 return eConnectionStatusSuccess
;
749 #endif // LLDB_ENABLE_POSIX
750 llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
753 ConnectionStatus
ConnectionFileDescriptor::ConnectSerialPort(
754 llvm::StringRef s
, socket_id_callback_type socket_id_callback
,
756 #if LLDB_ENABLE_POSIX
757 llvm::StringRef path
, qs
;
758 // serial:///PATH?k1=v1&k2=v2...
759 std::tie(path
, qs
) = s
.split('?');
761 llvm::Expected
<SerialPort::Options
> serial_options
=
762 SerialPort::OptionsFromURL(qs
);
763 if (!serial_options
) {
765 *error_ptr
= Status::FromError(serial_options
.takeError());
767 llvm::consumeError(serial_options
.takeError());
768 return eConnectionStatusError
;
771 int fd
= FileSystem::Instance().Open(path
.str().c_str(), O_RDWR
);
774 *error_ptr
= Status::FromErrno();
775 return eConnectionStatusError
;
778 llvm::Expected
<std::unique_ptr
<SerialPort
>> serial_sp
= SerialPort::Create(
779 fd
, File::eOpenOptionReadWrite
, serial_options
.get(), true);
782 *error_ptr
= Status::FromError(serial_sp
.takeError());
784 llvm::consumeError(serial_sp
.takeError());
785 return eConnectionStatusError
;
787 m_io_sp
= std::move(serial_sp
.get());
789 return eConnectionStatusSuccess
;
790 #endif // LLDB_ENABLE_POSIX
791 llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
794 void ConnectionFileDescriptor::InitializeSocket(Socket
*socket
) {
795 m_io_sp
.reset(socket
);
796 m_uri
= socket
->GetRemoteConnectionURI();