1 //===-- ConnectionFileDescriptorPosix.cpp -----------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #if defined(__APPLE__)
11 // Enable this special support for Apple builds where we can have unlimited
12 // select bounds. We tried switching to poll() and kqueue and we were panicing
13 // the kernel, so we have to stick with select for now.
14 #define _DARWIN_UNLIMITED_SELECT
15 #endif
16 
17 #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
18 #include "lldb/Host/Config.h"
19 #include "lldb/Host/IOObject.h"
20 #include "lldb/Host/SocketAddress.h"
21 #include "lldb/Host/Socket.h"
22 #include "lldb/Host/StringConvert.h"
23 #include "lldb/Utility/SelectHelper.h"
24 
25 // C Includes
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 
32 #ifndef LLDB_DISABLE_POSIX
33 #include <termios.h>
34 #endif
35 
36 // C++ Includes
37 #include <sstream>
38 
39 // Other libraries and framework includes
40 #include "llvm/Support/ErrorHandling.h"
41 #if defined(__APPLE__)
42 #include "llvm/ADT/SmallVector.h"
43 #endif
44 // Project includes
45 #include "lldb/Core/Communication.h"
46 #include "lldb/Core/Log.h"
47 #include "lldb/Core/StreamString.h"
48 #include "lldb/Core/Timer.h"
49 #include "lldb/Host/Host.h"
50 #include "lldb/Host/Socket.h"
51 #include "lldb/Host/common/TCPSocket.h"
52 #include "lldb/Interpreter/Args.h"
53 
54 using namespace lldb;
55 using namespace lldb_private;
56 
57 const char* ConnectionFileDescriptor::LISTEN_SCHEME = "listen";
58 const char* ConnectionFileDescriptor::ACCEPT_SCHEME = "accept";
59 const char* ConnectionFileDescriptor::UNIX_ACCEPT_SCHEME = "unix-accept";
60 const char* ConnectionFileDescriptor::CONNECT_SCHEME = "connect";
61 const char* ConnectionFileDescriptor::TCP_CONNECT_SCHEME = "tcp-connect";
62 const char* ConnectionFileDescriptor::UDP_SCHEME = "udp";
63 const char* ConnectionFileDescriptor::UNIX_CONNECT_SCHEME = "unix-connect";
64 const char* ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME = "unix-abstract-connect";
65 const char* ConnectionFileDescriptor::FD_SCHEME = "fd";
66 const char* ConnectionFileDescriptor::FILE_SCHEME = "file";
67 
68 namespace {
69 
70 const char*
71 GetURLAddress(const char *url, const char *scheme)
72 {
73     const auto prefix = std::string(scheme) + "://";
74     if (strstr(url, prefix.c_str()) != url)
75         return nullptr;
76 
77     return url + prefix.size();
78 }
79 
80 }
81 
82 ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit)
83     : Connection(),
84       m_pipe(),
85       m_mutex(),
86       m_shutting_down(false),
87       m_waiting_for_accept(false),
88       m_child_processes_inherit(child_processes_inherit)
89 {
90     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
91     if (log)
92         log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", static_cast<void *>(this));
93 }
94 
95 ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd)
96     : Connection(),
97       m_pipe(),
98       m_mutex(),
99       m_shutting_down(false),
100       m_waiting_for_accept(false),
101       m_child_processes_inherit(false)
102 {
103     m_write_sp.reset(new File(fd, owns_fd));
104     m_read_sp.reset(new File(fd, false));
105 
106     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
107     if (log)
108         log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)",
109                     static_cast<void *>(this), fd, owns_fd);
110     OpenCommandPipe();
111 }
112 
113 ConnectionFileDescriptor::ConnectionFileDescriptor(Socket *socket)
114     : Connection(),
115       m_pipe(),
116       m_mutex(),
117       m_shutting_down(false),
118       m_waiting_for_accept(false),
119       m_child_processes_inherit(false)
120 {
121     InitializeSocket(socket);
122 }
123 
124 ConnectionFileDescriptor::~ConnectionFileDescriptor()
125 {
126     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
127     if (log)
128         log->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", static_cast<void *>(this));
129     Disconnect(NULL);
130     CloseCommandPipe();
131 }
132 
133 void
134 ConnectionFileDescriptor::OpenCommandPipe()
135 {
136     CloseCommandPipe();
137 
138     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
139     // Make the command file descriptor here:
140     Error result = m_pipe.CreateNew(m_child_processes_inherit);
141     if (!result.Success())
142     {
143         if (log)
144             log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s", static_cast<void *>(this),
145                         result.AsCString());
146     }
147     else
148     {
149         if (log)
150             log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d", static_cast<void *>(this),
151                         m_pipe.GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor());
152     }
153 }
154 
155 void
156 ConnectionFileDescriptor::CloseCommandPipe()
157 {
158     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
159     if (log)
160         log->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()", static_cast<void *>(this));
161 
162     m_pipe.Close();
163 }
164 
165 bool
166 ConnectionFileDescriptor::IsConnected() const
167 {
168     return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid());
169 }
170 
171 ConnectionStatus
172 ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr)
173 {
174     std::lock_guard<std::recursive_mutex> guard(m_mutex);
175     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
176     if (log)
177         log->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')", static_cast<void *>(this), s);
178 
179     OpenCommandPipe();
180 
181     if (s && s[0])
182     {
183         const char *addr = nullptr;
184         if ((addr = GetURLAddress(s, LISTEN_SCHEME)))
185         {
186             // listen://HOST:PORT
187             return SocketListenAndAccept(addr, error_ptr);
188         }
189         else if ((addr = GetURLAddress(s, ACCEPT_SCHEME)))
190         {
191             // unix://SOCKNAME
192             return NamedSocketAccept(addr, error_ptr);
193         }
194         else if ((addr = GetURLAddress(s, UNIX_ACCEPT_SCHEME)))
195         {
196             // unix://SOCKNAME
197             return NamedSocketAccept(addr, error_ptr);
198         }
199         else if ((addr = GetURLAddress(s, CONNECT_SCHEME)))
200         {
201             return ConnectTCP(addr, error_ptr);
202         }
203         else if ((addr = GetURLAddress(s, TCP_CONNECT_SCHEME)))
204         {
205             return ConnectTCP(addr, error_ptr);
206         }
207         else if ((addr = GetURLAddress(s, UDP_SCHEME)))
208         {
209             return ConnectUDP(addr, error_ptr);
210         }
211         else if ((addr = GetURLAddress(s, UNIX_CONNECT_SCHEME)))
212         {
213             // unix-connect://SOCKNAME
214             return NamedSocketConnect(addr, error_ptr);
215         }
216         else if ((addr = GetURLAddress(s, UNIX_ABSTRACT_CONNECT_SCHEME)))
217         {
218             // unix-abstract-connect://SOCKNAME
219             return UnixAbstractSocketConnect(addr, error_ptr);
220         }
221 #ifndef LLDB_DISABLE_POSIX
222         else if ((addr = GetURLAddress(s, FD_SCHEME)))
223         {
224             // Just passing a native file descriptor within this current process
225             // that is already opened (possibly from a service or other source).
226             bool success = false;
227             int fd = StringConvert::ToSInt32(addr, -1, 0, &success);
228 
229             if (success)
230             {
231                 // We have what looks to be a valid file descriptor, but we
232                 // should make sure it is. We currently are doing this by trying to
233                 // get the flags from the file descriptor and making sure it
234                 // isn't a bad fd.
235                 errno = 0;
236                 int flags = ::fcntl(fd, F_GETFL, 0);
237                 if (flags == -1 || errno == EBADF)
238                 {
239                     if (error_ptr)
240                         error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", s);
241                     m_read_sp.reset();
242                     m_write_sp.reset();
243                     return eConnectionStatusError;
244                 }
245                 else
246                 {
247                     // Don't take ownership of a file descriptor that gets passed
248                     // to us since someone else opened the file descriptor and
249                     // handed it to us.
250                     // TODO: Since are using a URL to open connection we should
251                     // eventually parse options using the web standard where we
252                     // have "fd://123?opt1=value;opt2=value" and we can have an
253                     // option be "owns=1" or "owns=0" or something like this to
254                     // allow us to specify this. For now, we assume we must
255                     // assume we don't own it.
256 
257                     std::unique_ptr<TCPSocket> tcp_socket;
258                     tcp_socket.reset(new TCPSocket(fd, false));
259                     // Try and get a socket option from this file descriptor to
260                     // see if this is a socket and set m_is_socket accordingly.
261                     int resuse;
262                     bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
263                     if (is_socket)
264                     {
265                         m_read_sp = std::move(tcp_socket);
266                         m_write_sp = m_read_sp;
267                     }
268                     else
269                     {
270                         m_read_sp.reset(new File(fd, false));
271                         m_write_sp.reset(new File(fd, false));
272                     }
273                     m_uri.assign(addr);
274                     return eConnectionStatusSuccess;
275                 }
276             }
277 
278             if (error_ptr)
279                 error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"", s);
280             m_read_sp.reset();
281             m_write_sp.reset();
282             return eConnectionStatusError;
283         }
284         else if ((addr = GetURLAddress(s, FILE_SCHEME)))
285         {
286             // file:///PATH
287             const char *path = addr;
288             int fd = -1;
289             do
290             {
291                 fd = ::open(path, O_RDWR);
292             } while (fd == -1 && errno == EINTR);
293 
294             if (fd == -1)
295             {
296                 if (error_ptr)
297                     error_ptr->SetErrorToErrno();
298                 return eConnectionStatusError;
299             }
300 
301             if (::isatty(fd))
302             {
303                 // Set up serial terminal emulation
304                 struct termios options;
305                 ::tcgetattr(fd, &options);
306 
307                 // Set port speed to maximum
308                 ::cfsetospeed(&options, B115200);
309                 ::cfsetispeed(&options, B115200);
310 
311                 // Raw input, disable echo and signals
312                 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
313 
314                 // Make sure only one character is needed to return from a read
315                 options.c_cc[VMIN] = 1;
316                 options.c_cc[VTIME] = 0;
317 
318                 ::tcsetattr(fd, TCSANOW, &options);
319             }
320 
321             int flags = ::fcntl(fd, F_GETFL, 0);
322             if (flags >= 0)
323             {
324                 if ((flags & O_NONBLOCK) == 0)
325                 {
326                     flags |= O_NONBLOCK;
327                     ::fcntl(fd, F_SETFL, flags);
328                 }
329             }
330             m_read_sp.reset(new File(fd, true));
331             m_write_sp.reset(new File(fd, false));
332             return eConnectionStatusSuccess;
333         }
334 #endif
335         if (error_ptr)
336             error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", s);
337         return eConnectionStatusError;
338     }
339     if (error_ptr)
340         error_ptr->SetErrorString("invalid connect arguments");
341     return eConnectionStatusError;
342 }
343 
344 bool
345 ConnectionFileDescriptor::InterruptRead()
346 {
347     size_t bytes_written = 0;
348     Error result = m_pipe.Write("i", 1, bytes_written);
349     return result.Success();
350 }
351 
352 ConnectionStatus
353 ConnectionFileDescriptor::Disconnect(Error *error_ptr)
354 {
355     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
356     if (log)
357         log->Printf("%p ConnectionFileDescriptor::Disconnect ()", static_cast<void *>(this));
358 
359     ConnectionStatus status = eConnectionStatusSuccess;
360 
361     if (!IsConnected())
362     {
363         if (log)
364             log->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", static_cast<void *>(this));
365         return eConnectionStatusSuccess;
366     }
367 
368     if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
369         static_cast<Socket &>(*m_read_sp).PreDisconnect();
370 
371     // Try to get the ConnectionFileDescriptor's mutex.  If we fail, that is quite likely
372     // because somebody is doing a blocking read on our file descriptor.  If that's the case,
373     // then send the "q" char to the command file channel so the read will wake up and the connection
374     // will then know to shut down.
375 
376     m_shutting_down = true;
377 
378     std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);
379     if (!locker.try_lock())
380     {
381         if (m_pipe.CanWrite())
382         {
383             size_t bytes_written = 0;
384             Error result = m_pipe.Write("q", 1, bytes_written);
385             if (log)
386                 log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, error = '%s'.",
387                             static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString());
388         }
389         else if (log)
390         {
391             log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.",
392                         static_cast<void *>(this));
393         }
394         locker.lock();
395     }
396 
397     Error error = m_read_sp->Close();
398     Error error2 = m_write_sp->Close();
399     if (error.Fail() || error2.Fail())
400         status = eConnectionStatusError;
401     if (error_ptr)
402         *error_ptr = error.Fail() ? error : error2;
403 
404     // Close any pipes we were using for async interrupts
405     m_pipe.Close();
406 
407     m_uri.clear();
408     m_shutting_down = false;
409     return status;
410 }
411 
412 size_t
413 ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
414 {
415     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
416 
417     std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);
418     if (!locker.try_lock())
419     {
420         if (log)
421             log->Printf("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void *>(this));
422         if (error_ptr)
423             error_ptr->SetErrorString("failed to get the connection lock for read.");
424 
425         status = eConnectionStatusTimedOut;
426         return 0;
427     }
428 
429     if (m_shutting_down)
430     {
431         status = eConnectionStatusError;
432         return 0;
433     }
434 
435     status = BytesAvailable(timeout_usec, error_ptr);
436     if (status != eConnectionStatusSuccess)
437         return 0;
438 
439     Error error;
440     size_t bytes_read = dst_len;
441     error = m_read_sp->Read(dst, bytes_read);
442 
443     if (log)
444     {
445         log->Printf("%p ConnectionFileDescriptor::Read()  fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
446                     static_cast<void *>(this), static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), static_cast<void *>(dst),
447                     static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString());
448     }
449 
450     if (bytes_read == 0)
451     {
452         error.Clear(); // End-of-file.  Do not automatically close; pass along for the end-of-file handlers.
453         status = eConnectionStatusEndOfFile;
454     }
455 
456     if (error_ptr)
457         *error_ptr = error;
458 
459     if (error.Fail())
460     {
461         uint32_t error_value = error.GetError();
462         switch (error_value)
463         {
464             case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
465                 if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
466                     status = eConnectionStatusTimedOut;
467                 else
468                     status = eConnectionStatusSuccess;
469                 return 0;
470 
471             case EFAULT:  // Buf points outside the allocated address space.
472             case EINTR:   // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
473             case EINVAL:  // The pointer associated with fildes was negative.
474             case EIO:     // An I/O error occurred while reading from the file system.
475                           // The process group is orphaned.
476                           // The file is a regular file, nbyte is greater than 0,
477                           // the starting position is before the end-of-file, and
478                           // the starting position is greater than or equal to the
479                           // offset maximum established for the open file
480                           // descriptor associated with fildes.
481             case EISDIR:  // An attempt is made to read a directory.
482             case ENOBUFS: // An attempt to allocate a memory buffer fails.
483             case ENOMEM:  // Insufficient memory is available.
484                 status = eConnectionStatusError;
485                 break; // Break to close....
486 
487             case ENOENT:     // no such file or directory
488             case EBADF:      // fildes is not a valid file or socket descriptor open for reading.
489             case ENXIO:      // An action is requested of a device that does not exist..
490                              // A requested action cannot be performed by the device.
491             case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
492             case ENOTCONN:   // A read is attempted on an unconnected socket.
493                 status = eConnectionStatusLostConnection;
494                 break; // Break to close....
495 
496             case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
497                 status = eConnectionStatusTimedOut;
498                 return 0;
499 
500             default:
501                 if (log)
502                     log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", static_cast<void *>(this),
503                                 strerror(error_value));
504                 status = eConnectionStatusError;
505                 break; // Break to close....
506         }
507 
508         return 0;
509     }
510     return bytes_read;
511 }
512 
513 size_t
514 ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
515 {
516     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
517     if (log)
518         log->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void *>(this),
519                     static_cast<const void *>(src), static_cast<uint64_t>(src_len));
520 
521     if (!IsConnected())
522     {
523         if (error_ptr)
524             error_ptr->SetErrorString("not connected");
525         status = eConnectionStatusNoConnection;
526         return 0;
527     }
528 
529     Error error;
530 
531     size_t bytes_sent = src_len;
532     error = m_write_sp->Write(src, bytes_sent);
533 
534     if (log)
535     {
536         log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
537                     static_cast<void *>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void *>(src),
538                     static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString());
539     }
540 
541     if (error_ptr)
542         *error_ptr = error;
543 
544     if (error.Fail())
545     {
546         switch (error.GetError())
547         {
548             case EAGAIN:
549             case EINTR:
550                 status = eConnectionStatusSuccess;
551                 return 0;
552 
553             case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
554             case ENOTCONN:   // A read is attempted on an unconnected socket.
555                 status = eConnectionStatusLostConnection;
556                 break; // Break to close....
557 
558             default:
559                 status = eConnectionStatusError;
560                 break; // Break to close....
561         }
562 
563         return 0;
564     }
565 
566     status = eConnectionStatusSuccess;
567     return bytes_sent;
568 }
569 
570 std::string
571 ConnectionFileDescriptor::GetURI()
572 {
573     return m_uri;
574 }
575 
576 // This ConnectionFileDescriptor::BytesAvailable() uses select() via SelectHelper
577 //
578 // PROS:
579 //  - select is consistent across most unix platforms
580 //  - The Apple specific version allows for unlimited fds in the fd_sets by
581 //    setting the _DARWIN_UNLIMITED_SELECT define prior to including the
582 //    required header files.
583 // CONS:
584 //  - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE.
585 //     This implementation  will assert if it runs into that hard limit to let
586 //     users know that another ConnectionFileDescriptor::BytesAvailable() should
587 //     be used or a new version of ConnectionFileDescriptor::BytesAvailable()
588 //     should be written for the system that is running into the limitations.
589 
590 
591 ConnectionStatus
592 ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr)
593 {
594     // Don't need to take the mutex here separately since we are only called from Read.  If we
595     // ever get used more generally we will need to lock here as well.
596 
597     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION));
598     if (log)
599         log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", static_cast<void *>(this), timeout_usec);
600 
601 
602     // Make a copy of the file descriptors to make sure we don't
603     // have another thread change these values out from under us
604     // and cause problems in the loop below where like in FS_SET()
605     const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle();
606     const int pipe_fd = m_pipe.GetReadFileDescriptor();
607 
608 
609     if (handle != IOObject::kInvalidHandleValue)
610     {
611         SelectHelper select_helper;
612         if (timeout_usec != UINT32_MAX)
613             select_helper.SetTimeout(std::chrono::microseconds(timeout_usec));
614 
615         select_helper.FDSetRead(handle);
616 #if defined(_MSC_VER)
617         // select() won't accept pipes on Windows.  The entire Windows codepath needs to be
618         // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least
619         // this will allow ::select() to not return an error.
620         const bool have_pipe_fd = false;
621 #else
622         const bool have_pipe_fd = pipe_fd >= 0;
623 #endif
624         if (have_pipe_fd)
625             select_helper.FDSetRead(pipe_fd);
626 
627         while (handle == m_read_sp->GetWaitableHandle())
628         {
629 
630             Error error = select_helper.Select();
631 
632             if (error_ptr)
633                 *error_ptr = error;
634 
635             if (error.Fail())
636             {
637                 switch (error.GetError())
638                 {
639                     case EBADF: // One of the descriptor sets specified an invalid descriptor.
640                         return eConnectionStatusLostConnection;
641 
642                     case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
643                     default:     // Other unknown error
644                         return eConnectionStatusError;
645 
646                     case ETIMEDOUT:
647                         return eConnectionStatusTimedOut;
648 
649                     case EAGAIN: // The kernel was (perhaps temporarily) unable to
650                                  // allocate the requested number of file descriptors,
651                                  // or we have non-blocking IO
652                     case EINTR:  // A signal was delivered before the time limit
653                         // expired and before any of the selected events
654                         // occurred.
655                         break; // Lets keep reading to until we timeout
656                 }
657             }
658             else
659             {
660                 if (select_helper.FDIsSetRead(handle))
661                     return eConnectionStatusSuccess;
662 
663                 if (select_helper.FDIsSetRead(pipe_fd))
664                 {
665                     // There is an interrupt or exit command in the command pipe
666                     // Read the data from that pipe:
667                     char buffer[1];
668 
669                     ssize_t bytes_read;
670 
671                     do
672                     {
673                         bytes_read = ::read(pipe_fd, buffer, sizeof(buffer));
674                     } while (bytes_read < 0 && errno == EINTR);
675 
676                     switch (buffer[0])
677                     {
678                         case 'q':
679                             if (log)
680                                 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() "
681                                             "got data: %c from the command channel.",
682                                             static_cast<void *>(this), buffer[0]);
683                             return eConnectionStatusEndOfFile;
684                         case 'i':
685                             // Interrupt the current read
686                             return eConnectionStatusInterrupted;
687                     }
688                 }
689             }
690         }
691     }
692 
693     if (error_ptr)
694         error_ptr->SetErrorString("not connected");
695     return eConnectionStatusLostConnection;
696 }
697 
698 ConnectionStatus
699 ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *error_ptr)
700 {
701     Socket *socket = nullptr;
702     Error error = Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket);
703     if (error_ptr)
704         *error_ptr = error;
705     m_write_sp.reset(socket);
706     m_read_sp = m_write_sp;
707     if (error.Fail())
708     {
709         return eConnectionStatusError;
710     }
711     m_uri.assign(socket_name);
712     return eConnectionStatusSuccess;
713 }
714 
715 ConnectionStatus
716 ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *error_ptr)
717 {
718     Socket *socket = nullptr;
719     Error error = Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket);
720     if (error_ptr)
721         *error_ptr = error;
722     m_write_sp.reset(socket);
723     m_read_sp = m_write_sp;
724     if (error.Fail())
725     {
726         return eConnectionStatusError;
727     }
728     m_uri.assign(socket_name);
729     return eConnectionStatusSuccess;
730 }
731 
732 lldb::ConnectionStatus
733 ConnectionFileDescriptor::UnixAbstractSocketConnect(const char *socket_name, Error *error_ptr)
734 {
735     Socket *socket = nullptr;
736     Error error = Socket::UnixAbstractConnect(socket_name, m_child_processes_inherit, socket);
737     if (error_ptr)
738         *error_ptr = error;
739     m_write_sp.reset(socket);
740     m_read_sp = m_write_sp;
741     if (error.Fail())
742     {
743         return eConnectionStatusError;
744     }
745     m_uri.assign(socket_name);
746     return eConnectionStatusSuccess;
747 }
748 
749 ConnectionStatus
750 ConnectionFileDescriptor::SocketListenAndAccept(const char *s, Error *error_ptr)
751 {
752     m_port_predicate.SetValue(0, eBroadcastNever);
753 
754     Socket *socket = nullptr;
755     m_waiting_for_accept = true;
756     Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, &m_port_predicate);
757     if (error_ptr)
758         *error_ptr = error;
759     if (error.Fail())
760         return eConnectionStatusError;
761 
762     std::unique_ptr<Socket> listening_socket_up;
763 
764     listening_socket_up.reset(socket);
765     socket = nullptr;
766     error = listening_socket_up->Accept(s, m_child_processes_inherit, socket);
767     listening_socket_up.reset();
768     if (error_ptr)
769         *error_ptr = error;
770     if (error.Fail())
771         return eConnectionStatusError;
772 
773     InitializeSocket(socket);
774     return eConnectionStatusSuccess;
775 }
776 
777 ConnectionStatus
778 ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr)
779 {
780     Socket *socket = nullptr;
781     Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket);
782     if (error_ptr)
783         *error_ptr = error;
784     m_write_sp.reset(socket);
785     m_read_sp = m_write_sp;
786     if (error.Fail())
787     {
788         return eConnectionStatusError;
789     }
790     m_uri.assign(s);
791     return eConnectionStatusSuccess;
792 }
793 
794 ConnectionStatus
795 ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr)
796 {
797     Socket *send_socket = nullptr;
798     Socket *recv_socket = nullptr;
799     Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, recv_socket);
800     if (error_ptr)
801         *error_ptr = error;
802     m_write_sp.reset(send_socket);
803     m_read_sp.reset(recv_socket);
804     if (error.Fail())
805     {
806         return eConnectionStatusError;
807     }
808     m_uri.assign(s);
809     return eConnectionStatusSuccess;
810 }
811 
812 uint16_t
813 ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec)
814 {
815     uint16_t bound_port = 0;
816     if (timeout_sec == UINT32_MAX)
817         m_port_predicate.WaitForValueNotEqualTo(0, bound_port);
818     else
819         m_port_predicate.WaitForValueNotEqualTo(0, bound_port, std::chrono::seconds(timeout_sec));
820     return bound_port;
821 }
822 
823 bool
824 ConnectionFileDescriptor::GetChildProcessesInherit() const
825 {
826     return m_child_processes_inherit;
827 }
828 
829 void
830 ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit)
831 {
832     m_child_processes_inherit = child_processes_inherit;
833 }
834 
835 void
836 ConnectionFileDescriptor::InitializeSocket(Socket* socket)
837 {
838     assert(socket->GetSocketProtocol() == Socket::ProtocolTcp);
839     TCPSocket* tcp_socket = static_cast<TCPSocket*>(socket);
840 
841     m_write_sp.reset(socket);
842     m_read_sp = m_write_sp;
843     StreamString strm;
844     strm.Printf("connect://%s:%u",tcp_socket->GetRemoteIPAddress().c_str(), tcp_socket->GetRemotePortNumber());
845     m_uri.swap(strm.GetString());
846 }
847