From cb1cc3c0205295002f2cd760cbd801842b30096e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Thu, 31 Dec 2009 16:00:15 +0100
Subject: Put a timeout of 60s on connecting & resolving.

Resolves: #87.

diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp
index 27f3d9c..c704248 100644
--- a/Swiften/Client/Client.cpp
+++ b/Swiften/Client/Client.cpp
@@ -36,8 +36,9 @@ bool Client::isAvailable() {
 
 void Client::connect() {
 	assert(!connector_);
-	connector_ = boost::shared_ptr<Connector>(new Connector(jid_.getDomain(), &resolver_, connectionFactory_));
+	connector_ = boost::shared_ptr<Connector>(new Connector(jid_.getDomain(), &resolver_, connectionFactory_, timerFactory_));
 	connector_->onConnectFinished.connect(boost::bind(&Client::handleConnectorFinished, this, _1));
+	connector_->setTimeoutMilliseconds(60*1000);
 	connector_->start();
 }
 
diff --git a/Swiften/Elements/MUCPayload.h b/Swiften/Elements/MUCPayload.h
index 205ae46..97932a1 100644
--- a/Swiften/Elements/MUCPayload.h
+++ b/Swiften/Elements/MUCPayload.h
@@ -1,16 +1,11 @@
-#ifndef SWIFTEN_MUCPayload_H
-#define SWIFTEN_MUCPayload_H
+#pragma once
 
-#include "Swiften/Base/String.h"
 #include "Swiften/Elements/Payload.h"
 
 namespace Swift {
-	class MUCPayload : public Payload
-	{
+	class MUCPayload : public Payload {
 		public:
-			MUCPayload() { }
-
+			MUCPayload() {
+			}
 	};
 }
-
-#endif
diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp
index 9ea5a7f..d372bf2 100644
--- a/Swiften/Network/Connector.cpp
+++ b/Swiften/Network/Connector.cpp
@@ -6,10 +6,11 @@
 #include "Swiften/Network/ConnectionFactory.h"
 #include "Swiften/Network/DomainNameResolver.h"
 #include "Swiften/Network/DomainNameAddressQuery.h"
+#include "Swiften/Network/TimerFactory.h"
 
 namespace Swift {
 
-Connector::Connector(const String& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), queriedAllHosts(true) {
+Connector::Connector(const String& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0), queriedAllHosts(true) {
 }
 
 void Connector::setTimeoutMilliseconds(int milliseconds) {
@@ -20,9 +21,15 @@ void Connector::start() {
 	//std::cout << "Connector::start()" << std::endl;
 	assert(!currentConnection);
 	assert(!serviceQuery);
+	assert(!timer);
 	queriedAllHosts = false;
 	serviceQuery = resolver->createServiceQuery("_xmpp-client._tcp." + hostname);
 	serviceQuery->onResult.connect(boost::bind(&Connector::handleServiceQueryResult, this, _1));
+	if (timeoutMilliseconds > 0) {
+		timer = timerFactory->createTimer(timeoutMilliseconds);
+		timer->onTick.connect(boost::bind(&Connector::handleTimeout, this));
+		timer->start();
+	}
 	serviceQuery->run();
 }
 
@@ -43,7 +50,7 @@ void Connector::handleServiceQueryResult(const std::vector<DomainNameServiceQuer
 void Connector::tryNextHostname() {
 	if (queriedAllHosts) {
 		//std::cout << "Connector::tryNextHostName(): Queried all hosts. Error." << std::endl;
-		onConnectFinished(boost::shared_ptr<Connection>());
+		finish(boost::shared_ptr<Connection>());
 	}
 	else if (serviceQueryResults.empty()) {
 		//std::cout << "Connector::tryNextHostName(): Falling back on A resolution" << std::endl;
@@ -76,7 +83,7 @@ void Connector::handleAddressQueryResult(const HostAddress& address, boost::opti
 		//std::cout << "Connector::handleAddressQueryResult(): Fallback address query failed. Giving up" << std::endl;
 		// The fallback address query failed
 		assert(queriedAllHosts);
-		onConnectFinished(boost::shared_ptr<Connection>());
+		finish(boost::shared_ptr<Connection>());
 	}
 	else {
 		//std::cout << "Connector::handleAddressQueryResult(): Fallback address query succeeded: " << address.toString() << std::endl;
@@ -100,8 +107,20 @@ void Connector::handleConnectionConnectFinished(bool error) {
 		tryNextHostname();
 	}
 	else {
-		onConnectFinished(currentConnection);
+		finish(currentConnection);
+	}
+}
+
+void Connector::finish(boost::shared_ptr<Connection> connection) {
+	if (timer) {
+		timer->stop();
+		timer.reset();
 	}
+	onConnectFinished(connection);
+}
+
+void Connector::handleTimeout() {
+	finish(boost::shared_ptr<Connection>());
 }
 
 };
diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h
index 6df3970..507f085 100644
--- a/Swiften/Network/Connector.h
+++ b/Swiften/Network/Connector.h
@@ -6,6 +6,7 @@
 
 #include "Swiften/Network/DomainNameServiceQuery.h"
 #include "Swiften/Network/Connection.h"
+#include "Swiften/Network/Timer.h"
 #include "Swiften/Network/HostAddressPort.h"
 #include "Swiften/Base/String.h"
 #include "Swiften/Network/DomainNameResolveError.h"
@@ -14,10 +15,11 @@ namespace Swift {
 	class DomainNameAddressQuery;
 	class DomainNameResolver;
 	class ConnectionFactory;
+	class TimerFactory;
 
 	class Connector : public boost::bsignals::trackable {
 		public:
-			Connector(const String& hostname, DomainNameResolver*, ConnectionFactory*);
+			Connector(const String& hostname, DomainNameResolver*, ConnectionFactory*, TimerFactory*);
 
 			void setTimeoutMilliseconds(int milliseconds);
 			void start();
@@ -33,12 +35,16 @@ namespace Swift {
 			void tryConnect(const HostAddressPort& target);
 
 			void handleConnectionConnectFinished(bool error);
+			void finish(boost::shared_ptr<Connection>);
+			void handleTimeout();
 
 		private:
 			String hostname;
 			DomainNameResolver* resolver;
 			ConnectionFactory* connectionFactory;
+			TimerFactory* timerFactory;
 			int timeoutMilliseconds;
+			boost::shared_ptr<Timer> timer;
 			boost::shared_ptr<DomainNameServiceQuery> serviceQuery;
 			std::deque<DomainNameServiceQuery::Result> serviceQueryResults;
 			boost::shared_ptr<DomainNameAddressQuery> addressQuery;
diff --git a/Swiften/Network/DummyTimerFactory.cpp b/Swiften/Network/DummyTimerFactory.cpp
index 72523bb..7626584 100644
--- a/Swiften/Network/DummyTimerFactory.cpp
+++ b/Swiften/Network/DummyTimerFactory.cpp
@@ -2,8 +2,8 @@
 
 #include <algorithm>
 
-#include "Swiften/Network/Timer.h"
 #include "Swiften/Base/foreach.h"
+#include "Swiften/Network/Timer.h"
 
 namespace Swift {
 
@@ -40,7 +40,7 @@ static bool hasZeroTimeout(boost::shared_ptr<DummyTimerFactory::DummyTimer> time
 
 void DummyTimerFactory::setTime(int time) {
 	assert(time > currentTime);
-	int increment = currentTime - time;
+	int increment = time - currentTime;
 	std::vector< boost::shared_ptr<DummyTimer> > notifyTimers(timers.begin(), timers.end());
 	foreach(boost::shared_ptr<DummyTimer> timer, notifyTimers) {
 		if (increment >= timer->timeout) {
@@ -49,6 +49,9 @@ void DummyTimerFactory::setTime(int time) {
 			}
 			timer->timeout = 0;
 		}
+		else {
+			timer->timeout -= increment;
+		}
 	}
 	timers.erase(std::remove_if(timers.begin(), timers.end(), hasZeroTimeout), timers.end());
 	currentTime = time;
diff --git a/Swiften/Network/UnitTest/ConnectorTest.cpp b/Swiften/Network/UnitTest/ConnectorTest.cpp
index 08b9bc1..663011c 100644
--- a/Swiften/Network/UnitTest/ConnectorTest.cpp
+++ b/Swiften/Network/UnitTest/ConnectorTest.cpp
@@ -24,9 +24,9 @@ class ConnectorTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST(testConnect_AllSRVHostsFailWithoutFallbackHost);
 		CPPUNIT_TEST(testConnect_AllSRVHostsFailWithFallbackHost);
 		CPPUNIT_TEST(testConnect_SRVAndFallbackHostsFail);
-		//CPPUNIT_TEST(testConnect_TimeoutDuringResolve);
-		//CPPUNIT_TEST(testConnect_TimeoutDuringConnect);
-		//CPPUNIT_TEST(testConnect_NoTimeout);
+		CPPUNIT_TEST(testConnect_TimeoutDuringResolve);
+		CPPUNIT_TEST(testConnect_TimeoutDuringConnect);
+		CPPUNIT_TEST(testConnect_NoTimeout);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
@@ -186,7 +186,7 @@ class ConnectorTest : public CppUnit::TestFixture {
 
 	private:
 		Connector* createConnector() {
-			Connector* connector = new Connector("foo.com", resolver, connectionFactory);
+			Connector* connector = new Connector("foo.com", resolver, connectionFactory, timerFactory);
 			connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1));
 			return connector;
 		}
-- 
cgit v0.10.2-6-g49f6