bool LocalNode::_cmdGetNodeDataReply( Command& command ) { EQASSERT( _inReceiverThread( )); const NodeGetNodeDataReplyPacket* packet = command.get< NodeGetNodeDataReplyPacket >(); EQVERB << "cmd get node data reply: " << packet << std::endl; const uint32_t requestID = packet->requestID; const NodeID& nodeID = packet->nodeID; // No locking needed, only recv thread writes NodeHash::const_iterator i = _nodes->find( nodeID ); if( i != _nodes->end( )) { // Requested node connected to us in the meantime NodePtr node = i->second; node->ref( CO_REFERENCED_PARAM ); serveRequest( requestID, node.get( )); return true; } if( packet->nodeType == NODETYPE_CO_INVALID ) { serveRequest( requestID, (void*)0 ); return true; } // new node: create and add unconnected node NodePtr node = createNode( packet->nodeType ); EQASSERT( node.isValid( )); std::string data = packet->nodeData; if( !node->deserialize( data )) EQWARN << "Failed to initialize node data" << std::endl; EQASSERT( data.empty( )); node->ref( CO_REFERENCED_PARAM ); serveRequest( requestID, node.get( )); return true; }
bool LocalNode::_cmdConnectReply( Command& command ) { EQASSERT( !command.getNode( )); EQASSERT( _inReceiverThread( )); const NodeConnectReplyPacket* packet = command.get< NodeConnectReplyPacket >(); ConnectionPtr connection = _incoming.getConnection(); const NodeID& nodeID = packet->nodeID; EQVERB << "handle connect reply " << packet << std::endl; EQASSERT( _connectionNodes.find( connection ) == _connectionNodes.end( )); NodePtr remoteNode; // No locking needed, only recv thread modifies NodeHash::const_iterator i = _nodes->find( nodeID ); if( i != _nodes->end( )) remoteNode = i->second; if( nodeID == NodeID::ZERO || // connection refused // Node exists, probably simultaneous connect ( remoteNode.isValid() && remoteNode->isConnected( ))) { EQINFO << "ignoring connect reply, node already connected" << std::endl; _removeConnection( connection ); if( packet->requestID != EQ_UNDEFINED_UINT32 ) serveRequest( packet->requestID, false ); return true; } // create and add node if( !remoteNode ) { if( packet->requestID != EQ_UNDEFINED_UINT32 ) { void* ptr = getRequestData( packet->requestID ); EQASSERT( dynamic_cast< Node* >( (Dispatcher*)ptr )); remoteNode = static_cast< Node* >( ptr ); } else remoteNode = createNode( packet->nodeType ); } EQASSERT( remoteNode->getType() == packet->nodeType ); EQASSERT( remoteNode->_state == STATE_CLOSED ); std::string data = packet->nodeData; if( !remoteNode->deserialize( data )) EQWARN << "Error during node initialization" << std::endl; EQASSERT( data.empty( )); EQASSERT( remoteNode->_id == nodeID ); remoteNode->_outgoing = connection; remoteNode->_state = STATE_CONNECTED; _connectionNodes[ connection ] = remoteNode; { base::ScopedMutex< base::SpinLock > mutex( _nodes ); _nodes.data[ remoteNode->_id ] = remoteNode; } EQVERB << "Added node " << nodeID << std::endl; if( packet->requestID != EQ_UNDEFINED_UINT32 ) serveRequest( packet->requestID, true ); NodeConnectAckPacket ack; remoteNode->send( ack ); _connectMulticast( remoteNode ); return true; }
bool LocalNode::_cmdID( Command& command ) { EQASSERT( _inReceiverThread( )); const NodeIDPacket* packet = command.get< NodeIDPacket >(); NodeID nodeID = packet->id; if( command.getNode().isValid( )) { EQASSERT( nodeID == command.getNode()->getNodeID( )); EQASSERT( command.getNode()->_outMulticast->isValid( )); return true; } EQINFO << "handle ID " << packet << " node " << nodeID << std::endl; ConnectionPtr connection = _incoming.getConnection(); EQASSERT( connection->getDescription()->type >= CONNECTIONTYPE_MULTICAST ); EQASSERT( _connectionNodes.find( connection ) == _connectionNodes.end( )); NodePtr node; if( nodeID == _id ) // 'self' multicast connection node = this; else { // No locking needed, only recv thread writes NodeHash::const_iterator i = _nodes->find( nodeID ); if( i == _nodes->end( )) { // unknown node: create and add unconnected node node = createNode( packet->nodeType ); std::string data = packet->data; if( !node->deserialize( data )) EQWARN << "Error during node initialization" << std::endl; EQASSERTINFO( data.empty(), data ); { base::ScopedMutex< base::SpinLock > mutex( _nodes ); _nodes.data[ nodeID ] = node; } EQVERB << "Added node " << nodeID << " with multicast " << connection << std::endl; } else node = i->second; } EQASSERT( node.isValid( )); EQASSERTINFO( node->_id == nodeID, node->_id << "!=" << nodeID ); base::ScopedMutex<> mutex( _outMulticast ); MCDatas::iterator i = node->_multicasts.begin(); for( ; i != node->_multicasts.end(); ++i ) { if( (*i).connection == connection ) break; } if( node->_outMulticast->isValid( )) { if( node->_outMulticast.data == connection ) // connection already used { // nop EQASSERT( i == node->_multicasts.end( )); } else // another connection is used as multicast connection, save this { if( i == node->_multicasts.end( )) { EQASSERT( _state == STATE_LISTENING ); MCData data; data.connection = connection; data.node = this; node->_multicasts.push_back( data ); } // else nop, already know connection } } else { node->_outMulticast.data = connection; if( i != node->_multicasts.end( )) node->_multicasts.erase( i ); } _connectionNodes[ connection ] = node; EQINFO << "Added multicast connection " << connection << " from " << nodeID << " to " << _id << std::endl; return true; }
bool LocalNode::_cmdConnect( Command& command ) { EQASSERT( !command.getNode().isValid( )); EQASSERT( _inReceiverThread( )); const NodeConnectPacket* packet = command.get< NodeConnectPacket >(); ConnectionPtr connection = _incoming.getConnection(); const NodeID& nodeID = packet->nodeID; EQVERB << "handle connect " << packet << std::endl; EQASSERT( nodeID != _id ); EQASSERT( _connectionNodes.find( connection ) == _connectionNodes.end( )); NodePtr remoteNode; // No locking needed, only recv thread modifies NodeHash::const_iterator i = _nodes->find( nodeID ); if( i != _nodes->end( )) { remoteNode = i->second; if( remoteNode->isConnected( )) { // Node exists, probably simultaneous connect from peer EQINFO << "Already got node " << nodeID << ", refusing connect" << std::endl; // refuse connection NodeConnectReplyPacket reply( packet ); connection->send( reply, serialize( )); // NOTE: There is no close() here. The reply packet above has to be // received by the peer first, before closing the connection. _removeConnection( connection ); return true; } } // create and add connected node if( !remoteNode ) remoteNode = createNode( packet->nodeType ); std::string data = packet->nodeData; if( !remoteNode->deserialize( data )) EQWARN << "Error during node initialization" << std::endl; EQASSERTINFO( data.empty(), data ); EQASSERTINFO( remoteNode->_id == nodeID, remoteNode->_id << "!=" << nodeID ); remoteNode->_outgoing = connection; remoteNode->_state = STATE_CONNECTED; _connectionNodes[ connection ] = remoteNode; { base::ScopedMutex< base::SpinLock > mutex( _nodes ); _nodes.data[ remoteNode->_id ] = remoteNode; } EQVERB << "Added node " << nodeID << std::endl; // send our information as reply NodeConnectReplyPacket reply( packet ); reply.nodeID = _id; reply.nodeType = getType(); connection->send( reply, serialize( )); return true; }