diff options
| author | Remko Tronçon <git@el-tramo.be> | 2010-08-29 12:51:45 (GMT) | 
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2010-08-29 13:30:18 (GMT) | 
| commit | 0091fcc571758791442f82ece2a72444b6fe79cf (patch) | |
| tree | 807f20a4047604a87f56d247d8ad7180489fe82b | |
| parent | 901f620b6ccabde19ef460368028fa0464aa56c5 (diff) | |
| download | swift-contrib-0091fcc571758791442f82ece2a72444b6fe79cf.zip swift-contrib-0091fcc571758791442f82ece2a72444b6fe79cf.tar.bz2 | |
Added Stanza Ack Requester & Responder.
| -rw-r--r-- | QA/UnitTest/SConscript | 3 | ||||
| -rw-r--r-- | Swiften/Elements/Message.h | 4 | ||||
| -rw-r--r-- | Swiften/Elements/Stanza.h | 1 | ||||
| -rw-r--r-- | Swiften/Elements/StanzaAck.h | 10 | ||||
| -rw-r--r-- | Swiften/Parser/StanzaAckParser.cpp | 1 | ||||
| -rw-r--r-- | Swiften/Parser/UnitTest/StanzaAckParserTest.cpp | 2 | ||||
| -rw-r--r-- | Swiften/SConscript | 4 | ||||
| -rw-r--r-- | Swiften/StreamManagement/SConscript | 8 | ||||
| -rw-r--r-- | Swiften/StreamManagement/StanzaAckRequester.cpp | 39 | ||||
| -rw-r--r-- | Swiften/StreamManagement/StanzaAckRequester.h | 33 | ||||
| -rw-r--r-- | Swiften/StreamManagement/StanzaAckResponder.cpp | 24 | ||||
| -rw-r--r-- | Swiften/StreamManagement/StanzaAckResponder.h | 30 | ||||
| -rw-r--r-- | Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp | 120 | ||||
| -rw-r--r-- | Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp | 98 | 
14 files changed, 367 insertions, 10 deletions
| diff --git a/QA/UnitTest/SConscript b/QA/UnitTest/SConscript index cd9cdc8..d47474d 100644 --- a/QA/UnitTest/SConscript +++ b/QA/UnitTest/SConscript @@ -5,6 +5,7 @@ Import("env")  if env["TEST"] :  	if env["SCONS_STAGE"] == "flags" :  		env["UNITTEST_SOURCES"] = [] +		env["UNITTEST_OBJECTS"] = []  	if env["SCONS_STAGE"] == "test" :  		myenv = env.Clone()  		myenv.MergeFlags(env.get("CHECKER_FLAGS","")) @@ -23,7 +24,7 @@ if env["TEST"] :  			myenv.Append(CPPDEFINES = ["HAVE_LIBXML"])  		if env.get("HAVE_EXPAT") :  			myenv.Append(CPPDEFINES = ["HAVE_EXPAT"]) -		checker = myenv.Program("checker", env["UNITTEST_SOURCES"]) +		checker = myenv.Program("checker", env["UNITTEST_SOURCES"] + env["UNITTEST_OBJECTS"])  		for i in ["HOME", "USERPROFILE", "APPDATA"]:  			if os.environ.get(i, "") :  				myenv["ENV"][i] = os.environ[i] diff --git a/Swiften/Elements/Message.h b/Swiften/Elements/Message.h index f42aec6..e5e00ab 100644 --- a/Swiften/Elements/Message.h +++ b/Swiften/Elements/Message.h @@ -9,6 +9,7 @@  #include <boost/optional.hpp>  #include "Swiften/Base/String.h" +#include "Swiften/Base/Shared.h"  #include "Swiften/Elements/Body.h"  #include "Swiften/Elements/Subject.h"  #include "Swiften/Elements/ErrorPayload.h" @@ -16,8 +17,7 @@  namespace Swift  { -	class Message : public Stanza -	{ +	class Message : public Stanza, public Shared<Message> {  	  public:  			enum Type { Normal, Chat, Error, Groupchat, Headline }; diff --git a/Swiften/Elements/Stanza.h b/Swiften/Elements/Stanza.h index 20fb557..5d8fd6c 100644 --- a/Swiften/Elements/Stanza.h +++ b/Swiften/Elements/Stanza.h @@ -14,6 +14,7 @@  #include "Swiften/Elements/Element.h"  #include "Swiften/Elements/Payload.h"  #include "Swiften/Base/String.h" +#include "Swiften/Base/Shared.h"  #include "Swiften/Base/foreach.h"  #include "Swiften/JID/JID.h" diff --git a/Swiften/Elements/StanzaAck.h b/Swiften/Elements/StanzaAck.h index a1a39f8..eaf4e26 100644 --- a/Swiften/Elements/StanzaAck.h +++ b/Swiften/Elements/StanzaAck.h @@ -12,21 +12,23 @@  namespace Swift {  	class StanzaAck : public Element, public Shared<StanzaAck> {  		public: -			StanzaAck() : handledStanzasCount(-1) {} +			StanzaAck() : valid(false), handledStanzasCount(0) {} -			int getHandledStanzasCount() const { +			unsigned int getHandledStanzasCount() const {  				return handledStanzasCount;  			}  			void setHandledStanzasCount(int i) {  				handledStanzasCount = i; +				valid = true;  			}  			bool isValid() const { -				return handledStanzasCount != -1; +				return valid;  			}  		private: -			int handledStanzasCount; +			bool valid; +			unsigned int handledStanzasCount;  	};  } diff --git a/Swiften/Parser/StanzaAckParser.cpp b/Swiften/Parser/StanzaAckParser.cpp index 62e912b..d85eb9b 100644 --- a/Swiften/Parser/StanzaAckParser.cpp +++ b/Swiften/Parser/StanzaAckParser.cpp @@ -20,7 +20,6 @@ void StanzaAckParser::handleStartElement(const String&, const String&, const Att  			getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<int>(handledStanzasString.getUTF8String()));  		}  		catch (const boost::bad_lexical_cast &) { -			getElementGeneric()->setHandledStanzasCount(-1);  		}  	}  	++depth; diff --git a/Swiften/Parser/UnitTest/StanzaAckParserTest.cpp b/Swiften/Parser/UnitTest/StanzaAckParserTest.cpp index 39e67a7..b90af6e 100644 --- a/Swiften/Parser/UnitTest/StanzaAckParserTest.cpp +++ b/Swiften/Parser/UnitTest/StanzaAckParserTest.cpp @@ -28,7 +28,7 @@ class StanzaAckParserTest : public CppUnit::TestFixture {  			CPPUNIT_ASSERT(parser.parse("<a h=\"12\" xmlns=\"urn:xmpp:sm:2\"/>"));  			CPPUNIT_ASSERT(testling.getElementGeneric()->isValid()); -			CPPUNIT_ASSERT_EQUAL(12, testling.getElementGeneric()->getHandledStanzasCount()); +			CPPUNIT_ASSERT_EQUAL(12U, testling.getElementGeneric()->getHandledStanzasCount());  		}  		void testParse_Invalid() { diff --git a/Swiften/SConscript b/Swiften/SConscript index 3e5c35b..a23efa0 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -129,6 +129,7 @@ if env["SCONS_STAGE"] == "build" :  			"History",  			"StreamStack",  			"LinkLocal", +			"StreamManagement",  		])  	SConscript(test_only = True, dirs = [  			"QA", @@ -225,7 +226,8 @@ if env["SCONS_STAGE"] == "build" :  			File("Serializer/UnitTest/AuthRequestSerializerTest.cpp"),  			File("Serializer/UnitTest/AuthResponseSerializerTest.cpp"),  			File("Serializer/XML/UnitTest/XMLElementTest.cpp"), -			File("Server/UnitTest/ServerStanzaRouterTest.cpp"), +			File("StreamManagement/UnitTest/StanzaAckRequesterTest.cpp"), +			File("StreamManagement/UnitTest/StanzaAckResponderTest.cpp"),  			File("StreamStack/UnitTest/StreamStackTest.cpp"),  			File("StreamStack/UnitTest/XMPPLayerTest.cpp"),  			File("StringCodecs/UnitTest/Base64Test.cpp"), 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); | 
 Swift
 Swift