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