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

Generated by: LCOV version 1.11