ConnectionFileDescriptor.cpp revision 36f63a92bae332929e1a047b59ed6df651d8537f
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    Log *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    Log *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    Log *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        if (log)
329            log->Printf("%p ConnectionFileDescriptor::Write()  ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...",
330                        this, nfds, m_fd, tv_ptr);
331
332        const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr);
333        if (num_set_fds < 0)
334            error.SetErrorToErrno();
335        else
336            error.Clear();
337
338        if (log)
339            log->Printf("%p ConnectionFileDescriptor::Write()  ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s",
340                        this, nfds, m_fd, tv_ptr, num_set_fds, error.AsCString());
341
342        if (error_ptr)
343            *error_ptr = error;
344
345        if (error.Fail())
346        {
347            switch (error.GetError())
348            {
349            case EBADF:     // One of the descriptor sets specified an invalid descriptor.
350            case EINVAL:    // The specified time limit is invalid. One of its components is negative or too large.
351            default:        // Other unknown error
352                return eConnectionStatusError;
353
354            case EAGAIN:    // The kernel was (perhaps temporarily) unable to
355                            // allocate the requested number of file descriptors,
356                            // or we have non-blocking IO
357            case EINTR:     // A signal was delivered before the time limit
358                            // expired and before any of the selected events
359                            // occurred.
360                break;      // Lets keep reading to until we timeout
361            }
362        }
363        else if (num_set_fds == 0)
364        {
365            return eConnectionStatusTimedOut;
366        }
367        else if (num_set_fds > 0)
368        {
369            return eConnectionStatusSuccess;
370        }
371    }
372
373    if (error_ptr)
374        error_ptr->SetErrorString("Not connected.");
375    return eConnectionStatusLostConnection;
376}
377
378ConnectionStatus
379ConnectionFileDescriptor::Close (int& fd, Error *error_ptr)
380{
381    if (error_ptr)
382        error_ptr->Clear();
383    bool success = true;
384    if (fd >= 0)
385    {
386        lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
387                                             "%p ConnectionFileDescriptor::Close (fd = %i)",
388                                             this,
389                                             fd);
390
391        success = ::close (fd) == 0;
392        if (!success && error_ptr)
393        {
394            // Only set the error if we have been asked to since something else
395            // might have caused us to try and shut down the connection and may
396            // have already set the error.
397            error_ptr->SetErrorToErrno();
398        }
399        fd = -1;
400    }
401    m_is_socket = false;
402    if (success)
403        return eConnectionStatusSuccess;
404    else
405        return eConnectionStatusError;
406}
407
408ConnectionStatus
409ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr)
410{
411    ConnectionStatus result = eConnectionStatusError;
412    struct sockaddr_un saddr_un;
413
414    m_is_socket = true;
415
416    int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0);
417    if (listen_socket == -1)
418    {
419        if (error_ptr)
420            error_ptr->SetErrorToErrno();
421        return eConnectionStatusError;
422    }
423
424    saddr_un.sun_family = AF_UNIX;
425    ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1);
426    saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
427    saddr_un.sun_len = SUN_LEN (&saddr_un);
428
429    if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0)
430    {
431        if (::listen (listen_socket, 5) == 0)
432        {
433            m_fd = ::accept (listen_socket, NULL, 0);
434            if (m_fd > 0)
435            {
436                m_should_close_fd = true;
437
438                if (error_ptr)
439                    error_ptr->Clear();
440                result = eConnectionStatusSuccess;
441            }
442        }
443    }
444
445    if (result != eConnectionStatusSuccess)
446    {
447        if (error_ptr)
448            error_ptr->SetErrorToErrno();
449    }
450    // We are done with the listen port
451    Close (listen_socket, NULL);
452    return result;
453}
454
455ConnectionStatus
456ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr)
457{
458    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
459                                 "%p ConnectionFileDescriptor::SocketListen (port = %i)",
460                                 this, listen_port_num);
461
462    Close (m_fd, NULL);
463    m_is_socket = true;
464    int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
465    if (listen_port == -1)
466    {
467        if (error_ptr)
468            error_ptr->SetErrorToErrno();
469        return eConnectionStatusError;
470    }
471
472    // enable local address reuse
473    SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1);
474
475    struct sockaddr_in sa;
476    ::memset (&sa, 0, sizeof sa);
477    sa.sin_family = AF_INET;
478    sa.sin_port = htons (listen_port_num);
479    sa.sin_addr.s_addr = htonl (INADDR_ANY);
480
481    int err = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa));
482    if (err == -1)
483    {
484        if (error_ptr)
485            error_ptr->SetErrorToErrno();
486        Close (listen_port, NULL);
487        return eConnectionStatusError;
488    }
489
490    err = ::listen (listen_port, 1);
491    if (err == -1)
492    {
493        if (error_ptr)
494            error_ptr->SetErrorToErrno();
495        Close (listen_port, NULL);
496        return eConnectionStatusError;
497    }
498
499    m_fd = ::accept (listen_port, NULL, 0);
500    if (m_fd == -1)
501    {
502        if (error_ptr)
503            error_ptr->SetErrorToErrno();
504        Close (listen_port, NULL);
505        return eConnectionStatusError;
506    }
507
508    // We are done with the listen port
509    Close (listen_port, NULL);
510
511    m_should_close_fd = true;
512
513    // Keep our TCP packets coming without any delays.
514    SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
515    if (error_ptr)
516        error_ptr->Clear();
517    return eConnectionStatusSuccess;
518}
519
520ConnectionStatus
521ConnectionFileDescriptor::SocketConnect (const char *host_and_port, Error *error_ptr)
522{
523    lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION,
524                                 "%p ConnectionFileDescriptor::SocketConnect (host/port = %s)",
525                                 this, host_and_port);
526    Close (m_fd, NULL);
527    m_is_socket = true;
528
529    RegularExpression regex ("([^:]+):([0-9]+)");
530    if (regex.Execute (host_and_port, 2) == false)
531    {
532        if (error_ptr)
533            error_ptr->SetErrorStringWithFormat("Invalid host:port specification: '%s'.\n", host_and_port);
534        return eConnectionStatusError;
535    }
536    std::string host_str;
537    std::string port_str;
538    if (regex.GetMatchAtIndex (host_and_port, 1, host_str) == false ||
539        regex.GetMatchAtIndex (host_and_port, 2, port_str) == false)
540    {
541        if (error_ptr)
542            error_ptr->SetErrorStringWithFormat("Invalid host:port specification '%s'.\n", host_and_port);
543        return eConnectionStatusError;
544    }
545
546    int32_t port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
547    if (port == INT32_MIN)
548    {
549        if (error_ptr)
550            error_ptr->SetErrorStringWithFormat("Invalid port '%s'.\n", port_str.c_str());
551        return eConnectionStatusError;
552    }
553    // Create the socket
554    m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
555    if (m_fd == -1)
556    {
557        if (error_ptr)
558            error_ptr->SetErrorToErrno();
559        return eConnectionStatusError;
560    }
561
562    m_should_close_fd = true;
563
564    // Enable local address reuse
565    SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
566
567    struct sockaddr_in sa;
568    ::bzero (&sa, sizeof (sa));
569    sa.sin_family = AF_INET;
570    sa.sin_port = htons (port);
571
572    int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
573
574    if (inet_pton_result <= 0)
575    {
576        struct hostent *host_entry = gethostbyname (host_str.c_str());
577        if (host_entry)
578            host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
579        inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
580        if (inet_pton_result <= 0)
581        {
582
583            if (error_ptr)
584            {
585                if (inet_pton_result == -1)
586                    error_ptr->SetErrorToErrno();
587                else
588                    error_ptr->SetErrorStringWithFormat("Invalid host string: '%s'.\n", host_str.c_str());
589            }
590            Close (m_fd, NULL);
591            return eConnectionStatusError;
592        }
593    }
594
595    if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa)))
596    {
597        if (error_ptr)
598            error_ptr->SetErrorToErrno();
599        Close (m_fd, NULL);
600        return eConnectionStatusError;
601    }
602
603    // Keep our TCP packets coming without any delays.
604    SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
605    if (error_ptr)
606        error_ptr->Clear();
607    return eConnectionStatusSuccess;
608}
609
610int
611ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value)
612{
613    return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
614}
615
616
617