bool LocalNode::_connect( NodePtr node, ConnectionPtr connection ) { EQASSERT( connection.isValid( )); EQASSERT( node->getNodeID() != getNodeID( )); if( !node.isValid() || _state != STATE_LISTENING || !connection->isConnected() || node->_state != STATE_CLOSED ) { return false; } _addConnection( connection ); // send connect packet to peer NodeConnectPacket packet; packet.requestID = registerRequest( node.get( )); packet.nodeID = _id; packet.nodeType = getType(); connection->send( packet, serialize( )); bool connected = false; if( !waitRequest( packet.requestID, connected, 10000 /*ms*/ )) { EQWARN << "Node connection handshake timeout - peer not a Collage node?" << std::endl; return false; } if( !connected ) return false; EQASSERT( node->_id != NodeID::ZERO ); EQASSERTINFO( node->_id != _id, _id ); EQINFO << node << " connected to " << *(Node*)this << std::endl; return true; }
bool LocalNode::_cmdDisconnect( Command& command ) { EQASSERT( _inReceiverThread( )); const NodeDisconnectPacket* packet = command.get< NodeDisconnectPacket >(); NodePtr node = static_cast<Node*>( getRequestData( packet->requestID )); EQASSERT( node.isValid( )); ConnectionPtr connection = node->_outgoing; if( connection.isValid( )) { node->_state = STATE_CLOSED; node->_outgoing = 0; _removeConnection( connection ); EQASSERT( _connectionNodes.find( connection )!=_connectionNodes.end( )); _objectStore->removeInstanceData( node->_id ); _connectionNodes.erase( connection ); { base::ScopedMutex< base::SpinLock > mutex( _nodes ); _nodes->erase( node->_id ); } EQINFO << node << " disconnected from " << this << " connection used " << connection->getRefCount() << std::endl; } EQASSERT( node->_state == STATE_CLOSED ); serveRequest( packet->requestID ); return true; }
void LocalNode::_removeConnection( ConnectionPtr connection ) { EQASSERT( connection.isValid( )); _incoming.removeConnection( connection ); void* buffer( 0 ); uint64_t bytes( 0 ); connection->getRecvData( &buffer, &bytes ); EQASSERTINFO( !connection->isConnected() || buffer, *connection ); EQASSERT( !buffer || bytes == sizeof( uint64_t )); if( !connection->isClosed( )) connection->close(); // cancels pending IO's delete reinterpret_cast< uint64_t* >( buffer ); }
bool LocalNode::_handleData() { ConnectionPtr connection = _incoming.getConnection(); EQASSERT( connection.isValid( )); NodePtr node; ConnectionNodeHash::const_iterator i = _connectionNodes.find( connection ); if( i != _connectionNodes.end( )) node = i->second; EQASSERTINFO( !node || // unconnected node *(node->_outgoing) == *connection || // correct UC connection connection->getDescription()->type>=CONNECTIONTYPE_MULTICAST, base::className( node )); EQVERB << "Handle data from " << node << std::endl; void* sizePtr( 0 ); uint64_t bytes( 0 ); const bool gotSize = connection->recvSync( &sizePtr, &bytes, false ); if( !gotSize ) // Some systems signal data on dead connections. { connection->recvNB( sizePtr, sizeof( uint64_t )); return false; } EQASSERT( sizePtr ); const uint64_t size = *reinterpret_cast< uint64_t* >( sizePtr ); if( bytes == 0 ) // fluke signal { EQWARN << "Erronous network event on " << connection->getDescription() << std::endl; _incoming.setDirty(); return false; } EQASSERT( size ); EQASSERTINFO( bytes == sizeof( uint64_t ), bytes ); EQASSERT( size > sizeof( size )); if( node ) node->_lastReceive = getTime64(); Command& command = _commandCache.alloc( node, this, size ); uint8_t* ptr = reinterpret_cast< uint8_t* >( command.getModifiable< Packet >()) + sizeof( uint64_t ); connection->recvNB( ptr, size - sizeof( uint64_t )); const bool gotData = connection->recvSync( 0, 0 ); EQASSERT( gotData ); EQASSERT( command.isValid( )); EQASSERT( command.isFree( )); // start next receive connection->recvNB( sizePtr, sizeof( uint64_t )); if( !gotData ) { EQERROR << "Incomplete packet read: " << command << std::endl; return false; } // This is one of the initial packets during the connection handshake, at // this point the remote node is not yet available. EQASSERTINFO( node.isValid() || ( command->type == PACKETTYPE_CO_NODE && ( command->command == CMD_NODE_CONNECT || command->command == CMD_NODE_CONNECT_REPLY || command->command == CMD_NODE_ID )), command << " connection " << connection ); _dispatchCommand( command ); return true; }