std::ostream& operator << ( std::ostream& os, const Connection& connection ) { Connection::State state = connection.getState(); ConnectionDescriptionPtr desc = connection.getDescription(); os << "Connection " << (void*)&connection << " type " << typeid( connection ).name() << " state " << ( state == Connection::STATE_CLOSED ? "closed" : state == Connection::STATE_CONNECTING ? "connecting" : state == Connection::STATE_CONNECTED ? "connected" : state == Connection::STATE_LISTENING ? "listening" : state == Connection::STATE_CLOSING ? "closing" : "UNKNOWN" ); if( desc.isValid( )) os << " description " << desc->toString(); return os; }
ConnectionPtr SocketConnection::acceptSync() { if( !isListening( )) return 0; sockaddr_in newAddress; socklen_t newAddressLen = sizeof( newAddress ); Socket fd; unsigned nTries = 1000; do fd = ::accept( _readFD, (sockaddr*)&newAddress, &newAddressLen ); while( fd == INVALID_SOCKET && errno == EINTR && --nTries ); if( fd == INVALID_SOCKET ) { LBWARN << "accept failed: " << lunchbox::sysError << std::endl; return 0; } _tuneSocket( fd ); ConstConnectionDescriptionPtr description = getDescription(); SocketConnection* newConnection = new SocketConnection; newConnection->_readFD = fd; newConnection->_writeFD = fd; newConnection->_setState( STATE_CONNECTED ); ConnectionDescriptionPtr newDescription = newConnection->_getDescription(); newDescription->bandwidth = description->bandwidth; newDescription->port = ntohs( newAddress.sin_port ); newDescription->setHostname( inet_ntoa( newAddress.sin_addr )); LBDEBUG << "Accepted " << newDescription->toString() << std::endl; return newConnection; }
//---------------------------------------------------------------------- // 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; }
//---------------------------------------------------------------------- // 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; }