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

Generated by: LCOV version 1.10