LCOV - code coverage report
Current view: top level - co - socketConnection.cpp (source / functions) Hit Total Coverage
Test: Collage Lines: 134 183 73.2 %
Date: 2016-12-14 01:26:48 Functions: 18 19 94.7 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                    2010, Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *
       5             :  * This file is part of Collage <https://github.com/Eyescale/Collage>
       6             :  *
       7             :  * This library is free software; you can redistribute it and/or modify it under
       8             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       9             :  * by the Free Software Foundation.
      10             :  *
      11             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      12             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      13             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      14             :  * details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      18             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             :  */
      20             : 
      21             : #include "socketConnection.h"
      22             : 
      23             : #include "connectionDescription.h"
      24             : #include "exception.h"
      25             : #include "global.h"
      26             : 
      27             : #include <lunchbox/os.h>
      28             : #include <lunchbox/log.h>
      29             : #include <lunchbox/sleep.h>
      30             : #include <co/exception.h>
      31             : 
      32             : #include <limits>
      33             : #include <sstream>
      34             : #include <string.h>
      35             : #include <sys/types.h>
      36             : 
      37             : #ifdef _WIN32
      38             : #  include <mswsock.h>
      39             : #  include <winsock2.h>
      40             : #  include <ws2tcpip.h>
      41             : #  define CO_RECV_TIMEOUT 250 /*ms*/
      42             : #else
      43             : #  include <arpa/inet.h>
      44             : #  include <netdb.h>
      45             : #  include <netinet/tcp.h>
      46             : #  include <sys/errno.h>
      47             : #  include <sys/socket.h>
      48             : #endif
      49             : 
      50             : namespace co
      51             : {
      52         145 : SocketConnection::SocketConnection()
      53             : #ifdef _WIN32
      54             :         : _overlappedAcceptData( 0 )
      55             :         , _overlappedSocket( INVALID_SOCKET )
      56             :         , _overlappedDone( 0 )
      57             : #endif
      58             : {
      59             : #ifdef _WIN32
      60             :     memset( &_overlappedRead, 0, sizeof( _overlappedRead ));
      61             :     memset( &_overlappedWrite, 0, sizeof( _overlappedWrite ));
      62             : #endif
      63             : 
      64         290 :     ConnectionDescriptionPtr description = _getDescription();
      65         145 :     description->type = CONNECTIONTYPE_TCPIP;
      66         145 :     description->bandwidth = 102400; // 100MB/s
      67             : 
      68         145 :     LBVERB << "New SocketConnection @" << (void*)this << std::endl;
      69         145 : }
      70             : 
      71         435 : SocketConnection::~SocketConnection()
      72             : {
      73         145 :     _close();
      74         290 : }
      75             : 
      76             : namespace
      77             : {
      78          51 : std::string getHostName( const sockaddr_in& address )
      79             : {
      80             :     char hostname[NI_MAXHOST];
      81          51 :     if( getnameinfo( (sockaddr*)&address.sin_addr, sizeof(sockaddr_in),
      82             :                      hostname, sizeof(hostname), 0, 0, 0 ) == 0 )
      83             :     {
      84           0 :         return std::string( hostname );
      85             :     }
      86          51 :     if( address.sin_addr.s_addr == htonl( INADDR_ANY ))
      87          29 :         return "*";
      88          22 :     return std::string();
      89             : }
      90             : 
      91          98 : bool _parseAddress( ConstConnectionDescriptionPtr description,
      92             :                     sockaddr_in& address )
      93             : {
      94          98 :     address.sin_family      = AF_INET;
      95          98 :     address.sin_addr.s_addr = htonl( INADDR_ANY );
      96          98 :     address.sin_port        = htons( description->port );
      97          98 :     memset( &(address.sin_zero), 0, 8 ); // zero the rest
      98             : 
      99          98 :     const std::string& hostname = description->getHostname();
     100          98 :     if( !hostname.empty( ))
     101             :     {
     102             :         addrinfo hints;
     103          69 :         memset( &hints, 0, sizeof(hints));
     104          69 :         hints.ai_flags = 0;
     105          69 :         hints.ai_family = AF_INET;
     106          69 :         hints.ai_socktype = SOCK_STREAM;
     107          69 :         addrinfo* info = 0;
     108             : 
     109          69 :         if( getaddrinfo( hostname.c_str(), NULL, &hints, &info ) == 0 )
     110             :         {
     111          69 :             address.sin_addr.s_addr = ((sockaddr_in *)(info->ai_addr))->sin_addr.s_addr;
     112          69 :             freeaddrinfo( info );
     113             :         }
     114             :         else
     115             :         {
     116           0 :             LBWARN << "Can't resolve host " << hostname << std::endl;
     117           0 :             return false;
     118             :         }
     119             :     }
     120             : 
     121         196 :     LBVERB << "Address " << getHostName( address ) << ":"
     122         294 :            << ntohs( address.sin_port ) << std::endl;
     123          98 :     return true;
     124             : }
     125             : }
     126             : 
     127             : //----------------------------------------------------------------------
     128             : // connect
     129             : //----------------------------------------------------------------------
     130          47 : bool SocketConnection::connect()
     131             : {
     132          94 :     ConnectionDescriptionPtr description = _getDescription();
     133          47 :     LBASSERT( description->type == CONNECTIONTYPE_TCPIP );
     134          47 :     if( !isClosed( ))
     135           0 :         return false;
     136             : 
     137          47 :     if( description->port == 0 )
     138           0 :         return false;
     139             : 
     140          47 :     if( description->getHostname().empty( ))
     141          25 :         description->setHostname( "127.0.0.1" );
     142             : 
     143             :     sockaddr_in address;
     144          47 :     if( !_parseAddress( description, address ))
     145             :     {
     146           0 :         LBWARN << "Can't parse connection parameters" << std::endl;
     147           0 :         return false;
     148             :     }
     149             : 
     150          47 :     _setState( STATE_CONNECTING );
     151             : 
     152          47 :     if( !_createSocket( ))
     153           0 :         return false;
     154             : 
     155          47 :     if( address.sin_addr.s_addr == 0 )
     156             :     {
     157           0 :         LBWARN << "Refuse to connect to 0.0.0.0" << std::endl;
     158           0 :         close();
     159           0 :         return false;
     160             :     }
     161             : 
     162             : #ifdef _WIN32
     163             :     const bool connected = WSAConnect( _readFD, (sockaddr*)&address,
     164             :                                        sizeof( address ), 0, 0, 0, 0 ) == 0;
     165             : #else
     166          47 :     int nTries = 10;
     167          47 :     while( nTries-- )
     168             :     {
     169          47 :         const bool connected = (::connect( _readFD, (sockaddr*)&address,
     170          47 :                                            sizeof( address )) == 0);
     171          47 :         if( connected )
     172          47 :             break;
     173             : 
     174           0 :         switch( errno )
     175             :         {
     176             :           case EINTR: // Happens sometimes, but looks harmless
     177           0 :               LBDEBUG << "connect: " << lunchbox::sysError << ", retrying"
     178           0 :                      << std::endl;
     179           0 :               lunchbox::sleep( 5 /*ms*/ );
     180           0 :               break;
     181             : 
     182             :           default:
     183           0 :               nTries = 0;
     184           0 :               break;
     185             :         }
     186             :     }
     187          47 :     const bool connected = nTries > 0;
     188             : #endif
     189             : 
     190          47 :     if( !connected )
     191             :     {
     192           0 :         LBDEBUG << "Could not connect to '" << description->getHostname() << ":"
     193           0 :                 << description->port << "': " << lunchbox::sysError << std::endl;
     194           0 :         close();
     195           0 :         return false;
     196             :     }
     197             : 
     198          47 :     _initAIORead();
     199          47 :     _setState( STATE_CONNECTED );
     200          47 :     LBDEBUG << "Connected " << description->toString() << std::endl;
     201          47 :     return true;
     202             : }
     203             : 
     204         289 : void SocketConnection::_close()
     205             : {
     206         289 :     if( isClosed( ))
     207         144 :         return;
     208             : 
     209         145 :     if( isListening( ))
     210          51 :         _exitAIOAccept();
     211          94 :     else if( isConnected( ))
     212          94 :         _exitAIORead();
     213             : 
     214         145 :     LBASSERT( _readFD > 0 );
     215             : 
     216             : #ifdef _WIN32
     217             :     const bool closed = ( ::closesocket(_readFD) == 0 );
     218             : #else
     219         145 :     const bool closed = ( ::close(_readFD) == 0 );
     220             : #endif
     221             : 
     222         145 :     if( !closed )
     223           0 :         LBWARN << "Could not close socket: " << lunchbox::sysError
     224           0 :                << std::endl;
     225             : 
     226         145 :     _readFD  = INVALID_SOCKET;
     227         145 :     _writeFD = INVALID_SOCKET;
     228         145 :     _setState( STATE_CLOSED );
     229             : }
     230             : 
     231             : //----------------------------------------------------------------------
     232             : // Async IO handles
     233             : //----------------------------------------------------------------------
     234             : #ifdef _WIN32
     235             : void SocketConnection::_initAIORead()
     236             : {
     237             :     _overlappedRead.hEvent = CreateEvent( 0, FALSE, FALSE, 0 );
     238             :     LBASSERT( _overlappedRead.hEvent );
     239             : 
     240             :     _overlappedWrite.hEvent = CreateEvent( 0, FALSE, FALSE, 0 );
     241             :     LBASSERT( _overlappedWrite.hEvent );
     242             :     if( !_overlappedRead.hEvent )
     243             :         LBERROR << "Can't create event for AIO notification: "
     244             :                 << lunchbox::sysError << std::endl;
     245             : }
     246             : 
     247             : void SocketConnection::_initAIOAccept()
     248             : {
     249             :     _initAIORead();
     250             :     _overlappedAcceptData = malloc( 2*( sizeof( sockaddr_in ) + 16 ));
     251             : }
     252             : 
     253             : void SocketConnection::_exitAIOAccept()
     254             : {
     255             :     if( _overlappedAcceptData )
     256             :     {
     257             :         free( _overlappedAcceptData );
     258             :         _overlappedAcceptData = 0;
     259             :     }
     260             : 
     261             :     _exitAIORead();
     262             : }
     263             : void SocketConnection::_exitAIORead()
     264             : {
     265             :     if( _overlappedRead.hEvent )
     266             :     {
     267             :         CloseHandle( _overlappedRead.hEvent );
     268             :         _overlappedRead.hEvent = 0;
     269             :     }
     270             : 
     271             :     if( _overlappedWrite.hEvent )
     272             :     {
     273             :         CloseHandle( _overlappedWrite.hEvent );
     274             :         _overlappedWrite.hEvent = 0;
     275             :     }
     276             : }
     277             : #else
     278          51 : void SocketConnection::_initAIOAccept(){ /* NOP */ }
     279          51 : void SocketConnection::_exitAIOAccept(){ /* NOP */ }
     280          47 : void SocketConnection::_initAIORead(){ /* NOP */ }
     281          94 : void SocketConnection::_exitAIORead(){ /* NOP */ }
     282             : #endif
     283             : 
     284             : //----------------------------------------------------------------------
     285             : // accept
     286             : //----------------------------------------------------------------------
     287             : #ifdef _WIN32
     288             : void SocketConnection::acceptNB()
     289             : {
     290             :     LBASSERT( isListening() );
     291             : 
     292             :     // Create new accept socket
     293             :     const DWORD flags = WSA_FLAG_OVERLAPPED;
     294             : 
     295             :     LBASSERT( _overlappedAcceptData );
     296             :     LBASSERT( _overlappedSocket == INVALID_SOCKET );
     297             :     _overlappedSocket = WSASocketW( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0,
     298             :                                     flags );
     299             : 
     300             :     if( _overlappedSocket == INVALID_SOCKET )
     301             :     {
     302             :         LBERROR << "Could not create accept socket: " << lunchbox::sysError
     303             :                 << ", closing listening socket" << std::endl;
     304             :         close();
     305             :         return;
     306             :     }
     307             : 
     308             :     const int on = 1;
     309             :     setsockopt( _overlappedSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
     310             :         reinterpret_cast<const char*>( &on ), sizeof( on ));
     311             : 
     312             :     // Start accept
     313             :     ResetEvent( _overlappedRead.hEvent );
     314             :     DWORD got;
     315             :     if( !AcceptEx( _readFD, _overlappedSocket, _overlappedAcceptData, 0,
     316             :                    sizeof( sockaddr_in ) + 16, sizeof( sockaddr_in ) + 16,
     317             :                    &got, &_overlappedRead ) &&
     318             :         GetLastError() != WSA_IO_PENDING )
     319             :     {
     320             :         LBERROR << "Could not start accept operation: "
     321             :                 << lunchbox::sysError << ", closing connection" << std::endl;
     322             :         close();
     323             :     }
     324             : }
     325             : 
     326             : ConnectionPtr SocketConnection::acceptSync()
     327             : {
     328             :     LB_TS_THREAD( _recvThread );
     329             :     if( !isListening( ))
     330             :         return 0;
     331             : 
     332             :     LBASSERT( _overlappedAcceptData );
     333             :     LBASSERT( _overlappedSocket != INVALID_SOCKET );
     334             :     if( _overlappedSocket == INVALID_SOCKET )
     335             :         return 0;
     336             : 
     337             :     // complete accept
     338             :     DWORD got   = 0;
     339             :     DWORD flags = 0;
     340             : 
     341             :     if( !WSAGetOverlappedResult( _readFD, &_overlappedRead, &got, TRUE,
     342             :                                  &flags ))
     343             :     {
     344             :         LBWARN << "Accept completion failed: " << lunchbox::sysError
     345             :                << ", closing socket" << std::endl;
     346             :         close();
     347             :         return 0;
     348             :     }
     349             : 
     350             :     sockaddr_in* local     = 0;
     351             :     sockaddr_in* remote    = 0;
     352             :     int          localLen  = 0;
     353             :     int          remoteLen = 0;
     354             :     GetAcceptExSockaddrs( _overlappedAcceptData, 0, sizeof( sockaddr_in ) + 16,
     355             :                           sizeof( sockaddr_in ) + 16, (sockaddr**)&local,
     356             :                           &localLen, (sockaddr**)&remote, &remoteLen );
     357             :     _tuneSocket( _overlappedSocket );
     358             : 
     359             :     ConstConnectionDescriptionPtr description = getDescription();
     360             :     SocketConnection* newConnection = new SocketConnection;
     361             :     ConnectionPtr connection( newConnection ); // to keep ref-counting correct
     362             : 
     363             :     newConnection->_readFD  = _overlappedSocket;
     364             :     newConnection->_writeFD = _overlappedSocket;
     365             : 
     366             : #ifndef _WIN32
     367             :     //fcntl( _overlappedSocket, F_SETFL, O_NONBLOCK );
     368             : #endif
     369             : 
     370             :     newConnection->_initAIORead();
     371             :     _overlappedSocket       = INVALID_SOCKET;
     372             : 
     373             :     newConnection->_setState( STATE_CONNECTED );
     374             :     ConnectionDescriptionPtr newDescription = newConnection->_getDescription();
     375             :     newDescription->bandwidth = description->bandwidth;
     376             :     newDescription->port = ntohs( remote->sin_port );
     377             :     newDescription->setHostname( getHostName( *remote ));
     378             : 
     379             :     LBDEBUG << "accepted connection from " << newDescription->getHostname()
     380             :            << ":" << newDescription->port << std::endl;
     381             :     return connection;
     382             : }
     383             : 
     384             : #else // !_WIN32
     385             : 
     386          94 : void SocketConnection::acceptNB(){ /* NOP */ }
     387             : 
     388          47 : ConnectionPtr SocketConnection::acceptSync()
     389             : {
     390          47 :     if( !isListening( ))
     391           0 :         return 0;
     392             : 
     393             :     sockaddr_in newAddress;
     394          47 :     socklen_t   newAddressLen = sizeof( newAddress );
     395             : 
     396             :     Socket    fd;
     397          47 :     unsigned  nTries = 1000;
     398          47 :     do
     399          47 :         fd = ::accept( _readFD, (sockaddr*)&newAddress, &newAddressLen );
     400          47 :     while( fd == INVALID_SOCKET && errno == EINTR && --nTries );
     401             : 
     402          47 :     if( fd == INVALID_SOCKET )
     403             :     {
     404           0 :       LBWARN << "accept failed: " << lunchbox::sysError << std::endl;
     405           0 :         return 0;
     406             :     }
     407             : 
     408          47 :     _tuneSocket( fd );
     409             : 
     410          94 :     ConstConnectionDescriptionPtr description = getDescription();
     411          47 :     SocketConnection* newConnection = new SocketConnection;
     412             : 
     413          47 :     newConnection->_readFD      = fd;
     414          47 :     newConnection->_writeFD     = fd;
     415          47 :     newConnection->_setState( STATE_CONNECTED );
     416          94 :     ConnectionDescriptionPtr newDescription = newConnection->_getDescription();
     417          47 :     newDescription->bandwidth = description->bandwidth;
     418          47 :     newDescription->port = ntohs( newAddress.sin_port );
     419          47 :     newDescription->setHostname( inet_ntoa( newAddress.sin_addr ));
     420             : 
     421          47 :     LBDEBUG << "Accepted " << newDescription->toString() << std::endl;
     422          47 :     return newConnection;
     423             : }
     424             : 
     425             : #endif // !_WIN32
     426             : 
     427             : 
     428             : 
     429             : #ifdef _WIN32
     430             : //----------------------------------------------------------------------
     431             : // read
     432             : //----------------------------------------------------------------------
     433             : void SocketConnection::readNB( void* buffer, const uint64_t bytes )
     434             : {
     435             :     if( isClosed() )
     436             :         return;
     437             : 
     438             :     WSABUF wsaBuffer = { LB_MIN( bytes, 65535 ),
     439             :                          reinterpret_cast< char* >( buffer ) };
     440             :     DWORD  flags = 0;
     441             : 
     442             :     ResetEvent( _overlappedRead.hEvent );
     443             :     _overlappedDone = 0;
     444             :     const int result = WSARecv( _readFD, &wsaBuffer, 1, &_overlappedDone,
     445             :                                 &flags, &_overlappedRead, 0 );
     446             :     if( result == 0 ) // got data already
     447             :     {
     448             :         if( _overlappedDone == 0 ) // socket closed
     449             :         {
     450             :             LBDEBUG << "Got EOF, closing connection" << std::endl;
     451             :             close();
     452             :         }
     453             :         SetEvent( _overlappedRead.hEvent );
     454             :     }
     455             :     else if( GetLastError() != WSA_IO_PENDING )
     456             :     {
     457             :         LBWARN << "Could not start overlapped receive: " << lunchbox::sysError
     458             :                << ", closing connection" << std::endl;
     459             :         close();
     460             :     }
     461             : }
     462             : 
     463             : int64_t SocketConnection::readSync( void* buffer, const uint64_t bytes,
     464             :                                     const bool block )
     465             : {
     466             :     LB_TS_THREAD( _recvThread );
     467             : 
     468             :     if( _readFD == INVALID_SOCKET )
     469             :     {
     470             :         LBERROR << "Invalid read handle" << std::endl;
     471             :         return READ_ERROR;
     472             :     }
     473             : 
     474             :     if( _overlappedDone > 0 )
     475             :         return _overlappedDone;
     476             : 
     477             :     DWORD got   = 0;
     478             :     DWORD flags = 0;
     479             :     DWORD startTime = 0;
     480             : 
     481             :     while( true )
     482             :     {
     483             :         if( WSAGetOverlappedResult( _readFD, &_overlappedRead, &got, block,
     484             :                                     &flags ))
     485             :             return got;
     486             : 
     487             :         const int err = WSAGetLastError();
     488             :         if( err == ERROR_SUCCESS || got > 0 )
     489             :         {
     490             :             LBWARN << "Got " << lunchbox::sysError << " with " << got
     491             :                    << " bytes on " << getDescription() << std::endl;
     492             :             return got;
     493             :         }
     494             : 
     495             :         if( startTime == 0 )
     496             :             startTime = GetTickCount();
     497             : 
     498             :         switch( err )
     499             :         {
     500             :             case WSA_IO_INCOMPLETE:
     501             :                 return READ_TIMEOUT;
     502             : 
     503             :             case WSASYSCALLFAILURE:  // happens sometimes!?
     504             :             case WSA_IO_PENDING:
     505             :                 if( GetTickCount() - startTime > CO_RECV_TIMEOUT ) // timeout
     506             :                 {
     507             :                     LBWARN << "Error timeout " << std::endl;
     508             :                     return READ_ERROR;
     509             :                 }
     510             : 
     511             :                 LBWARN << "WSAGetOverlappedResult error loop"
     512             :                        << std::endl;
     513             :                 // one millisecond to recover
     514             :                 lunchbox::sleep( 1 );
     515             :                 break;
     516             : 
     517             :             default:
     518             :                 LBWARN << "Got " << lunchbox::sysError
     519             :                        << ", closing connection" << std::endl;
     520             :                 close();
     521             :                 return READ_ERROR;
     522             :         }
     523             :     }
     524             : }
     525             : 
     526             : int64_t SocketConnection::write( const void* buffer, const uint64_t bytes )
     527             : {
     528             :     if( !isConnected() || _writeFD == INVALID_SOCKET )
     529             :         return -1;
     530             : 
     531             :     DWORD  wrote;
     532             :     WSABUF wsaBuffer =
     533             :         {
     534             :             LB_MIN( bytes, 65535 ),
     535             :             const_cast<char*>( static_cast< const char* >( buffer ))
     536             :         };
     537             : 
     538             :     ResetEvent( _overlappedWrite.hEvent );
     539             :     if( WSASend(_writeFD, &wsaBuffer, 1, &wrote, 0, &_overlappedWrite, 0 ) == 0 )
     540             :         // ok
     541             :         return wrote;
     542             : 
     543             :     if( WSAGetLastError() != WSA_IO_PENDING )
     544             :           return -1;
     545             : 
     546             :     const DWORD err = WaitForSingleObject( _overlappedWrite.hEvent, INFINITE );
     547             :     switch( err )
     548             :     {
     549             :       case WAIT_FAILED:
     550             :       case WAIT_ABANDONED:
     551             :         {
     552             :             LBWARN << "Write error" << lunchbox::sysError << std::endl;
     553             :             return -1;
     554             :         }
     555             : 
     556             :       default:
     557             :           LBWARN << "Unhandled write error " << err << ": " << lunchbox::sysError
     558             :                  << std::endl;
     559             :           // no break;
     560             :       case WAIT_OBJECT_0:
     561             :           break;
     562             :     }
     563             : 
     564             :     DWORD got = 0;
     565             :     DWORD flags = 0;
     566             :     if( WSAGetOverlappedResult( _writeFD, &_overlappedWrite, &got, false,
     567             :                                 &flags ))
     568             :     {
     569             :         return got;
     570             :     }
     571             : 
     572             :     switch( WSAGetLastError() )
     573             :     {
     574             :       case WSA_IO_INCOMPLETE:
     575             :           throw Exception( Exception::TIMEOUT_WRITE );
     576             : 
     577             :       default:
     578             :       {
     579             :           LBWARN << "Write error : " << lunchbox::sysError << std::endl;
     580             :           return -1;
     581             :       }
     582             :     }
     583             : 
     584             :     LBUNREACHABLE;
     585             :     return -1;
     586             : }
     587             : #endif // _WIN32
     588             : 
     589          98 : bool SocketConnection::_createSocket()
     590             : {
     591         196 :     ConstConnectionDescriptionPtr description = getDescription();
     592             : #ifdef _WIN32
     593             :     const DWORD flags = WSA_FLAG_OVERLAPPED;
     594             :     const SOCKET fd = WSASocketW( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0,
     595             :                                   flags );
     596             : #else
     597          98 :     const Socket fd = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
     598             : #endif
     599             : 
     600          98 :     if( fd == INVALID_SOCKET )
     601             :     {
     602           0 :         LBERROR << "Could not create socket: "
     603           0 :                 << lunchbox::sysError << std::endl;
     604           0 :         return false;
     605             :     }
     606             : 
     607          98 :     _tuneSocket( fd );
     608             : 
     609          98 :     _readFD  = fd;
     610          98 :     _writeFD = fd; // TCP/IP sockets are bidirectional
     611             : 
     612          98 :     return true;
     613             : }
     614             : 
     615         145 : void SocketConnection::_tuneSocket( const Socket fd )
     616             : {
     617         145 :     const int on         = 1;
     618             :     setsockopt( fd, IPPROTO_TCP, TCP_NODELAY,
     619         145 :                 reinterpret_cast<const char*>( &on ), sizeof( on ));
     620             :     setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
     621         145 :                 reinterpret_cast<const char*>( &on ), sizeof( on ));
     622             : 
     623             : #ifdef _WIN32
     624             :     const int size = 128768;
     625             :     setsockopt( fd, SOL_SOCKET, SO_RCVBUF,
     626             :                 reinterpret_cast<const char*>( &size ), sizeof( size ));
     627             :     setsockopt( fd, SOL_SOCKET, SO_SNDBUF,
     628             :                 reinterpret_cast<const char*>( &size ), sizeof( size ));
     629             : #endif
     630         145 : }
     631             : 
     632             : //----------------------------------------------------------------------
     633             : // listen
     634             : //----------------------------------------------------------------------
     635          51 : bool SocketConnection::listen()
     636             : {
     637         102 :     ConnectionDescriptionPtr description = _getDescription();
     638          51 :     LBASSERT( description->type == CONNECTIONTYPE_TCPIP );
     639             : 
     640          51 :     if( !isClosed( ))
     641           0 :         return false;
     642             : 
     643          51 :     _setState( STATE_CONNECTING );
     644             : 
     645             :     sockaddr_in address;
     646          51 :     const size_t size = sizeof( sockaddr_in );
     647             : 
     648          51 :     if( !_parseAddress( description, address ))
     649             :     {
     650           0 :         LBWARN << "Can't parse connection parameters" << std::endl;
     651           0 :         return false;
     652             :     }
     653             : 
     654          51 :     if( !_createSocket())
     655           0 :         return false;
     656             : 
     657          51 :     const bool bound = (::bind( _readFD, (sockaddr *)&address, size ) == 0);
     658             : 
     659          51 :     if( !bound )
     660             :     {
     661           0 :         LBWARN << "Could not bind socket " << _readFD << ": "
     662           0 :                << lunchbox::sysError << " to " << getHostName( address )
     663           0 :                << ":" << ntohs( address.sin_port ) << " AF "
     664           0 :                << (int)address.sin_family << std::endl;
     665             : 
     666           0 :         close();
     667           0 :         return false;
     668             :     }
     669             : 
     670          51 :     if( ::listen( _readFD, SOMAXCONN ) != 0 )
     671             :     {
     672           0 :         LBWARN << "Could not listen on socket: " << lunchbox::sysError
     673           0 :                << std::endl;
     674           0 :         close();
     675           0 :         return false;
     676             :     }
     677             : 
     678             :     // get socket parameters
     679          51 :     socklen_t used = size;
     680          51 :     getsockname( _readFD, (struct sockaddr *)&address, &used );
     681          51 :     description->port = ntohs( address.sin_port );
     682             : 
     683         102 :     std::string hostname = description->getHostname();
     684          51 :     if( hostname.empty( ))
     685             :     {
     686          29 :         if( address.sin_addr.s_addr == INADDR_ANY )
     687             :         {
     688          29 :             char cHostname[256] = {0};
     689          29 :             gethostname( cHostname, 256 );
     690          29 :             hostname = cHostname;
     691             : 
     692          29 :             description->setHostname( hostname );
     693             :         }
     694             :         else
     695           0 :             description->setHostname( getHostName( address ));
     696             :     }
     697             : 
     698          51 :     _initAIOAccept();
     699          51 :     _setState( STATE_LISTENING );
     700             : 
     701         204 :     LBDEBUG << "Listening on " << description->getHostname() << "["
     702         153 :            << getHostName( address ) << "]:" << description->port
     703         255 :            << " (" << description->toString() << ")" << std::endl;
     704             : 
     705          51 :     return true;
     706             : }
     707             : 
     708           0 : uint16_t SocketConnection::_getPort() const
     709             : {
     710             :     sockaddr_in address;
     711           0 :     socklen_t used = sizeof( address );
     712           0 :     getsockname( _readFD, (struct sockaddr *) &address, &used );
     713           0 :     return ntohs(address.sin_port);
     714             : }
     715             : 
     716          66 : }

Generated by: LCOV version 1.11