Ejemplo n.º 1
0
ConnectionPtr SocketConnection::acceptSync()
{
    LB_TS_THREAD( _recvThread );
    if( !isListening( ))
        return 0;

    LBASSERT( _overlappedAcceptData );
    LBASSERT( _overlappedSocket != INVALID_SOCKET );
    if( _overlappedSocket == INVALID_SOCKET )
        return 0;

    // complete accept
    DWORD got   = 0;
    DWORD flags = 0;

    if( !WSAGetOverlappedResult( _readFD, &_overlappedRead, &got, TRUE,
                                 &flags ))
    {
        LBWARN << "Accept completion failed: " << lunchbox::sysError
               << ", closing socket" << std::endl;
        close();
        return 0;
    }

    sockaddr_in* local     = 0;
    sockaddr_in* remote    = 0;
    int          localLen  = 0;
    int          remoteLen = 0;
    GetAcceptExSockaddrs( _overlappedAcceptData, 0, sizeof( sockaddr_in ) + 16,
                          sizeof( sockaddr_in ) + 16, (sockaddr**)&local,
                          &localLen, (sockaddr**)&remote, &remoteLen );
    _tuneSocket( _overlappedSocket );

    ConstConnectionDescriptionPtr description = getDescription();
    SocketConnection* newConnection = new SocketConnection;
    ConnectionPtr connection( newConnection ); // to keep ref-counting correct

    newConnection->_readFD  = _overlappedSocket;
    newConnection->_writeFD = _overlappedSocket;

#ifndef _WIN32
    //fcntl( _overlappedSocket, F_SETFL, O_NONBLOCK );
#endif

    newConnection->_initAIORead();
    _overlappedSocket       = INVALID_SOCKET;

    newConnection->_setState( STATE_CONNECTED );
    ConnectionDescriptionPtr newDescription = newConnection->_getDescription();
    newDescription->bandwidth = description->bandwidth;
    newDescription->port = ntohs( remote->sin_port );
    newDescription->setHostname( getHostName( *remote ));

    LBDEBUG << "accepted connection from " << newDescription->getHostname()
           << ":" << newDescription->port << std::endl;
    return connection;
}
Ejemplo n.º 2
0
//----------------------------------------------------------------------
// listen
//----------------------------------------------------------------------
bool SocketConnection::listen()
{
    ConnectionDescriptionPtr description = _getDescription();
    LBASSERT( description->type == CONNECTIONTYPE_TCPIP );

    if( !isClosed( ))
        return false;

    _setState( STATE_CONNECTING );

    sockaddr_in address;
    const size_t size = sizeof( sockaddr_in );

    if( !_parseAddress( description, address ))
    {
        LBWARN << "Can't parse connection parameters" << std::endl;
        return false;
    }

    if( !_createSocket())
        return false;

    const bool bound = (::bind( _readFD, (sockaddr *)&address, size ) == 0);

    if( !bound )
    {
        LBWARN << "Could not bind socket " << _readFD << ": "
               << lunchbox::sysError << " to " << getHostName( address )
               << ":" << ntohs( address.sin_port ) << " AF "
               << (int)address.sin_family << std::endl;

        close();
        return false;
    }

    if( ::listen( _readFD, SOMAXCONN ) != 0 )
    {
        LBWARN << "Could not listen on socket: " << lunchbox::sysError
               << std::endl;
        close();
        return false;
    }

    // get socket parameters
    socklen_t used = size;
    getsockname( _readFD, (struct sockaddr *)&address, &used );
    description->port = ntohs( address.sin_port );

    std::string hostname = description->getHostname();
    if( hostname.empty( ))
    {
        if( address.sin_addr.s_addr == INADDR_ANY )
        {
            char cHostname[256] = {0};
            gethostname( cHostname, 256 );
            hostname = cHostname;

            description->setHostname( hostname );
        }
        else
            description->setHostname( getHostName( address ));
    }

    _initAIOAccept();
    _setState( STATE_LISTENING );

    LBDEBUG << "Listening on " << description->getHostname() << "["
           << getHostName( address ) << "]:" << description->port
           << " (" << description->toString() << ")" << std::endl;

    return true;
}
Ejemplo n.º 3
0
//----------------------------------------------------------------------
// connect
//----------------------------------------------------------------------
bool SocketConnection::connect()
{
    ConnectionDescriptionPtr description = _getDescription();
    LBASSERT( description->type == CONNECTIONTYPE_TCPIP );
    if( !isClosed( ))
        return false;

    if( description->port == 0 )
        return false;

    if( description->getHostname().empty( ))
        description->setHostname( "127.0.0.1" );

    sockaddr_in address;
    if( !_parseAddress( description, address ))
    {
        LBWARN << "Can't parse connection parameters" << std::endl;
        return false;
    }

    _setState( STATE_CONNECTING );

    if( !_createSocket( ))
        return false;

    if( address.sin_addr.s_addr == 0 )
    {
        LBWARN << "Refuse to connect to 0.0.0.0" << std::endl;
        close();
        return false;
    }

#ifdef _WIN32
    const bool connected = WSAConnect( _readFD, (sockaddr*)&address,
                                       sizeof( address ), 0, 0, 0, 0 ) == 0;
#else
    int nTries = 10;
    while( nTries-- )
    {
        const bool connected = (::connect( _readFD, (sockaddr*)&address,
                                           sizeof( address )) == 0);
        if( connected )
            break;

        switch( errno )
        {
          case EINTR: // Happens sometimes, but looks harmless
              LBDEBUG << "connect: " << lunchbox::sysError << ", retrying"
                     << std::endl;
              lunchbox::sleep( 5 /*ms*/ );
              break;

          default:
              nTries = 0;
              break;
        }
    }
    const bool connected = nTries > 0;
#endif

    if( !connected )
    {
        LBDEBUG << "Could not connect to '" << description->getHostname() << ":"
                << description->port << "': " << lunchbox::sysError << std::endl;
        close();
        return false;
    }

    _initAIORead();
    _setState( STATE_CONNECTED );
    LBDEBUG << "Connected " << description->toString() << std::endl;
    return true;
}