From 1b47266d6b955fb533b4c272b4bcc58693078a1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Fri, 11 Sep 2009 15:46:08 +0200
Subject: Disable WhitespacePingLayer on disconnect + Timer refactoring.

Timer now no longer runs in its own thread, but in the main Boost
IOService thread.

diff --git a/QA/Swiften/ClientTest/ClientTest.cpp b/QA/Swiften/ClientTest/ClientTest.cpp
index b628a8d..412eb53 100644
--- a/QA/Swiften/ClientTest/ClientTest.cpp
+++ b/QA/Swiften/ClientTest/ClientTest.cpp
@@ -7,6 +7,8 @@
 #include "Swiften/EventLoop/SimpleEventLoop.h"
 #include "Swiften/Queries/Requests/GetRosterRequest.h"
 #include "Swiften/Client/ClientXMLTracer.h"
+#include "Swiften/Network/BoostIOServiceThread.h"
+#include "Swiften/Network/MainBoostIOServiceThread.h"
 
 using namespace Swift;
 
@@ -44,7 +46,7 @@ int main(int, char**) {
 	client->connect();
 
 	{
-		boost::shared_ptr<Timer> timer(new Timer(10000));
+		boost::shared_ptr<Timer> timer(new Timer(10000, &MainBoostIOServiceThread::getInstance().getIOService()));
 		timer->onTick.connect(boost::bind(&SimpleEventLoop::stop, &eventLoop));
 		timer->start();
 
diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp
index 1409195..ae98ee6 100644
--- a/Swiften/Client/ClientSession.cpp
+++ b/Swiften/Client/ClientSession.cpp
@@ -96,6 +96,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) {
 			// Add a whitespace ping layer
 			whitespacePingLayer_ = boost::shared_ptr<WhitespacePingLayer>(new WhitespacePingLayer());
 			getStreamStack()->addLayer(whitespacePingLayer_);
+			whitespacePingLayer_->setActive();
 
 			if (streamFeatures->hasSession()) {
 				needSessionStart_ = true;
@@ -196,6 +197,10 @@ void ClientSession::sendSessionStart() {
 }
 
 void ClientSession::handleSessionFinished(const boost::optional<SessionError>& error) {
+	if (whitespacePingLayer_) {
+		whitespacePingLayer_->setInactive();
+	}
+	
 	if (error) {
 		//assert(!error_);
 		state_ = Error;
diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp
index bb10cfd..cbf20d2 100644
--- a/Swiften/Client/UnitTest/ClientSessionTest.cpp
+++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp
@@ -39,6 +39,7 @@ using namespace Swift;
 class ClientSessionTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST_SUITE(ClientSessionTest);
 		CPPUNIT_TEST(testConstructor);
+		CPPUNIT_TEST(testDisconnect);
 		/*
 		CPPUNIT_TEST(testStart_Error);
 		CPPUNIT_TEST(testStart_XMLError);
@@ -84,6 +85,21 @@ class ClientSessionTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT_EQUAL(ClientSession::Initial, session->getState());
 		}
 
+		void testDisconnect() {
+			boost::shared_ptr<MockSession> session(createSession("me@foo.com/Bar"));
+
+			/*
+			session->startSession();
+			processEvents();
+			session->finishSession();
+			processEvents();
+
+			boost::shared_ptr<WhitespacePingLayer> whitespacePingLayer = session->getWhitespacePingLayer();
+			CPPUNIT_ASSERT(whitespacePingLayer);
+			*/
+			//CPPUNIT_ASSERT(!whitespacePingLayer->isActive());
+		}
+
 /*
 		void testStart_Error() {
 			boost::shared_ptr<MockSession> session(createSession("me@foo.com/Bar"));
@@ -650,6 +666,12 @@ class ClientSessionTest : public CppUnit::TestFixture {
 	*/
 
 	private:
+		void processEvents() {
+			eventLoop_->processEvents();
+		}
+
+
+	private:
 		struct MockConnection : public Connection, public XMPPParserClient {
 			MockConnection() :
 					resetParser_(false),
diff --git a/Swiften/Network/Timer.cpp b/Swiften/Network/Timer.cpp
index f3b296c..d6120e3 100644
--- a/Swiften/Network/Timer.cpp
+++ b/Swiften/Network/Timer.cpp
@@ -6,35 +6,32 @@
 
 namespace Swift {
 
-Timer::Timer(int milliseconds) :
-		timeout_(milliseconds), ioService_(0), thread_(0), timer_(0) {
-	ioService_ = new boost::asio::io_service();
+Timer::Timer(int milliseconds, boost::asio::io_service* service) :
+		timeout(milliseconds), timer(*service) {
 }
 
 Timer::~Timer() {
-	//MainEventLoop::removeEventsFromOwner(shared_from_this());
-	ioService_->stop();
-	thread_->join();
-	delete timer_;
-	delete thread_;
-	delete ioService_;
+	stop();
 }
 
 void Timer::start() {
-	thread_ = new boost::thread(boost::bind(&Timer::doStart, shared_from_this()));
+	timer.expires_from_now(boost::posix_time::milliseconds(timeout));
+	timer.async_wait(boost::bind(&Timer::handleTimerTick, shared_from_this(), boost::asio::placeholders::error));
 }
 
-void Timer::doStart() {
-	timer_ = new boost::asio::deadline_timer(*ioService_);
-	timer_->expires_from_now(boost::posix_time::milliseconds(timeout_));
-	timer_->async_wait(boost::bind(&Timer::handleTimerTick, shared_from_this()));
-	ioService_->run();
+void Timer::stop() {
+	timer.cancel();
 }
 
-void Timer::handleTimerTick() {
-	MainEventLoop::postEvent(boost::bind(boost::ref(onTick)), shared_from_this());
-	timer_->expires_from_now(boost::posix_time::milliseconds(timeout_));
-	timer_->async_wait(boost::bind(&Timer::handleTimerTick, shared_from_this()));
+void Timer::handleTimerTick(const boost::system::error_code& error) {
+	if (error) {
+		assert(error == boost::asio::error::operation_aborted);
+	}
+	else {
+		MainEventLoop::postEvent(boost::bind(boost::ref(onTick)), shared_from_this());
+		timer.expires_from_now(boost::posix_time::milliseconds(timeout));
+		timer.async_wait(boost::bind(&Timer::handleTimerTick, shared_from_this(), boost::asio::placeholders::error));
+	}
 }
 
 }
diff --git a/Swiften/Network/Timer.h b/Swiften/Network/Timer.h
index de97c13..6474fe9 100644
--- a/Swiften/Network/Timer.h
+++ b/Swiften/Network/Timer.h
@@ -10,22 +10,20 @@
 namespace Swift {
 	class Timer : public EventOwner, public boost::enable_shared_from_this<Timer> {
 		public:
-			Timer(int milliseconds);
+			Timer(int milliseconds, boost::asio::io_service* service);
 			~Timer();
 
 			void start();
+			void stop();
 
 		public:
 			boost::signal<void ()> onTick;
 
 		private:
-			void doStart();
-			void handleTimerTick();
+			void handleTimerTick(const boost::system::error_code& error);
 
 		private:
-			int timeout_;
-			boost::asio::io_service* ioService_;
-			boost::thread* thread_;
-			boost::asio::deadline_timer* timer_;
+			int timeout;
+			boost::asio::deadline_timer timer;
 	};
 }
diff --git a/Swiften/StreamStack/WhitespacePingLayer.cpp b/Swiften/StreamStack/WhitespacePingLayer.cpp
index b10ba1a..25e4436 100644
--- a/Swiften/StreamStack/WhitespacePingLayer.cpp
+++ b/Swiften/StreamStack/WhitespacePingLayer.cpp
@@ -1,4 +1,7 @@
 #include "Swiften/StreamStack/WhitespacePingLayer.h"
+
+#include "Swiften/Network/BoostIOServiceThread.h"
+#include "Swiften/Network/MainBoostIOServiceThread.h"
 #include "Swiften/Network/Timer.h"
 
 namespace Swift {
@@ -6,9 +9,9 @@ namespace Swift {
 static const int TIMEOUT_MILLISECONDS = 60000;
 
 WhitespacePingLayer::WhitespacePingLayer() {
-	timer = boost::shared_ptr<Timer>(new Timer(TIMEOUT_MILLISECONDS));
+	// FIXME: Create a BoostTimerFactory.
+	timer = boost::shared_ptr<Timer>(new Timer(TIMEOUT_MILLISECONDS, &MainBoostIOServiceThread::getInstance().getIOService()));
 	timer->onTick.connect(boost::bind(&WhitespacePingLayer::handleTimerTick, this));
-	timer->start();
 }
 
 void WhitespacePingLayer::writeData(const ByteArray& data) {
@@ -23,4 +26,12 @@ void WhitespacePingLayer::handleTimerTick() {
 	onWriteData(" ");
 }
 
+void WhitespacePingLayer::setActive() {
+	timer->start();
+}
+
+void WhitespacePingLayer::setInactive() {
+	timer->stop();
+}
+
 }
diff --git a/Swiften/StreamStack/WhitespacePingLayer.h b/Swiften/StreamStack/WhitespacePingLayer.h
index ed0648b..de6013b 100644
--- a/Swiften/StreamStack/WhitespacePingLayer.h
+++ b/Swiften/StreamStack/WhitespacePingLayer.h
@@ -12,6 +12,8 @@ namespace Swift {
 		public:
 			WhitespacePingLayer();
 
+			void setActive();
+			void setInactive();
 			void writeData(const ByteArray& data);
 			void handleDataRead(const ByteArray& data);
 
-- 
cgit v0.10.2-6-g49f6