diff options
author | Remko Tronçon <git@el-tramo.be> | 2009-07-11 19:10:20 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2009-07-11 20:43:12 (GMT) |
commit | 69f6c80767ae1b36d8761188e02983ed4b20c371 (patch) | |
tree | 6bf7e7fa406f17e33819e7688ebf97117255f4c6 | |
parent | e1cc40f06af44243e288f5df2aafe292dd82a02a (diff) | |
download | swift-contrib-69f6c80767ae1b36d8761188e02983ed4b20c371.zip swift-contrib-69f6c80767ae1b36d8761188e02983ed4b20c371.tar.bz2 |
Implemented basic server stanza routing.
-rw-r--r-- | Swiften/Makefile.inc | 1 | ||||
-rw-r--r-- | Swiften/Server/Makefile.inc | 5 | ||||
-rw-r--r-- | Swiften/Server/ServerSession.cpp | 8 | ||||
-rw-r--r-- | Swiften/Server/ServerSession.h | 17 | ||||
-rw-r--r-- | Swiften/Server/ServerStanzaRouter.cpp | 67 | ||||
-rw-r--r-- | Swiften/Server/ServerStanzaRouter.h | 24 | ||||
-rw-r--r-- | Swiften/Server/UnitTest/Makefile.inc | 2 | ||||
-rw-r--r-- | Swiften/Server/UnitTest/ServerStanzaRouterTest.cpp | 144 |
8 files changed, 268 insertions, 0 deletions
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 <boost/shared_ptr.hpp> + +#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<Stanza>) = 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 <cassert> +#include <algorithm> + +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> 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<ServerSession*>::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<ServerSession*> candidateSessions; + for (std::vector<ServerSession*>::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<ServerSession*>::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 <boost/shared_ptr.hpp> +#include <map> + +#include "Swiften/JID/JID.h" +#include "Swiften/Elements/Stanza.h" + +namespace Swift { + class ServerSession; + + class ServerStanzaRouter { + public: + ServerStanzaRouter(); + + bool routeStanza(boost::shared_ptr<Stanza>); + + void addClientSession(ServerSession*); + void removeClientSession(ServerSession*); + + private: + std::vector<ServerSession*> 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 <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#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<int>(session1.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(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<int>(session1.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(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<int>(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<int>(session1.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(session2.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(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<int>(session1.sentStanzas.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(session2.sentStanzas.size())); + } + + private: + boost::shared_ptr<Message> createMessageTo(const String& recipient) { + boost::shared_ptr<Message> 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> stanza) { + sentStanzas.push_back(stanza); + } + + JID jid; + int priority; + std::vector< boost::shared_ptr<Stanza> > sentStanzas; + }; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ServerStanzaRouterTest); |