xref: /llvm-project/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp (revision 18de1db0cfbfbbf12d16338923b43077a87dce18)
1 //===-- ConnectionFileDescriptorPosix.cpp ---------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #if defined(__APPLE__)
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
14 #endif
15 
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"
24 
25 #include <cerrno>
26 #include <cstdlib>
27 #include <cstring>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 
31 #if LLDB_ENABLE_POSIX
32 #include <termios.h>
33 #include <unistd.h>
34 #endif
35 
36 #include <memory>
37 #include <sstream>
38 
39 #include "llvm/Support/Errno.h"
40 #include "llvm/Support/ErrorHandling.h"
41 #if defined(__APPLE__)
42 #include "llvm/ADT/SmallVector.h"
43 #endif
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"
51 
52 using namespace lldb;
53 using namespace lldb_private;
54 
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));
60 }
61 
62 ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd)
63     : Connection(), m_pipe(), m_mutex(), m_shutting_down(false) {
64   m_io_sp =
65       std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, owns_fd);
66 
67   Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object));
68   LLDB_LOGF(log,
69             "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = "
70             "%i, owns_fd = %i)",
71             static_cast<void *>(this), fd, owns_fd);
72   OpenCommandPipe();
73 }
74 
75 ConnectionFileDescriptor::ConnectionFileDescriptor(Socket *socket)
76     : Connection(), m_pipe(), m_mutex(), m_shutting_down(false) {
77   InitializeSocket(socket);
78 }
79 
80 ConnectionFileDescriptor::~ConnectionFileDescriptor() {
81   Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object));
82   LLDB_LOGF(log, "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
83             static_cast<void *>(this));
84   Disconnect(nullptr);
85   CloseCommandPipe();
86 }
87 
88 void ConnectionFileDescriptor::OpenCommandPipe() {
89   CloseCommandPipe();
90 
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()) {
95     LLDB_LOGF(log,
96               "%p ConnectionFileDescriptor::OpenCommandPipe () - could not "
97               "make pipe: %s",
98               static_cast<void *>(this), result.AsCString());
99   } else {
100     LLDB_LOGF(log,
101               "%p ConnectionFileDescriptor::OpenCommandPipe() - success "
102               "readfd=%d writefd=%d",
103               static_cast<void *>(this), m_pipe.GetReadFileDescriptor(),
104               m_pipe.GetWriteFileDescriptor());
105   }
106 }
107 
108 void ConnectionFileDescriptor::CloseCommandPipe() {
109   Log *log = GetLog(LLDBLog::Connection);
110   LLDB_LOGF(log, "%p ConnectionFileDescriptor::CloseCommandPipe()",
111             static_cast<void *>(this));
112 
113   m_pipe.Close();
114 }
115 
116 bool ConnectionFileDescriptor::IsConnected() const {
117   return m_io_sp && m_io_sp->IsValid();
118 }
119 
120 ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path,
121                                                    Status *error_ptr) {
122   return Connect(path, [](llvm::StringRef) {}, error_ptr);
123 }
124 
125 ConnectionStatus
126 ConnectionFileDescriptor::Connect(llvm::StringRef path,
127                                   socket_id_callback_type socket_id_callback,
128                                   Status *error_ptr) {
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());
133 
134   OpenCommandPipe();
135 
136   if (path.empty()) {
137     if (error_ptr)
138       *error_ptr = Status::FromErrorString("invalid connect arguments");
139     return eConnectionStatusError;
140   }
141 
142   llvm::StringRef scheme;
143   std::tie(scheme, path) = path.split("://");
144 
145   if (!path.empty()) {
146     auto method =
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)
164 #endif
165             .Default(nullptr);
166 
167     if (method) {
168       if (error_ptr)
169         *error_ptr = Status();
170       return (this->*method)(path, socket_id_callback, error_ptr);
171     }
172   }
173 
174   if (error_ptr)
175     *error_ptr = Status::FromErrorStringWithFormat(
176         "unsupported connection URL: '%s'", path.str().c_str());
177   return eConnectionStatusError;
178 }
179 
180 bool ConnectionFileDescriptor::InterruptRead() {
181   size_t bytes_written = 0;
182   Status result = m_pipe.Write("i", 1, bytes_written);
183   return result.Success();
184 }
185 
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));
190 
191   ConnectionStatus status = eConnectionStatusSuccess;
192 
193   if (!IsConnected()) {
194     LLDB_LOGF(
195         log, "%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
196         static_cast<void *>(this));
197     return eConnectionStatusSuccess;
198   }
199 
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
204   // shut down.
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);
210       LLDB_LOGF(log,
211                 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get "
212                 "the lock, sent 'q' to %d, error = '%s'.",
213                 static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(),
214                 result.AsCString());
215     } else if (log) {
216       LLDB_LOGF(log,
217                 "%p ConnectionFileDescriptor::Disconnect(): Couldn't get the "
218                 "lock, but no command pipe is available.",
219                 static_cast<void *>(this));
220     }
221     locker.lock();
222   }
223 
224   // Prevents reads and writes during shutdown.
225   m_shutting_down = true;
226 
227   Status error = m_io_sp->Close();
228   if (error.Fail())
229     status = eConnectionStatusError;
230   if (error_ptr)
231     *error_ptr = std::move(error);
232 
233   // Close any pipes we were using for async interrupts
234   m_pipe.Close();
235 
236   m_uri.clear();
237   m_shutting_down = false;
238   return status;
239 }
240 
241 size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len,
242                                       const Timeout<std::micro> &timeout,
243                                       ConnectionStatus &status,
244                                       Status *error_ptr) {
245   Log *log = GetLog(LLDBLog::Connection);
246 
247   std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);
248   if (!locker.try_lock()) {
249     LLDB_LOGF(log,
250               "%p ConnectionFileDescriptor::Read () failed to get the "
251               "connection lock.",
252               static_cast<void *>(this));
253     if (error_ptr)
254       *error_ptr = Status::FromErrorString(
255           "failed to get the connection lock for read.");
256 
257     status = eConnectionStatusTimedOut;
258     return 0;
259   }
260 
261   if (m_shutting_down) {
262     if (error_ptr)
263       *error_ptr = Status::FromErrorString("shutting down");
264     status = eConnectionStatusError;
265     return 0;
266   }
267 
268   status = BytesAvailable(timeout, error_ptr);
269   if (status != eConnectionStatusSuccess)
270     return 0;
271 
272   Status error;
273   size_t bytes_read = dst_len;
274   error = m_io_sp->Read(dst, bytes_read);
275 
276   if (log) {
277     LLDB_LOGF(log,
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());
284   }
285 
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;
290   }
291 
292   if (error_ptr)
293     *error_ptr = error.Clone();
294 
295   if (error.Fail()) {
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
299                  // ready to be read.
300       if (m_io_sp->GetFdType() == IOObject::eFDTypeSocket)
301         status = eConnectionStatusTimedOut;
302       else
303         status = eConnectionStatusSuccess;
304       return 0;
305 
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....
322 
323     case ENOENT:     // no such file or directory
324     case EBADF:      // fildes is not a valid file or socket descriptor open for
325                      // reading.
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....
333 
334     case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a
335                     // socket.
336       status = eConnectionStatusTimedOut;
337       return 0;
338 
339     default:
340       LLDB_LOG(log, "this = {0}, unexpected error: {1}", this,
341                llvm::sys::StrError(error_value));
342       status = eConnectionStatusError;
343       break; // Break to close....
344     }
345 
346     return 0;
347   }
348   return bytes_read;
349 }
350 
351 size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len,
352                                        ConnectionStatus &status,
353                                        Status *error_ptr) {
354   Log *log = GetLog(LLDBLog::Connection);
355   LLDB_LOGF(log,
356             "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64
357             ")",
358             static_cast<void *>(this), static_cast<const void *>(src),
359             static_cast<uint64_t>(src_len));
360 
361   if (!IsConnected()) {
362     if (error_ptr)
363       *error_ptr = Status::FromErrorString("not connected");
364     status = eConnectionStatusNoConnection;
365     return 0;
366   }
367 
368   if (m_shutting_down) {
369     if (error_ptr)
370       *error_ptr = Status::FromErrorString("shutting down");
371     status = eConnectionStatusError;
372     return 0;
373   }
374 
375   Status error;
376 
377   size_t bytes_sent = src_len;
378   error = m_io_sp->Write(src, bytes_sent);
379 
380   if (log) {
381     LLDB_LOGF(log,
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());
388   }
389 
390   if (error_ptr)
391     *error_ptr = error.Clone();
392 
393   if (error.Fail()) {
394     switch (error.GetError()) {
395     case EAGAIN:
396     case EINTR:
397       status = eConnectionStatusSuccess;
398       return 0;
399 
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....
405 
406     default:
407       status = eConnectionStatusError;
408       break; // Break to close....
409     }
410 
411     return 0;
412   }
413 
414   status = eConnectionStatusSuccess;
415   return bytes_sent;
416 }
417 
418 std::string ConnectionFileDescriptor::GetURI() { return m_uri; }
419 
420 // This ConnectionFileDescriptor::BytesAvailable() uses select() via
421 // SelectHelper
422 //
423 // PROS:
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.
428 // CONS:
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.
434 
435 ConnectionStatus
436 ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,
437                                          Status *error_ptr) {
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
440   // well.
441 
442   Log *log = GetLog(LLDBLog::Connection);
443   LLDB_LOG(log, "this = {0}, timeout = {1}", this, timeout);
444 
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();
450 
451   if (handle != IOObject::kInvalidHandleValue) {
452     SelectHelper select_helper;
453     if (timeout)
454       select_helper.SetTimeout(*timeout);
455 
456     select_helper.FDSetRead(handle);
457 #if defined(_WIN32)
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
461     // an error.
462     const bool have_pipe_fd = false;
463 #else
464     const bool have_pipe_fd = pipe_fd >= 0;
465 #endif
466     if (have_pipe_fd)
467       select_helper.FDSetRead(pipe_fd);
468 
469     while (handle == m_io_sp->GetWaitableHandle()) {
470 
471       Status error = select_helper.Select();
472 
473       if (error_ptr)
474         *error_ptr = error.Clone();
475 
476       if (error.Fail()) {
477         switch (error.GetError()) {
478         case EBADF: // One of the descriptor sets specified an invalid
479                     // descriptor.
480           return eConnectionStatusLostConnection;
481 
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;
486 
487         case ETIMEDOUT:
488           return eConnectionStatusTimedOut;
489 
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
496         }
497       } else {
498         if (select_helper.FDIsSetRead(handle))
499           return eConnectionStatusSuccess;
500 
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:
504           char c;
505 
506           ssize_t bytes_read =
507               llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1);
508           assert(bytes_read == 1);
509           UNUSED_IF_ASSERT_DISABLED(bytes_read);
510           switch (c) {
511           case 'q':
512             LLDB_LOGF(log,
513                       "%p ConnectionFileDescriptor::BytesAvailable() "
514                       "got data: %c from the command channel.",
515                       static_cast<void *>(this), c);
516             return eConnectionStatusEndOfFile;
517           case 'i':
518             // Interrupt the current read
519             return eConnectionStatusInterrupted;
520           }
521         }
522       }
523     }
524   }
525 
526   if (error_ptr)
527     *error_ptr = Status::FromErrorString("not connected");
528   return eConnectionStatusLostConnection;
529 }
530 
531 lldb::ConnectionStatus ConnectionFileDescriptor::AcceptSocket(
532     Socket::SocketProtocol socket_protocol, llvm::StringRef socket_name,
533     llvm::function_ref<void(Socket &)> post_listen_callback,
534     Status *error_ptr) {
535   Status error;
536   std::unique_ptr<Socket> listening_socket =
537       Socket::Create(socket_protocol, error);
538   Socket *accepted_socket;
539 
540   if (!error.Fail())
541     error = listening_socket->Listen(socket_name, 5);
542 
543   if (!error.Fail()) {
544     post_listen_callback(*listening_socket);
545     error = listening_socket->Accept(/*timeout=*/std::nullopt, accepted_socket);
546   }
547 
548   if (!error.Fail()) {
549     m_io_sp.reset(accepted_socket);
550     m_uri.assign(socket_name.str());
551     return eConnectionStatusSuccess;
552   }
553 
554   if (error_ptr)
555     *error_ptr = error.Clone();
556   return eConnectionStatusError;
557 }
558 
559 lldb::ConnectionStatus
560 ConnectionFileDescriptor::ConnectSocket(Socket::SocketProtocol socket_protocol,
561                                         llvm::StringRef socket_name,
562                                         Status *error_ptr) {
563   Status error;
564   std::unique_ptr<Socket> socket = Socket::Create(socket_protocol, error);
565 
566   if (!error.Fail())
567     error = socket->Connect(socket_name);
568 
569   if (!error.Fail()) {
570     m_io_sp = std::move(socket);
571     m_uri.assign(socket_name.str());
572     return eConnectionStatusSuccess;
573   }
574 
575   if (error_ptr)
576     *error_ptr = error.Clone();
577   return eConnectionStatusError;
578 }
579 
580 ConnectionStatus ConnectionFileDescriptor::AcceptNamedSocket(
581     llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,
582     Status *error_ptr) {
583   return AcceptSocket(
584       Socket::ProtocolUnixDomain, socket_name,
585       [socket_id_callback, socket_name](Socket &listening_socket) {
586         socket_id_callback(socket_name);
587       },
588       error_ptr);
589 }
590 
591 ConnectionStatus ConnectionFileDescriptor::ConnectNamedSocket(
592     llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,
593     Status *error_ptr) {
594   return ConnectSocket(Socket::ProtocolUnixDomain, socket_name, error_ptr);
595 }
596 
597 ConnectionStatus ConnectionFileDescriptor::AcceptAbstractSocket(
598     llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,
599     Status *error_ptr) {
600   return AcceptSocket(
601       Socket::ProtocolUnixAbstract, socket_name,
602       [socket_id_callback, socket_name](Socket &listening_socket) {
603         socket_id_callback(socket_name);
604       },
605       error_ptr);
606 }
607 
608 lldb::ConnectionStatus ConnectionFileDescriptor::ConnectAbstractSocket(
609     llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,
610     Status *error_ptr) {
611   return ConnectSocket(Socket::ProtocolUnixAbstract, socket_name, error_ptr);
612 }
613 
614 ConnectionStatus
615 ConnectionFileDescriptor::AcceptTCP(llvm::StringRef socket_name,
616                                     socket_id_callback_type socket_id_callback,
617                                     Status *error_ptr) {
618   ConnectionStatus ret = AcceptSocket(
619       Socket::ProtocolTcp, socket_name,
620       [socket_id_callback](Socket &listening_socket) {
621         uint16_t port =
622             static_cast<TCPSocket &>(listening_socket).GetLocalPortNumber();
623         socket_id_callback(std::to_string(port));
624       },
625       error_ptr);
626   if (ret == eConnectionStatusSuccess)
627     m_uri.assign(
628         static_cast<TCPSocket *>(m_io_sp.get())->GetRemoteConnectionURI());
629   return ret;
630 }
631 
632 ConnectionStatus
633 ConnectionFileDescriptor::ConnectTCP(llvm::StringRef socket_name,
634                                      socket_id_callback_type socket_id_callback,
635                                      Status *error_ptr) {
636   return ConnectSocket(Socket::ProtocolTcp, socket_name, error_ptr);
637 }
638 
639 ConnectionStatus
640 ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s,
641                                      socket_id_callback_type socket_id_callback,
642                                      Status *error_ptr) {
643   if (error_ptr)
644     *error_ptr = Status();
645   llvm::Expected<std::unique_ptr<UDPSocket>> socket = Socket::UdpConnect(s);
646   if (!socket) {
647     if (error_ptr)
648       *error_ptr = Status::FromError(socket.takeError());
649     else
650       LLDB_LOG_ERROR(GetLog(LLDBLog::Connection), socket.takeError(),
651                      "tcp connect failed: {0}");
652     return eConnectionStatusError;
653   }
654   m_io_sp = std::move(*socket);
655   m_uri.assign(std::string(s));
656   return eConnectionStatusSuccess;
657 }
658 
659 ConnectionStatus
660 ConnectionFileDescriptor::ConnectFD(llvm::StringRef s,
661                                     socket_id_callback_type socket_id_callback,
662                                     Status *error_ptr) {
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).
666   int fd = -1;
667 
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.
672     errno = 0;
673     int flags = ::fcntl(fd, F_GETFL, 0);
674     if (flags == -1 || errno == EBADF) {
675       if (error_ptr)
676         *error_ptr = Status::FromErrorStringWithFormat(
677             "stale file descriptor: %s", s.str().c_str());
678       m_io_sp.reset();
679       return eConnectionStatusError;
680     } else {
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.
688 
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.
693       int resuse;
694       bool is_socket =
695           !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
696       if (is_socket)
697         m_io_sp = std::move(tcp_socket);
698       else
699         m_io_sp =
700             std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, false);
701       m_uri = s.str();
702       return eConnectionStatusSuccess;
703     }
704   }
705 
706   if (error_ptr)
707     *error_ptr = Status::FromErrorStringWithFormat(
708         "invalid file descriptor: \"%s\"", s.str().c_str());
709   m_io_sp.reset();
710   return eConnectionStatusError;
711 #endif // LLDB_ENABLE_POSIX
712   llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
713 }
714 
715 ConnectionStatus ConnectionFileDescriptor::ConnectFile(
716     llvm::StringRef s, socket_id_callback_type socket_id_callback,
717     Status *error_ptr) {
718 #if LLDB_ENABLE_POSIX
719   std::string addr_str = s.str();
720   // file:///PATH
721   int fd = FileSystem::Instance().Open(addr_str.c_str(), O_RDWR);
722   if (fd == -1) {
723     if (error_ptr)
724       *error_ptr = Status::FromErrno();
725     return eConnectionStatusError;
726   }
727 
728   if (::isatty(fd)) {
729     // Set up serial terminal emulation
730     struct termios options;
731     ::tcgetattr(fd, &options);
732 
733     // Set port speed to the available maximum
734 #ifdef B115200
735     ::cfsetospeed(&options, B115200);
736     ::cfsetispeed(&options, B115200);
737 #elif B57600
738     ::cfsetospeed(&options, B57600);
739     ::cfsetispeed(&options, B57600);
740 #elif B38400
741     ::cfsetospeed(&options, B38400);
742     ::cfsetispeed(&options, B38400);
743 #else
744 #error "Maximum Baud rate is Unknown"
745 #endif
746 
747     // Raw input, disable echo and signals
748     options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
749 
750     // Make sure only one character is needed to return from a read
751     options.c_cc[VMIN] = 1;
752     options.c_cc[VTIME] = 0;
753 
754     llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW, &options);
755   }
756 
757   m_io_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, true);
758   return eConnectionStatusSuccess;
759 #endif // LLDB_ENABLE_POSIX
760   llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
761 }
762 
763 ConnectionStatus ConnectionFileDescriptor::ConnectSerialPort(
764     llvm::StringRef s, socket_id_callback_type socket_id_callback,
765     Status *error_ptr) {
766 #if LLDB_ENABLE_POSIX
767   llvm::StringRef path, qs;
768   // serial:///PATH?k1=v1&k2=v2...
769   std::tie(path, qs) = s.split('?');
770 
771   llvm::Expected<SerialPort::Options> serial_options =
772       SerialPort::OptionsFromURL(qs);
773   if (!serial_options) {
774     if (error_ptr)
775       *error_ptr = Status::FromError(serial_options.takeError());
776     else
777       llvm::consumeError(serial_options.takeError());
778     return eConnectionStatusError;
779   }
780 
781   int fd = FileSystem::Instance().Open(path.str().c_str(), O_RDWR);
782   if (fd == -1) {
783     if (error_ptr)
784       *error_ptr = Status::FromErrno();
785     return eConnectionStatusError;
786   }
787 
788   llvm::Expected<std::unique_ptr<SerialPort>> serial_sp = SerialPort::Create(
789       fd, File::eOpenOptionReadWrite, serial_options.get(), true);
790   if (!serial_sp) {
791     if (error_ptr)
792       *error_ptr = Status::FromError(serial_sp.takeError());
793     else
794       llvm::consumeError(serial_sp.takeError());
795     return eConnectionStatusError;
796   }
797   m_io_sp = std::move(serial_sp.get());
798 
799   return eConnectionStatusSuccess;
800 #endif // LLDB_ENABLE_POSIX
801   llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
802 }
803 
804 void ConnectionFileDescriptor::InitializeSocket(Socket *socket) {
805   m_io_sp.reset(socket);
806   m_uri = socket->GetRemoteConnectionURI();
807 }
808