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