LCOV - code coverage report
Current view: top level - co - socketConnection.cpp (source / functions) Hit Total Coverage
Test: Collage Lines: 139 184 75.5 %
Date: 2016-06-07 01:19:44 Functions: 19 19 100.0 %

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

Generated by: LCOV version 1.11