ConnectionFileDescriptor.cpp revision e005f2ce03c489ebde9110678a29cbfe8488d5b4
1//===-- ConnectionFileDescriptor.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#include "lldb/Core/ConnectionFileDescriptor.h"
11
12// C Includes
13#include <arpa/inet.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <netdb.h>
17#include <netinet/in.h>
18#include <netinet/tcp.h>
19#include <sys/socket.h>
20#include <sys/types.h>
21#include <sys/un.h>
22#include <string.h>
23#include <stdlib.h>
24
25// C++ Includes
26// Other libraries and framework includes
27// Project includes
28#include "lldb/lldb-private-log.h"
29#include "lldb/Interpreter/Args.h"
30#include "lldb/Core/Communication.h"
31#include "lldb/Core/Log.h"
32#include "lldb/Core/RegularExpression.h"
33#include "lldb/Core/Timer.h"
34
35using namespace lldb;
36using namespace lldb_private;
37
38ConnectionFileDescriptor::ConnectionFileDescriptor () :
39    Connection(),
40    m_fd (-1),
41    m_should_close_fd (false)
42{
43    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION |  LIBLLDB_LOG_OBJECT,
44                                 "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
45                                 this);
46}
47
48ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
49    Connection(),
50    m_fd (fd),
51    m_should_close_fd (owns_fd)
52{
53    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION |  LIBLLDB_LOG_OBJECT,
54                                 "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)",
55                                 this, fd, owns_fd);
56}
57
58
59ConnectionFileDescriptor::~ConnectionFileDescriptor ()
60{
61    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION |  LIBLLDB_LOG_OBJECT,
62                                 "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
63                                 this);
64    Disconnect (NULL);
65}
66
67bool
68ConnectionFileDescriptor::IsConnected () const
69{
70    return m_fd >= 0;
71}
72
73ConnectionStatus
74ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
75{
76    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
77                                 "%p ConnectionFileDescriptor::Connect (url = '%s')",
78                                 this, s);
79
80    if (s && s[0])
81    {
82        char *end = NULL;
83        if (strstr(s, "listen://"))
84        {
85            // listen://HOST:PORT
86            unsigned long listen_port = ::strtoul(s + strlen("listen://"), &end, 0);
87            return SocketListen (listen_port, error_ptr);
88        }
89        else if (strstr(s, "unix-accept://"))
90        {
91            // unix://SOCKNAME
92            return NamedSocketAccept (s + strlen("unix-accept://"), error_ptr);
93        }
94        else if (strstr(s, "connect://"))
95        {
96            return SocketConnect (s + strlen("connect://"), error_ptr);
97        }
98        else if (strstr(s, "file://"))
99        {
100            // file:///PATH
101            const char *path = s + strlen("file://");
102            m_fd = ::open (path, O_RDWR);
103            if (m_fd == -1)
104            {
105                if (error_ptr)
106                    error_ptr->SetErrorToErrno();
107                return eConnectionStatusError;
108            }
109
110            int flags = ::fcntl (m_fd, F_GETFL, 0);
111            if (flags >= 0)
112            {
113                if ((flags & O_NONBLOCK) == 0)
114                {
115                    flags |= O_NONBLOCK;
116                    ::fcntl (m_fd, F_SETFL, flags);
117                }
118            }
119            m_should_close_fd = true;
120            return eConnectionStatusSuccess;
121        }
122        if (error_ptr)
123            error_ptr->SetErrorStringWithFormat ("Unsupported connection URL: '%s'.\n", s);
124        return eConnectionStatusError;
125    }
126    if (error_ptr)
127        error_ptr->SetErrorString("NULL connection URL.");
128    return eConnectionStatusError;
129}
130
131ConnectionStatus
132ConnectionFileDescriptor::Disconnect (Error *error_ptr)
133{
134    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
135                                 "%p ConnectionFileDescriptor::Disconnect ()",
136                                 this);
137    if (m_should_close_fd == false)
138    {
139        m_fd = -1;
140        return eConnectionStatusSuccess;
141    }
142    return Close (m_fd, error_ptr);
143}
144
145size_t
146ConnectionFileDescriptor::Read (void *dst, size_t dst_len, ConnectionStatus &status, Error *error_ptr)
147{
148    LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
149    if (log)
150        log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu)...",
151                     this, m_fd, dst, dst_len);
152
153    Error error;
154    ssize_t bytes_read = ::read (m_fd, dst, dst_len);
155    if (bytes_read == 0)
156    {
157        error.SetErrorStringWithFormat("End-of-file.\n");
158        status = eConnectionStatusLostConnection;
159    }
160    else if (bytes_read < 0)
161    {
162        error.SetErrorToErrno();
163    }
164    else
165    {
166        error.Clear();
167    }
168
169    if (log)
170        log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu) => %zi, error = %s",
171                     this,
172                     m_fd,
173                     dst,
174                     dst_len,
175                     bytes_read,
176                     error.AsCString());
177
178    if (error_ptr)
179        *error_ptr = error;
180
181    if (error.Fail())
182    {
183        uint32_t error_value = error.GetError();
184        switch (error_value)
185        {
186        case EAGAIN:    // The file was marked for non-blocking I/O, and no data were ready to be read.
187            status = eConnectionStatusSuccess;
188            return 0;
189
190        case EBADF:     // fildes is not a valid file or socket descriptor open for reading.
191        case EFAULT:    // Buf points outside the allocated address space.
192        case EINTR:     // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
193        case EINVAL:    // The pointer associated with fildes was negative.
194        case EIO:       // An I/O error occurred while reading from the file system.
195                        // The process group is orphaned.
196                        // The file is a regular file, nbyte is greater than 0,
197                        // the starting position is before the end-of-file, and
198                        // the starting position is greater than or equal to the
199                        // offset maximum established for the open file
200                        // descriptor associated with fildes.
201        case EISDIR:    // An attempt is made to read a directory.
202        case ENOBUFS:   // An attempt to allocate a memory buffer fails.
203        case ENOMEM:    // Insufficient memory is available.
204            status = eConnectionStatusError;
205            break;  // Break to close....
206
207        case ENXIO:     // An action is requested of a device that does not exist..
208                        // A requested action cannot be performed by the device.
209        case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
210        case ENOTCONN:  // A read is attempted on an unconnected socket.
211            status = eConnectionStatusLostConnection;
212            break;  // Break to close....
213
214        case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
215            status = eConnectionStatusTimedOut;
216            return 0;
217        }
218
219//      if (log)
220//          error->Log(log, "::read ( %i, %p, %zu ) => %i", m_fd, dst, dst_len, bytesread);
221        Close (m_fd, NULL);
222        return 0;
223    }
224    return bytes_read;
225}
226
227size_t
228ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
229{
230    LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
231    if (log)
232        log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %zu)", this, src, src_len);
233
234    if (!IsConnected ())
235    {
236        if (error_ptr)
237            error_ptr->SetErrorString("Not connected.");
238        status = eConnectionStatusNoConnection;
239        return 0;
240    }
241
242
243    Error error;
244
245    ssize_t bytes_sent = 0;
246
247    if (m_is_socket)
248        bytes_sent = ::send (m_fd, src, src_len, 0);
249    else
250        bytes_sent = ::write (m_fd, src, src_len);
251
252    if (bytes_sent < 0)
253        error.SetErrorToErrno ();
254    else
255        error.Clear ();
256
257    if (log)
258    {
259        if (m_is_socket)
260            log->Printf ("%p ConnectionFileDescriptor::Write()  ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)",
261                         this, m_fd, src, src_len, bytes_sent, error.AsCString());
262        else
263            log->Printf ("%p ConnectionFileDescriptor::Write()  ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)",
264                         this, m_fd, src, src_len, bytes_sent, error.AsCString());
265    }
266
267    if (error_ptr)
268        *error_ptr = error;
269
270    if (error.Fail())
271    {
272        switch (error.GetError())
273        {
274        case EAGAIN:
275        case EINTR:
276            status = eConnectionStatusSuccess;
277            return 0;
278
279        case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
280        case ENOTCONN:  // A read is attempted on an unconnected socket.
281            status = eConnectionStatusLostConnection;
282            break;  // Break to close....
283
284        default:
285            status = eConnectionStatusError;
286            break;  // Break to close....
287        }
288
289        Close (m_fd, NULL);
290        return 0;
291    }
292
293    status = eConnectionStatusSuccess;
294    return bytes_sent;
295}
296
297ConnectionStatus
298ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
299{
300    LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
301    if (log)
302        log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
303    struct timeval *tv_ptr;
304    struct timeval tv;
305    if (timeout_usec == UINT32_MAX)
306    {
307        // Infinite wait...
308        tv_ptr = NULL;
309    }
310    else
311    {
312        TimeValue time_value;
313        time_value.OffsetWithMicroSeconds (timeout_usec);
314        tv = time_value.GetAsTimeVal();
315        tv_ptr = &tv;
316    }
317
318    while (IsConnected())
319    {
320        fd_set read_fds;
321        FD_ZERO (&read_fds);
322        FD_SET (m_fd, &read_fds);
323        int nfds = m_fd + 1;
324
325        Error error;
326
327
328        log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION);
329        if (log)
330            log->Printf("%p ConnectionFileDescriptor::Write()  ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...",
331                        this, nfds, m_fd, tv_ptr);
332
333        const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr);
334        if (num_set_fds < 0)
335            error.SetErrorToErrno();
336        else
337            error.Clear();
338
339        log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION);
340        if (log)
341            log->Printf("%p ConnectionFileDescriptor::Write()  ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s",
342                        this, nfds, m_fd, tv_ptr, num_set_fds, error.AsCString());
343
344        if (error_ptr)
345            *error_ptr = error;
346
347        if (error.Fail())
348        {
349            switch (error.GetError())
350            {
351            case EBADF:     // One of the descriptor sets specified an invalid descriptor.
352            case EINVAL:    // The specified time limit is invalid. One of its components is negative or too large.
353            default:        // Other unknown error
354                return eConnectionStatusError;
355
356            case EAGAIN:    // The kernel was (perhaps temporarily) unable to
357                            // allocate the requested number of file descriptors,
358                            // or we have non-blocking IO
359            case EINTR:     // A signal was delivered before the time limit
360                            // expired and before any of the selected events
361                            // occurred.
362                break;      // Lets keep reading to until we timeout
363            }
364        }
365        else if (num_set_fds == 0)
366        {
367            return eConnectionStatusTimedOut;
368        }
369        else if (num_set_fds > 0)
370        {
371            return eConnectionStatusSuccess;
372        }
373    }
374
375    if (error_ptr)
376        error_ptr->SetErrorString("Not connected.");
377    return eConnectionStatusLostConnection;
378}
379
380ConnectionStatus
381ConnectionFileDescriptor::Close (int& fd, Error *error_ptr)
382{
383    if (error_ptr)
384        error_ptr->Clear();
385    bool success = true;
386    if (fd >= 0)
387    {
388        lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
389                                             "%p ConnectionFileDescriptor::Close (fd = %i)",
390                                             this,
391                                             fd);
392
393        success = ::close (fd) == 0;
394        if (!success && error_ptr)
395        {
396            // Only set the error if we have been asked to since something else
397            // might have caused us to try and shut down the connection and may
398            // have already set the error.
399            error_ptr->SetErrorToErrno();
400        }
401        fd = -1;
402    }
403    m_is_socket = false;
404    if (success)
405        return eConnectionStatusSuccess;
406    else
407        return eConnectionStatusError;
408}
409
410ConnectionStatus
411ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr)
412{
413    ConnectionStatus result = eConnectionStatusError;
414    struct sockaddr_un saddr_un;
415
416    m_is_socket = true;
417
418    int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0);
419    if (listen_socket == -1)
420    {
421        if (error_ptr)
422            error_ptr->SetErrorToErrno();
423        return eConnectionStatusError;
424    }
425
426    saddr_un.sun_family = AF_UNIX;
427    ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1);
428    saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
429    saddr_un.sun_len = SUN_LEN (&saddr_un);
430
431    if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0)
432    {
433        if (::listen (listen_socket, 5) == 0)
434        {
435            m_fd = ::accept (listen_socket, NULL, 0);
436            if (m_fd > 0)
437            {
438                m_should_close_fd = true;
439
440                if (error_ptr)
441                    error_ptr->Clear();
442                result = eConnectionStatusSuccess;
443            }
444        }
445    }
446
447    if (result != eConnectionStatusSuccess)
448    {
449        if (error_ptr)
450            error_ptr->SetErrorToErrno();
451    }
452    // We are done with the listen port
453    Close (listen_socket, NULL);
454    return result;
455}
456
457ConnectionStatus
458ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr)
459{
460    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
461                                 "%p ConnectionFileDescriptor::SocketListen (port = %i)",
462                                 this, listen_port_num);
463
464    Close (m_fd, NULL);
465    m_is_socket = true;
466    int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
467    if (listen_port == -1)
468    {
469        if (error_ptr)
470            error_ptr->SetErrorToErrno();
471        return eConnectionStatusError;
472    }
473
474    // enable local address reuse
475    SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1);
476
477    struct sockaddr_in sa;
478    ::memset (&sa, 0, sizeof sa);
479    sa.sin_family = AF_INET;
480    sa.sin_port = htons (listen_port_num);
481    sa.sin_addr.s_addr = htonl (INADDR_ANY);
482
483    int err = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa));
484    if (err == -1)
485    {
486        if (error_ptr)
487            error_ptr->SetErrorToErrno();
488        Close (listen_port, NULL);
489        return eConnectionStatusError;
490    }
491
492    err = ::listen (listen_port, 1);
493    if (err == -1)
494    {
495        if (error_ptr)
496            error_ptr->SetErrorToErrno();
497        Close (listen_port, NULL);
498        return eConnectionStatusError;
499    }
500
501    m_fd = ::accept (listen_port, NULL, 0);
502    if (m_fd == -1)
503    {
504        if (error_ptr)
505            error_ptr->SetErrorToErrno();
506        Close (listen_port, NULL);
507        return eConnectionStatusError;
508    }
509
510    // We are done with the listen port
511    Close (listen_port, NULL);
512
513    m_should_close_fd = true;
514
515    // Keep our TCP packets coming without any delays.
516    SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
517    if (error_ptr)
518        error_ptr->Clear();
519    return eConnectionStatusSuccess;
520}
521
522ConnectionStatus
523ConnectionFileDescriptor::SocketConnect (const char *host_and_port, Error *error_ptr)
524{
525    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
526                                 "%p ConnectionFileDescriptor::SocketConnect (host/port = %s)",
527                                 this, host_and_port);
528    Close (m_fd, NULL);
529    m_is_socket = true;
530
531    RegularExpression regex ("([^:]+):([0-9]+)");
532    if (regex.Execute (host_and_port, 2) == false)
533    {
534        if (error_ptr)
535            error_ptr->SetErrorStringWithFormat("Invalid host:port specification: '%s'.\n", host_and_port);
536        return eConnectionStatusError;
537    }
538    std::string host_str;
539    std::string port_str;
540    if (regex.GetMatchAtIndex (host_and_port, 1, host_str) == false ||
541        regex.GetMatchAtIndex (host_and_port, 2, port_str) == false)
542    {
543        if (error_ptr)
544            error_ptr->SetErrorStringWithFormat("Invalid host:port specification '%s'.\n", host_and_port);
545        return eConnectionStatusError;
546    }
547
548    int32_t port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
549    if (port == INT32_MIN)
550    {
551        if (error_ptr)
552            error_ptr->SetErrorStringWithFormat("Invalid port '%s'.\n", port_str.c_str());
553        return eConnectionStatusError;
554    }
555    // Create the socket
556    m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
557    if (m_fd == -1)
558    {
559        if (error_ptr)
560            error_ptr->SetErrorToErrno();
561        return eConnectionStatusError;
562    }
563
564    m_should_close_fd = true;
565
566    // Enable local address reuse
567    SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
568
569    struct sockaddr_in sa;
570    ::bzero (&sa, sizeof (sa));
571    sa.sin_family = AF_INET;
572    sa.sin_port = htons (port);
573
574    int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
575
576    if (inet_pton_result <= 0)
577    {
578        struct hostent *host_entry = gethostbyname (host_str.c_str());
579        if (host_entry)
580            host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
581        inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
582        if (inet_pton_result <= 0)
583        {
584
585            if (error_ptr)
586            {
587                if (inet_pton_result == -1)
588                    error_ptr->SetErrorToErrno();
589                else
590                    error_ptr->SetErrorStringWithFormat("Invalid host string: '%s'.\n", host_str.c_str());
591            }
592            Close (m_fd, NULL);
593            return eConnectionStatusError;
594        }
595    }
596
597    if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa)))
598    {
599        if (error_ptr)
600            error_ptr->SetErrorToErrno();
601        Close (m_fd, NULL);
602        return eConnectionStatusError;
603    }
604
605    // Keep our TCP packets coming without any delays.
606    SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
607    if (error_ptr)
608        error_ptr->Clear();
609    return eConnectionStatusSuccess;
610}
611
612int
613ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value)
614{
615    return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
616}
617
618
619