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