From 69f6c80767ae1b36d8761188e02983ed4b20c371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Sat, 11 Jul 2009 21:10:20 +0200 Subject: Implemented basic server stanza routing. diff --git a/Swiften/Makefile.inc b/Swiften/Makefile.inc index 0ed7bab..6e47259 100644 --- a/Swiften/Makefile.inc +++ b/Swiften/Makefile.inc @@ -21,6 +21,7 @@ include Swiften/Presence/Makefile.inc include Swiften/Notifier/Makefile.inc include Swiften/History/Makefile.inc include Swiften/Avatars/Makefile.inc +include Swiften/Server/Makefile.inc CPPFLAGS += $(SQLITE_CPPFLAGS) diff --git a/Swiften/Server/Makefile.inc b/Swiften/Server/Makefile.inc new file mode 100644 index 0000000..8dd6051 --- /dev/null +++ b/Swiften/Server/Makefile.inc @@ -0,0 +1,5 @@ +SWIFTEN_SOURCES += \ + Swiften/Server/ServerSession.cpp \ + Swiften/Server/ServerStanzaRouter.cpp + +include Swiften/Server/UnitTest/Makefile.inc diff --git a/Swiften/Server/ServerSession.cpp b/Swiften/Server/ServerSession.cpp new file mode 100644 index 0000000..e62957c --- /dev/null +++ b/Swiften/Server/ServerSession.cpp @@ -0,0 +1,8 @@ +#include "Swiften/Server/ServerSession.h" + +namespace Swift { + +ServerSession::~ServerSession() { +} + +} diff --git a/Swiften/Server/ServerSession.h b/Swiften/Server/ServerSession.h new file mode 100644 index 0000000..1ebf68e --- /dev/null +++ b/Swiften/Server/ServerSession.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include "Swiften/Elements/Stanza.h" + +namespace Swift { + class ServerSession { + public: + virtual ~ServerSession(); + + virtual const JID& getJID() const = 0; + virtual int getPriority() const = 0; + + virtual void sendStanza(boost::shared_ptr) = 0; + }; +} diff --git a/Swiften/Server/ServerStanzaRouter.cpp b/Swiften/Server/ServerStanzaRouter.cpp new file mode 100644 index 0000000..5661de5 --- /dev/null +++ b/Swiften/Server/ServerStanzaRouter.cpp @@ -0,0 +1,67 @@ +#include "Swiften/Server/ServerStanzaRouter.h" +#include "Swiften/Server/ServerSession.h" + +#include +#include + +namespace Swift { + +namespace { + struct PriorityLessThan { + bool operator()(const ServerSession* s1, const ServerSession* s2) const { + return s1->getPriority() < s2->getPriority(); + } + }; + + struct HasJID { + HasJID(const JID& jid) : jid(jid) {} + bool operator()(const ServerSession* session) const { + return session->getJID().equals(jid, JID::WithResource); + } + JID jid; + }; +} + +ServerStanzaRouter::ServerStanzaRouter() { +} + +bool ServerStanzaRouter::routeStanza(boost::shared_ptr stanza) { + JID to = stanza->getTo(); + assert(to.isValid()); + + // For a full JID, first try to route to a session with the full JID + if (!to.isBare()) { + std::vector::const_iterator i = std::find_if(clientSessions_.begin(), clientSessions_.end(), HasJID(to)); + if (i != clientSessions_.end()) { + (*i)->sendStanza(stanza); + return true; + } + } + + // Look for candidate sessions + to = to.toBare(); + std::vector candidateSessions; + for (std::vector::const_iterator i = clientSessions_.begin(); i != clientSessions_.end(); ++i) { + if ((*i)->getJID().equals(to, JID::WithoutResource) && (*i)->getPriority() >= 0) { + candidateSessions.push_back(*i); + } + } + if (candidateSessions.empty()) { + return false; + } + + // Find the session with the highest priority + std::vector::const_iterator i = std::max_element(clientSessions_.begin(), clientSessions_.end(), PriorityLessThan()); + (*i)->sendStanza(stanza); + return true; +} + +void ServerStanzaRouter::addClientSession(ServerSession* clientSession) { + clientSessions_.push_back(clientSession); +} + +void ServerStanzaRouter::removeClientSession(ServerSession* clientSession) { + clientSessions_.erase(std::remove(clientSessions_.begin(), clientSessions_.end(), clientSession), clientSessions_.end()); +} + +} diff --git a/Swiften/Server/ServerStanzaRouter.h b/Swiften/Server/ServerStanzaRouter.h new file mode 100644 index 0000000..057a2ea --- /dev/null +++ b/Swiften/Server/ServerStanzaRouter.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#include "Swiften/JID/JID.h" +#include "Swiften/Elements/Stanza.h" + +namespace Swift { + class ServerSession; + + class ServerStanzaRouter { + public: + ServerStanzaRouter(); + + bool routeStanza(boost::shared_ptr); + + void addClientSession(ServerSession*); + void removeClientSession(ServerSession*); + + private: + std::vector clientSessions_; + }; +} diff --git a/Swiften/Server/UnitTest/Makefile.inc b/Swiften/Server/UnitTest/Makefile.inc new file mode 100644 index 0000000..a61ec06 --- /dev/null +++ b/Swiften/Server/UnitTest/Makefile.inc @@ -0,0 +1,2 @@ +UNITTEST_SOURCES += \ + Swiften/Server/UnitTest/ServerStanzaRouterTest.cpp diff --git a/Swiften/Server/UnitTest/ServerStanzaRouterTest.cpp b/Swiften/Server/UnitTest/ServerStanzaRouterTest.cpp new file mode 100644 index 0000000..03a607a --- /dev/null +++ b/Swiften/Server/UnitTest/ServerStanzaRouterTest.cpp @@ -0,0 +1,144 @@ +#include +#include + +#include "Swiften/Elements/Message.h" +#include "Swiften/Server/ServerStanzaRouter.h" +#include "Swiften/Server/ServerSession.h" + +using namespace Swift; + +class ServerStanzaRouterTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ServerStanzaRouterTest); + CPPUNIT_TEST(testRouteStanza_FullJID); + CPPUNIT_TEST(testRouteStanza_FullJIDWithNegativePriority); + CPPUNIT_TEST(testRouteStanza_FullJIDWithOnlyBareJIDMatchingSession); + CPPUNIT_TEST(testRouteStanza_BareJIDWithoutMatchingSession); + CPPUNIT_TEST(testRouteStanza_BareJIDWithMultipleSessions); + CPPUNIT_TEST(testRouteStanza_BareJIDWithOnlyNegativePriorities); + CPPUNIT_TEST(testRouteStanza_BareJIDWithChangingPresence); + CPPUNIT_TEST_SUITE_END(); + + public: + ServerStanzaRouterTest() {} + + void setUp() { + } + + void tearDown() { + } + + void testRouteStanza_FullJID() { + ServerStanzaRouter testling; + MockServerSession session1(JID("foo@bar.com/Bla"), 0); + testling.addClientSession(&session1); + MockServerSession session2(JID("foo@bar.com/Baz"), 0); + testling.addClientSession(&session2); + + bool result = testling.routeStanza(createMessageTo("foo@bar.com/Baz")); + + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(0, static_cast(session1.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast(session2.sentStanzas.size())); + } + + void testRouteStanza_FullJIDWithNegativePriority() { + ServerStanzaRouter testling; + MockServerSession session1(JID("foo@bar.com/Bla"), -1); + testling.addClientSession(&session1); + MockServerSession session2(JID("foo@bar.com/Baz"), 0); + testling.addClientSession(&session2); + + bool result = testling.routeStanza(createMessageTo("foo@bar.com/Bla")); + + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(1, static_cast(session1.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast(session2.sentStanzas.size())); + } + + void testRouteStanza_FullJIDWithOnlyBareJIDMatchingSession() { + ServerStanzaRouter testling; + MockServerSession session(JID("foo@bar.com/Bla"), 0); + testling.addClientSession(&session); + + bool result = testling.routeStanza(createMessageTo("foo@bar.com/Baz")); + + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(1, static_cast(session.sentStanzas.size())); + } + + void testRouteStanza_BareJIDWithoutMatchingSession() { + ServerStanzaRouter testling; + + bool result = testling.routeStanza(createMessageTo("foo@bar.com")); + + CPPUNIT_ASSERT(!result); + } + + void testRouteStanza_BareJIDWithMultipleSessions() { + ServerStanzaRouter testling; + MockServerSession session1(JID("foo@bar.com/Bla"), 1); + testling.addClientSession(&session1); + MockServerSession session2(JID("foo@bar.com/Baz"), 8); + testling.addClientSession(&session2); + MockServerSession session3(JID("foo@bar.com/Bar"), 5); + testling.addClientSession(&session3); + + bool result = testling.routeStanza(createMessageTo("foo@bar.com")); + + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(0, static_cast(session1.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast(session2.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast(session3.sentStanzas.size())); + } + + void testRouteStanza_BareJIDWithOnlyNegativePriorities() { + ServerStanzaRouter testling; + MockServerSession session(JID("foo@bar.com/Bla"), -1); + testling.addClientSession(&session); + + bool result = testling.routeStanza(createMessageTo("foo@bar.com")); + + CPPUNIT_ASSERT(!result); + } + + void testRouteStanza_BareJIDWithChangingPresence() { + ServerStanzaRouter testling; + MockServerSession session1(JID("foo@bar.com/Baz"), 8); + testling.addClientSession(&session1); + MockServerSession session2(JID("foo@bar.com/Bar"), 5); + testling.addClientSession(&session2); + + session1.priority = 3; + session2.priority = 4; + bool result = testling.routeStanza(createMessageTo("foo@bar.com")); + + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(0, static_cast(session1.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast(session2.sentStanzas.size())); + } + + private: + boost::shared_ptr createMessageTo(const String& recipient) { + boost::shared_ptr message(new Message()); + message->setTo(JID(recipient)); + return message; + } + + class MockServerSession : public ServerSession { + public: + MockServerSession(const JID& jid, int priority) : jid(jid), priority(priority) {} + + virtual const JID& getJID() const { return jid; } + virtual int getPriority() const { return priority; } + + virtual void sendStanza(boost::shared_ptr stanza) { + sentStanzas.push_back(stanza); + } + + JID jid; + int priority; + std::vector< boost::shared_ptr > sentStanzas; + }; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ServerStanzaRouterTest); -- cgit v0.10.2-6-g49f6