summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/StreamManagement')
-rw-r--r--Swiften/StreamManagement/SConscript8
-rw-r--r--Swiften/StreamManagement/StanzaAckRequester.cpp39
-rw-r--r--Swiften/StreamManagement/StanzaAckRequester.h33
-rw-r--r--Swiften/StreamManagement/StanzaAckResponder.cpp24
-rw-r--r--Swiften/StreamManagement/StanzaAckResponder.h30
-rw-r--r--Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp120
-rw-r--r--Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp98
7 files changed, 352 insertions, 0 deletions
diff --git a/Swiften/StreamManagement/SConscript b/Swiften/StreamManagement/SConscript
new file mode 100644
index 0000000..d3fab8e
--- /dev/null
+++ b/Swiften/StreamManagement/SConscript
@@ -0,0 +1,8 @@
+Import("swiften_env")
+
+sources = [
+ "StanzaAckRequester.cpp",
+ "StanzaAckResponder.cpp",
+ ]
+
+swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.StaticObject(sources)) \ No newline at end of file
diff --git a/Swiften/StreamManagement/StanzaAckRequester.cpp b/Swiften/StreamManagement/StanzaAckRequester.cpp
new file mode 100644
index 0000000..b007675
--- /dev/null
+++ b/Swiften/StreamManagement/StanzaAckRequester.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/StreamManagement/StanzaAckRequester.h"
+
+#include <boost/numeric/conversion/cast.hpp>
+
+namespace Swift {
+
+static const unsigned int MAX_HANDLED_STANZA_COUNT = boost::numeric_cast<unsigned int>((1ULL<<32) - 1);
+
+StanzaAckRequester::StanzaAckRequester() : lastHandledStanzasCount(0) {
+
+}
+
+void StanzaAckRequester::handleStanzaSent(boost::shared_ptr<Stanza> stanza) {
+ unackedStanzas.push_back(stanza);
+ onRequestAck();
+}
+
+void StanzaAckRequester::handleAckReceived(unsigned int handledStanzasCount) {
+ unsigned int i = lastHandledStanzasCount;
+ while (i != handledStanzasCount) {
+ if (unackedStanzas.size() == 0) {
+ std::cerr << "Warning: Server acked more stanzas than we sent" << std::endl;
+ break;
+ }
+ boost::shared_ptr<Stanza> ackedStanza = unackedStanzas.front();
+ unackedStanzas.pop_front();
+ onStanzaAcked(ackedStanza);
+ i = (i == MAX_HANDLED_STANZA_COUNT ? 0 : i + 1);
+ }
+ lastHandledStanzasCount = handledStanzasCount;
+}
+
+}
diff --git a/Swiften/StreamManagement/StanzaAckRequester.h b/Swiften/StreamManagement/StanzaAckRequester.h
new file mode 100644
index 0000000..89f068e
--- /dev/null
+++ b/Swiften/StreamManagement/StanzaAckRequester.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <deque>
+
+#include "Swiften/Elements/Stanza.h"
+#include "Swiften/Base/boost_bsignals.h"
+
+namespace Swift {
+ class StanzaAckRequester {
+ public:
+ StanzaAckRequester();
+
+ void handleStanzaSent(boost::shared_ptr<Stanza> stanza);
+ void handleAckReceived(unsigned int handledStanzasCount);
+
+ public:
+ boost::signal<void ()> onRequestAck;
+ boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked;
+
+ private:
+ friend class StanzaAckRequesterTest;
+ unsigned int lastHandledStanzasCount;
+ std::deque<boost::shared_ptr<Stanza> > unackedStanzas;
+ };
+
+}
diff --git a/Swiften/StreamManagement/StanzaAckResponder.cpp b/Swiften/StreamManagement/StanzaAckResponder.cpp
new file mode 100644
index 0000000..05ab5c4
--- /dev/null
+++ b/Swiften/StreamManagement/StanzaAckResponder.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/StreamManagement/StanzaAckResponder.h"
+
+#include <boost/numeric/conversion/cast.hpp>
+
+namespace Swift {
+
+static const unsigned int MAX_HANDLED_STANZA_COUNT = boost::numeric_cast<unsigned int>((1ULL<<32) - 1);
+
+StanzaAckResponder::StanzaAckResponder() : handledStanzasCount(0) {
+}
+
+void StanzaAckResponder::handleStanzaReceived() {
+ handledStanzasCount = (handledStanzasCount == MAX_HANDLED_STANZA_COUNT ? 0 : handledStanzasCount + 1);
+}
+
+void StanzaAckResponder::handleAckRequestReceived() {
+ onAck(handledStanzasCount);}
+}
diff --git a/Swiften/StreamManagement/StanzaAckResponder.h b/Swiften/StreamManagement/StanzaAckResponder.h
new file mode 100644
index 0000000..bc83aa1
--- /dev/null
+++ b/Swiften/StreamManagement/StanzaAckResponder.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Elements/Stanza.h"
+#include "Swiften/Base/boost_bsignals.h"
+
+namespace Swift {
+ class StanzaAckResponder {
+ public:
+ StanzaAckResponder();
+
+ void handleStanzaReceived();
+ void handleAckRequestReceived();
+
+ public:
+ boost::signal<void (unsigned int /* handledStanzaCount */)> onAck;
+
+ private:
+ friend class StanzaAckResponderTest;
+ unsigned int handledStanzasCount;
+ };
+
+}
diff --git a/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp b/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp
new file mode 100644
index 0000000..70fe6eb
--- /dev/null
+++ b/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <boost/bind.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include "Swiften/StreamManagement/StanzaAckRequester.h"
+#include "Swiften/Elements/Message.h"
+
+using namespace Swift;
+
+namespace Swift {
+
+class StanzaAckRequesterTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(StanzaAckRequesterTest);
+ CPPUNIT_TEST(testHandleStanzaSent_RequestsAck);
+ CPPUNIT_TEST(testHandleAckReceived_AcksStanza);
+ CPPUNIT_TEST(testHandleAckReceived_AcksMultipleStanzas);
+ CPPUNIT_TEST(testHandleAckReceived_MultipleAcks);
+ CPPUNIT_TEST(testHandleAckReceived_WrapAround);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ acksRequested = 0;
+ }
+
+ void testHandleStanzaSent_RequestsAck() {
+ std::auto_ptr<StanzaAckRequester> testling(createRequester());
+ testling->handleStanzaSent(createMessage("m1"));
+
+ CPPUNIT_ASSERT_EQUAL(1, acksRequested);
+ }
+
+ void testHandleAckReceived_AcksStanza() {
+ std::auto_ptr<StanzaAckRequester> testling(createRequester());
+ testling->handleStanzaSent(createMessage("m1"));
+
+ testling->handleAckReceived(1);
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(ackedStanzas.size()));
+ CPPUNIT_ASSERT_EQUAL(String("m1"), ackedStanzas[0]->getID());
+ }
+
+ void testHandleAckReceived_AcksMultipleStanzas() {
+ std::auto_ptr<StanzaAckRequester> testling(createRequester());
+ testling->handleStanzaSent(createMessage("m1"));
+ testling->handleStanzaSent(createMessage("m2"));
+
+ testling->handleAckReceived(2);
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(ackedStanzas.size()));
+ CPPUNIT_ASSERT_EQUAL(String("m1"), ackedStanzas[0]->getID());
+ CPPUNIT_ASSERT_EQUAL(String("m2"), ackedStanzas[1]->getID());
+ }
+
+ void testHandleAckReceived_MultipleAcks() {
+ std::auto_ptr<StanzaAckRequester> testling(createRequester());
+ testling->handleStanzaSent(createMessage("m1"));
+ testling->handleAckReceived(1);
+
+ testling->handleStanzaSent(createMessage("m2"));
+ testling->handleStanzaSent(createMessage("m3"));
+ testling->handleAckReceived(3);
+
+ CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(ackedStanzas.size()));
+ CPPUNIT_ASSERT_EQUAL(String("m1"), ackedStanzas[0]->getID());
+ CPPUNIT_ASSERT_EQUAL(String("m2"), ackedStanzas[1]->getID());
+ CPPUNIT_ASSERT_EQUAL(String("m3"), ackedStanzas[2]->getID());
+ }
+
+ // Handle stanza ack count wrapping, as per the XEP
+ void testHandleAckReceived_WrapAround() {
+ std::auto_ptr<StanzaAckRequester> testling(createRequester());
+ testling->lastHandledStanzasCount = boost::numeric_cast<unsigned int>((1ULL<<32) - 1);
+ testling->handleStanzaSent(createMessage("m1"));
+ testling->handleStanzaSent(createMessage("m2"));
+
+ testling->handleAckReceived(1);
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(ackedStanzas.size()));
+ CPPUNIT_ASSERT_EQUAL(String("m1"), ackedStanzas[0]->getID());
+ CPPUNIT_ASSERT_EQUAL(String("m2"), ackedStanzas[1]->getID());
+ }
+
+ private:
+ Message::ref createMessage(const String& id) {
+ Message::ref result(new Message());
+ result->setID(id);
+ return result;
+ }
+
+ StanzaAckRequester* createRequester() {
+ StanzaAckRequester* requester = new StanzaAckRequester();
+ requester->onRequestAck.connect(boost::bind(&StanzaAckRequesterTest::handleRequestAck, this));
+ requester->onStanzaAcked.connect(boost::bind(&StanzaAckRequesterTest::handleStanzaAcked, this, _1));
+ return requester;
+ }
+
+ void handleRequestAck() {
+ acksRequested++;
+ }
+
+ void handleStanzaAcked(boost::shared_ptr<Stanza> stanza) {
+ ackedStanzas.push_back(stanza);
+ }
+
+ private:
+ int acksRequested;
+ std::vector< boost::shared_ptr<Stanza> > ackedStanzas;
+};
+
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Swift::StanzaAckRequesterTest);
diff --git a/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp b/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp
new file mode 100644
index 0000000..fa2b782
--- /dev/null
+++ b/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <boost/bind.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include "Swiften/StreamManagement/StanzaAckResponder.h"
+#include "Swiften/Elements/Message.h"
+
+using namespace Swift;
+
+namespace Swift {
+
+class StanzaAckResponderTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(StanzaAckResponderTest);
+ CPPUNIT_TEST(testHandleAckRequestReceived_AcksStanza);
+ CPPUNIT_TEST(testHandleAckRequestReceived_AcksMultipleStanzas);
+ CPPUNIT_TEST(testHandleAckRequestReceived_MultipleAcks);
+ CPPUNIT_TEST(testHandleAckRequestReceived_WrapAround);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void testHandleAckRequestReceived_AcksStanza() {
+ std::auto_ptr<StanzaAckResponder> testling(createResponder());
+ testling->handleStanzaReceived();
+
+ testling->handleAckRequestReceived();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(acks.size()));
+ CPPUNIT_ASSERT_EQUAL(1U, acks[0]);
+ }
+
+ void testHandleAckRequestReceived_AcksMultipleStanzas() {
+ std::auto_ptr<StanzaAckResponder> testling(createResponder());
+ testling->handleStanzaReceived();
+ testling->handleStanzaReceived();
+
+ testling->handleAckRequestReceived();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(acks.size()));
+ CPPUNIT_ASSERT_EQUAL(2U, acks[0]);
+ }
+
+ void testHandleAckRequestReceived_MultipleAcks() {
+ std::auto_ptr<StanzaAckResponder> testling(createResponder());
+ testling->handleStanzaReceived();
+ testling->handleAckRequestReceived();
+
+ testling->handleStanzaReceived();
+ testling->handleAckRequestReceived();
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(acks.size()));
+ CPPUNIT_ASSERT_EQUAL(1U, acks[0]);
+ CPPUNIT_ASSERT_EQUAL(2U, acks[1]);
+ }
+
+ // Handle stanza ack count wrapping, as per the XEP
+ void testHandleAckRequestReceived_WrapAround() {
+ std::auto_ptr<StanzaAckResponder> testling(createResponder());
+ testling->handledStanzasCount = boost::numeric_cast<unsigned int>((1ULL<<32) - 1);
+ testling->handleStanzaReceived();
+ testling->handleStanzaReceived();
+
+ testling->handleAckRequestReceived();
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(acks.size()));
+ CPPUNIT_ASSERT_EQUAL(1U, acks[0]);
+ }
+
+ private:
+ Message::ref createMessage(const String& id) {
+ Message::ref result(new Message());
+ result->setID(id);
+ return result;
+ }
+
+ StanzaAckResponder* createResponder() {
+ StanzaAckResponder* responder = new StanzaAckResponder();
+ responder->onAck.connect(boost::bind(&StanzaAckResponderTest::handleAck, this, _1));
+ return responder;
+ }
+
+ void handleAck(unsigned int h) {
+ acks.push_back(h);
+ }
+
+ private:
+ std::vector<unsigned int> acks;
+};
+
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Swift::StanzaAckResponderTest);