void ConnectionCharacterintegration::test_connected() { // Dispatching an external op from the character should have no effect // if the external mind is already in place. m_character->linkExternal(m_connection); ASSERT_NOT_NULL(m_character->m_externalMind); ExternalMind * em = dynamic_cast<ExternalMind*>(m_character->m_externalMind); ASSERT_NOT_NULL(em); ASSERT_TRUE(em->isLinked()); ASSERT_TRUE(em->isLinkedTo(m_connection)); Router * saved_em = m_character->m_externalMind; RootOperation op; op->setFrom(m_character->getId()); m_connection->externalOperation(op, *m_connection); ASSERT_TRUE(!m_Link_send_sent.isValid()); ASSERT_NOT_EQUAL(m_logEvent_logged, TAKE_CHAR); ASSERT_NOT_NULL(m_character->m_externalMind); ASSERT_EQUAL(m_character->m_externalMind, saved_em); em = dynamic_cast<ExternalMind*>(m_character->m_externalMind); ASSERT_NOT_NULL(em); ASSERT_TRUE(em->isLinked()); ASSERT_TRUE(em->isLinkedTo(m_connection)); }
void ConnectionCharacterintegration::test_connect_up() { // Dispatching an external op from the character should cause it to // get connected up with an external mind RootOperation op; op->setFrom(m_character->getId()); ASSERT_NULL(m_character->m_externalMind); m_connection->externalOperation(op, *m_connection); ASSERT_NOT_NULL(m_character->m_externalMind); ExternalMind * em = dynamic_cast<ExternalMind*>(m_character->m_externalMind); ASSERT_NOT_NULL(em); ASSERT_TRUE(em->isLinked()); ASSERT_TRUE(em->isLinkedTo(m_connection)); ASSERT_TRUE(m_Link_send_sent.isValid()); ASSERT_EQUAL(m_Link_send_sent->getClassNo(), Atlas::Objects::Operation::INFO_NO); ASSERT_EQUAL(m_logEvent_logged, TAKE_CHAR); }
void ConnectionCharacterintegration::test_unlinked() { // Dispatching an external op from the character if the external mind is // already in place, but is not linked to a connection should link it // back up. m_character->linkExternal(m_connection); ASSERT_NOT_NULL(m_character->m_externalMind); ExternalMind * em = dynamic_cast<ExternalMind*>(m_character->m_externalMind); ASSERT_NOT_NULL(em); ASSERT_TRUE(em->isLinked()); ASSERT_TRUE(em->isLinkedTo(m_connection)); // Remove the link from the external mind back to m_connection em->linkUp(0); ASSERT_TRUE(!em->isLinked()); Router * saved_em = m_character->m_externalMind; RootOperation op; op->setFrom(m_character->getId()); m_connection->externalOperation(op, *m_connection); ASSERT_NOT_NULL(m_character->m_externalMind); ASSERT_EQUAL(m_character->m_externalMind, saved_em); em = dynamic_cast<ExternalMind*>(m_character->m_externalMind); ASSERT_NOT_NULL(em); ASSERT_TRUE(em->isLinked()); ASSERT_TRUE(em->isLinkedTo(m_connection)); ASSERT_TRUE(m_Link_send_sent.isValid()); ASSERT_EQUAL(m_logEvent_logged, TAKE_CHAR); }
/// \brief Handle an Info op response sent as reply to a teleport request /// /// @param op The Info op sent back as reply to a teleport request /// @param res The result set of replies void Peer::peerTeleportResponse(const Operation &op, OpVector &res) { log(INFO, "Got a peer teleport response"); // Response to a Create op const std::vector<Root> & args = op->getArgs(); if (args.size() < 1) { log(ERROR, "Malformed args in Info op"); return; } const Root & arg = args.front(); if (op->isDefaultRefno()) { log(ERROR, "Response to teleport has no refno"); return; } long iid = op->getRefno(); CommPeer *peer = dynamic_cast<CommPeer*>(&m_commClient); if(peer == 0) { log(ERROR, "Unable to get CommPeer object"); return; } TeleportMap::iterator I = m_teleports.find(iid); if (I == m_teleports.end()) { log(ERROR, "Info op for unknown create"); return; } TeleportState *s = I->second; assert (s != NULL); s->setCreated(); log(INFO, String::compose("Entity with ID %1 replicated on peer", iid)); // This is the sender entity. This is retreived again rather than // relying on a pointer (in the TeleportState object perhaps) as the // entity might have been deleted in the time between sending and response Entity * entity = BaseWorld::instance().getEntity(iid); if (entity == 0) { log(ERROR, String::compose("No entity found with ID: %1", iid)); // Clean up the teleport state object m_teleports.erase(I); return; } // If entity has a mind, add extra information in the Logout op if (s->isMind()) { Character * chr = dynamic_cast<Character *>(entity); if (!chr) { log(ERROR, "Entity is not a character"); return; } if (chr->m_externalMind == 0) { log(ERROR, "No external mind (though teleport state claims it)"); return; } ExternalMind * mind = dynamic_cast<ExternalMind*>(chr->m_externalMind); if (mind == 0 || !mind->isConnected()) { log(ERROR, "Mind is NULL or not connected"); return; } std::vector<Root> logout_args; Anonymous op_arg; op_arg->setId(entity->getId()); logout_args.push_back(op_arg); Anonymous ip_arg; ip_arg->setAttr("teleport_host", peer->getHost()); ip_arg->setAttr("teleport_port", peer->getPort()); ip_arg->setAttr("possess_key", s->getPossessKey()); ip_arg->setAttr("possess_entity_id", arg->getId()); logout_args.push_back(ip_arg); Logout logoutOp; logoutOp->setArgs(logout_args); logoutOp->setTo(entity->getId()); OpVector temp; mind->operation(logoutOp, temp); log(INFO, "Sent random key to connected mind"); } // FIXME Remove from the world cleanly, not delete. // Delete the entity from the current world Delete delOp; Anonymous del_arg; del_arg->setId(entity->getId()); delOp->setArgs1(del_arg); delOp->setTo(entity->getId()); entity->sendWorld(delOp); log(INFO, "Deleted entity from current server"); logEvent(EXPORT_ENT, String::compose("%1 - %2 Exported entity", getId(), entity->getId())); // Clean up the teleport state object m_teleports.erase(I); }
/// \brief Teleport an entity to the connected peer /// /// @param ent The entity to be teleported /// @return Returns 0 on success and -1 on failure int Peer::teleportEntity(const Entity * ent) { if (m_state != PEER_AUTHENTICATED) { log(ERROR, "Peer not authenticated yet."); return -1; } long iid = ent->getIntId(); if (m_teleports.find(iid) != m_teleports.end()) { log(INFO, "Transfer of this entity already in progress"); return -1; } struct timeval timeVal; gettimeofday(&timeVal, NULL); time_t teleport_time = timeVal.tv_sec; // Add a teleport state object to identify this teleport request TeleportState * s = new TeleportState(teleport_time); if (s == NULL) { log(ERROR, "Unable to allocate teleport state object"); return -1; } // Check if the entity has a mind const Character * chr = dynamic_cast<const Character *>(ent); ExternalMind * mind = 0; if (chr != 0 && chr->m_externalMind != 0) { mind = dynamic_cast<ExternalMind*>(chr->m_externalMind); } Atlas::Objects::Entity::Anonymous atlas_repr; ent->addToEntity(atlas_repr); Create op; op->setFrom(m_accountId); op->setSerialno(iid); op->setArgs1(atlas_repr); if (mind != 0 && mind->isConnected()) { // Entities with a mind require an additional one-time possess key that // is used by the client to authenticate a teleport on the destination // peer std::string key; log(INFO, "Entity has a mind. Generating random key"); // FIXME non-random, plus potetial timing attack. WFMath::MTRand generator; for(int i=0;i<32;i++) { char ch = (char)((int)'a' + generator.rand(25)); key += ch; } s->setKey(key); // Add an additional possess key argument log(INFO, String::compose("Adding possess key %1 to Create op", key)); Anonymous key_arg; key_arg->setAttr("possess_key", key); std::vector<Root> & create_args = op->modifyArgs(); create_args.push_back(key_arg); } m_commClient.send(op); log(INFO, "Sent Create op to peer"); // Set it as validated and add to the list of teleports s->setRequested(); m_teleports[iid] = s; log(INFO, "Added new teleport state"); return 0; }
int main() { TestWorld world; CommServer server; { Peer * p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); delete p; } { Peer * p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); Atlas::Objects::Operation::RootOperation op; OpVector res; p->operation(op, res); delete p; } { // Test the setting of authentiaction states Peer * p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); assert(p->getAuthState() == PEER_INIT); p->setAuthState(PEER_AUTHENTICATED); assert(p->getAuthState() == PEER_AUTHENTICATED); delete p; } { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); Atlas::Objects::Operation::Info op; OpVector res; p->operation(op, res); } // Authenticating (no args) { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATING); Atlas::Objects::Operation::Info op; OpVector res; p->operation(op, res); } // Authenticating (empty arg) { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATING); Atlas::Objects::Operation::Info op; Atlas::Objects::Root arg; op->setArgs1(arg); OpVector res; p->operation(op, res); } // Authenticating (full arg) { TestPeer *p = new TestPeer(*(CommSocket*)0, *(ServerRouting*)0, "addr", "1", 1); p->setAuthState(PEER_AUTHENTICATING); Atlas::Objects::Operation::Info op; Atlas::Objects::Root arg; arg->setId("2"); std::list<std::string> parents; parents.push_back("server"); arg->setParents(parents); op->setArgs1(arg); OpVector res; p->operation(op, res); assert(p->getAccountType() == "server"); } // Authenticated (no args) { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Atlas::Objects::Operation::Info op; OpVector res; p->operation(op, res); } { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); Atlas::Objects::Operation::Error op; OpVector res; p->operation(op, res); } // Not authenticated { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); Entity e("3", 3); int ret = p->teleportEntity(&e); assert(ret == -1); } // Authenticated { TestCommClient client(server, ""); Peer *p = new Peer(client, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Entity e("3", 3); int ret = p->teleportEntity(&e); assert(ret == 0); assert(stub_CommClient_sent_op.isValid()); assert(stub_CommClient_sent_op->getArgs().size() == 1); } // Re-teleport same entity { TestCommClient client(server, ""); Peer *p = new Peer(client, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Entity e("3", 3); int ret = p->teleportEntity(&e); assert(ret == 0); assert(stub_CommClient_sent_op.isValid()); assert(stub_CommClient_sent_op->getArgs().size() == 1); ret = p->teleportEntity(&e); assert(ret != 0); } // Character (no mind) { TestCommClient client(server, ""); Peer *p = new Peer(client, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Character e("3", 3); int ret = p->teleportEntity(&e); assert(ret == 0); assert(stub_CommClient_sent_op.isValid()); assert(stub_CommClient_sent_op->getArgs().size() == 1); } // Character (externl mind, unconnected) { TestCommClient client(server, ""); Peer *p = new Peer(client, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Character e("3", 3); e.m_externalMind = new ExternalMind(e); int ret = p->teleportEntity(&e); assert(ret == 0); assert(stub_CommClient_sent_op.isValid()); assert(stub_CommClient_sent_op->getArgs().size() == 1); } // Character (externl mind, connected) { TestCommClient client(server, ""); Peer *p = new Peer(client, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Character e("3", 3); ExternalMind * mind = new ExternalMind(e); mind->linkUp((Link*)23); e.m_externalMind = mind; int ret = p->teleportEntity(&e); assert(ret == 0); assert(stub_CommClient_sent_op.isValid()); assert(stub_CommClient_sent_op->getArgs().size() == 2); } // No arg { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); Atlas::Objects::Operation::Info op; OpVector res; p->peerTeleportResponse(op, res); } // Empty arg, no refno { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); Atlas::Objects::Operation::Info op; OpVector res; Atlas::Objects::Root arg; op->setArgs1(arg); p->peerTeleportResponse(op, res); } // Empty arg, made up refno, not CommPeer { TestCommClient *peerConn = new TestCommClient(*(CommServer*)0, "name"); Peer *p = new Peer(*peerConn, *(ServerRouting*)0, "addr", 6767, "1", 1); Atlas::Objects::Operation::Info op; OpVector res; Atlas::Objects::Root arg; op->setArgs1(arg); op->setRefno(23); p->peerTeleportResponse(op, res); } // Empty arg, made up refno { CommPeer *peerConn = new CommPeer(*(CommServer*)0, "name"); Peer *p = new Peer(*peerConn, *(ServerRouting*)0, "addr", 6767, "1", 1); Atlas::Objects::Operation::Info op; OpVector res; Atlas::Objects::Root arg; op->setArgs1(arg); op->setRefno(23); p->peerTeleportResponse(op, res); } // Empty arg, refno that matches earlier teleport, not in world { CommPeer *peerConn = new CommPeer(server, "name"); Peer *p = new Peer(*peerConn, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Entity e("23", 23); int ret = p->teleportEntity(&e); assert(ret == 0); Atlas::Objects::Operation::Info op; OpVector res; Atlas::Objects::Root arg; op->setArgs1(arg); op->setRefno(23); p->peerTeleportResponse(op, res); } // Empty arg, refno that matches earlier teleport, in world { CommPeer *peerConn = new CommPeer(server, "name"); Peer *p = new Peer(*peerConn, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Entity e("23", 23); int ret = p->teleportEntity(&e); assert(ret == 0); world.test_addEntity(&e, 23); Atlas::Objects::Operation::Info op; OpVector res; Atlas::Objects::Root arg; op->setArgs1(arg); op->setRefno(23); p->peerTeleportResponse(op, res); world.test_delEntity(23); } // Empty arg, refno that matches earlier teleport, with mind { CommPeer *peerConn = new CommPeer(server, "name"); Peer *p = new Peer(*peerConn, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Character e("23", 23); ExternalMind * mind = new ExternalMind(e); mind->linkUp((Link*)23); e.m_externalMind = mind; int ret = p->teleportEntity(&e); assert(ret == 0); world.test_addEntity(&e, 23); Atlas::Objects::Operation::Info op; OpVector res; Atlas::Objects::Root arg; op->setArgs1(arg); op->setRefno(23); p->peerTeleportResponse(op, res); world.test_delEntity(23); } // No teleports to clear { Peer *p = new Peer(*(CommSocket*)0, *(ServerRouting*)0, "addr", 6767, "1", 1); p->cleanTeleports(); } // One teleport to clear { TestCommClient client(server, ""); Peer *p = new Peer(client, *(ServerRouting*)0, "addr", 6767, "1", 1); p->setAuthState(PEER_AUTHENTICATED); Entity e("23", 23); int ret = p->teleportEntity(&e); assert(ret == 0); p->cleanTeleports(); } return 0; }