summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2009-07-11 19:10:20 (GMT)
committerRemko Tronçon <git@el-tramo.be>2009-07-11 20:43:12 (GMT)
commit69f6c80767ae1b36d8761188e02983ed4b20c371 (patch)
tree6bf7e7fa406f17e33819e7688ebf97117255f4c6
parente1cc40f06af44243e288f5df2aafe292dd82a02a (diff)
downloadswift-69f6c80767ae1b36d8761188e02983ed4b20c371.zip
swift-69f6c80767ae1b36d8761188e02983ed4b20c371.tar.bz2
Implemented basic server stanza routing.
-rw-r--r--Swiften/Makefile.inc1
-rw-r--r--Swiften/Server/Makefile.inc5
-rw-r--r--Swiften/Server/ServerSession.cpp8
-rw-r--r--Swiften/Server/ServerSession.h17
-rw-r--r--Swiften/Server/ServerStanzaRouter.cpp67
-rw-r--r--Swiften/Server/ServerStanzaRouter.h24
-rw-r--r--Swiften/Server/UnitTest/Makefile.inc2
-rw-r--r--Swiften/Server/UnitTest/ServerStanzaRouterTest.cpp144
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);