From df029015f47f284ced01b8d1f11c4d48cc2f2564 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 22 Jan 2011 15:00:01 +0100
Subject: Close connection properly before quitting.


diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp
index 9400b56..9950a76 100644
--- a/Swiften/Client/ClientSession.cpp
+++ b/Swiften/Client/ClientSession.cpp
@@ -62,7 +62,7 @@ ClientSession::~ClientSession() {
 void ClientSession::start() {
 	stream->onStreamStartReceived.connect(boost::bind(&ClientSession::handleStreamStart, shared_from_this(), _1));
 	stream->onElementReceived.connect(boost::bind(&ClientSession::handleElement, shared_from_this(), _1));
-	stream->onClosed.connect(boost::bind(&ClientSession::handleStreamFinished, shared_from_this(), _1));
+	stream->onClosed.connect(boost::bind(&ClientSession::handleStreamClosed, shared_from_this(), _1));
 	stream->onTLSEncrypted.connect(boost::bind(&ClientSession::handleTLSEncrypted, shared_from_this()));
 
 	assert(state == Initial);
@@ -367,20 +367,10 @@ void ClientSession::continueAfterTLSEncrypted() {
 	sendStreamHeader();
 }
 
-void ClientSession::handleStreamFinished(boost::shared_ptr<Swift::Error> error) {
-	finishSession(error);
-}
-
-void ClientSession::finish() {
-	finishSession(boost::shared_ptr<Error>());
-}
-
-void ClientSession::finishSession(Error::Type error) {
-	finishSession(boost::shared_ptr<Swift::ClientSession::Error>(new Swift::ClientSession::Error(error)));
-}
-
-void ClientSession::finishSession(boost::shared_ptr<Swift::Error> error) {
+void ClientSession::handleStreamClosed(boost::shared_ptr<Swift::Error> streamError) {
+	State previousState = state;
 	state = Finished;
+
 	if (stanzaAckRequester_) {
 		stanzaAckRequester_->onRequestAck.disconnect(boost::bind(&ClientSession::requestAck, shared_from_this()));
 		stanzaAckRequester_->onStanzaAcked.disconnect(boost::bind(&ClientSession::handleStanzaAcked, shared_from_this(), _1));
@@ -393,14 +383,32 @@ void ClientSession::finishSession(boost::shared_ptr<Swift::Error> error) {
 	stream->setWhitespacePingEnabled(false);
 	stream->onStreamStartReceived.disconnect(boost::bind(&ClientSession::handleStreamStart, shared_from_this(), _1));
 	stream->onElementReceived.disconnect(boost::bind(&ClientSession::handleElement, shared_from_this(), _1));
-	stream->onClosed.disconnect(boost::bind(&ClientSession::handleStreamFinished, shared_from_this(), _1));
+	stream->onClosed.disconnect(boost::bind(&ClientSession::handleStreamClosed, shared_from_this(), _1));
 	stream->onTLSEncrypted.disconnect(boost::bind(&ClientSession::handleTLSEncrypted, shared_from_this()));
-	if (stream->isAvailable()) {
-		stream->writeFooter();
+
+	if (previousState == Finishing) {
+		onFinished(error_);
 	}
-	onFinished(error);
+	else {
+		onFinished(streamError);
+	}
+}
+
+void ClientSession::finish() {
+	finishSession(boost::shared_ptr<Error>());
 }
 
+void ClientSession::finishSession(Error::Type error) {
+	finishSession(boost::shared_ptr<Swift::ClientSession::Error>(new Swift::ClientSession::Error(error)));
+}
+
+void ClientSession::finishSession(boost::shared_ptr<Swift::Error> error) {
+	state = Finishing;
+	error_ = error;
+	assert(stream->isOpen());
+	stream->writeFooter();
+	stream->close();
+}
 
 void ClientSession::requestAck() {
 	stream->writeElement(boost::shared_ptr<StanzaAckRequest>(new StanzaAckRequest()));
diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h
index f35c298..be0f89e 100644
--- a/Swiften/Client/ClientSession.h
+++ b/Swiften/Client/ClientSession.h
@@ -37,6 +37,7 @@ namespace Swift {
 				BindingResource,
 				StartingSession,
 				Initialized,
+				Finishing,
 				Finished
 			};
 
@@ -115,7 +116,7 @@ namespace Swift {
 
 			void handleElement(boost::shared_ptr<Element>);
 			void handleStreamStart(const ProtocolHeader&);
-			void handleStreamFinished(boost::shared_ptr<Swift::Error>);
+			void handleStreamClosed(boost::shared_ptr<Swift::Error>);
 
 			void handleTLSEncrypted();
 
@@ -139,6 +140,7 @@ namespace Swift {
 			ClientAuthenticator* authenticator;
 			boost::shared_ptr<StanzaAckRequester> stanzaAckRequester_;
 			boost::shared_ptr<StanzaAckResponder> stanzaAckResponder_;
+			boost::shared_ptr<Swift::Error> error_;
 			CertificateTrustChecker* certificateTrustChecker;
 	};
 }
diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp
index 2b0241a..5d0e2aa 100644
--- a/Swiften/Client/UnitTest/ClientSessionTest.cpp
+++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp
@@ -296,7 +296,11 @@ class ClientSessionTest : public CppUnit::TestFixture {
 				MockSessionStream() : available(true), canTLSEncrypt(true), tlsEncrypted(false), compressed(false), whitespacePingEnabled(false), resetCount(0) {
 				}
 
-				virtual bool isAvailable() {
+				virtual void close() {
+					onClosed(boost::shared_ptr<Error>());
+				}
+
+				virtual bool isOpen() {
 					return available;
 				}
 
diff --git a/Swiften/Component/ComponentSession.cpp b/Swiften/Component/ComponentSession.cpp
index 967e68d..c45f663 100644
--- a/Swiften/Component/ComponentSession.cpp
+++ b/Swiften/Component/ComponentSession.cpp
@@ -24,7 +24,7 @@ ComponentSession::~ComponentSession() {
 void ComponentSession::start() {
 	stream->onStreamStartReceived.connect(boost::bind(&ComponentSession::handleStreamStart, shared_from_this(), _1));
 	stream->onElementReceived.connect(boost::bind(&ComponentSession::handleElement, shared_from_this(), _1));
-	stream->onClosed.connect(boost::bind(&ComponentSession::handleStreamError, shared_from_this(), _1));
+	stream->onClosed.connect(boost::bind(&ComponentSession::handleStreamClosed, shared_from_this(), _1));
 
 	assert(state == Initial);
 	state = WaitingForStreamStart;
@@ -81,8 +81,19 @@ bool ComponentSession::checkState(State state) {
 	return true;
 }
 
-void ComponentSession::handleStreamError(boost::shared_ptr<Swift::Error> error) {
-	finishSession(error);
+void ComponentSession::handleStreamClosed(boost::shared_ptr<Swift::Error> streamError) {
+	State oldState = state;
+	state = Finished;
+	stream->setWhitespacePingEnabled(false);
+	stream->onStreamStartReceived.disconnect(boost::bind(&ComponentSession::handleStreamStart, shared_from_this(), _1));
+	stream->onElementReceived.disconnect(boost::bind(&ComponentSession::handleElement, shared_from_this(), _1));
+	stream->onClosed.disconnect(boost::bind(&ComponentSession::handleStreamClosed, shared_from_this(), _1));
+	if (oldState == Finishing) {
+		onFinished(error);
+	}
+	else {
+		onFinished(streamError);
+	}
 }
 
 void ComponentSession::finish() {
@@ -93,16 +104,12 @@ void ComponentSession::finishSession(Error::Type error) {
 	finishSession(boost::shared_ptr<Swift::ComponentSession::Error>(new Swift::ComponentSession::Error(error)));
 }
 
-void ComponentSession::finishSession(boost::shared_ptr<Swift::Error> error) {
-	state = Finished;
-	stream->setWhitespacePingEnabled(false);
-	stream->onStreamStartReceived.disconnect(boost::bind(&ComponentSession::handleStreamStart, shared_from_this(), _1));
-	stream->onElementReceived.disconnect(boost::bind(&ComponentSession::handleElement, shared_from_this(), _1));
-	stream->onClosed.disconnect(boost::bind(&ComponentSession::handleStreamError, shared_from_this(), _1));
-	if (stream->isAvailable()) {
-		stream->writeFooter();
-	}
-	onFinished(error);
+void ComponentSession::finishSession(boost::shared_ptr<Swift::Error> finishError) {
+	state = Finishing;
+	error = finishError;
+	assert(stream->isOpen());
+	stream->writeFooter();
+	stream->close();
 }
 
 }
diff --git a/Swiften/Component/ComponentSession.h b/Swiften/Component/ComponentSession.h
index cbfa227..dbe6e27 100644
--- a/Swiften/Component/ComponentSession.h
+++ b/Swiften/Component/ComponentSession.h
@@ -27,6 +27,7 @@ namespace Swift {
 				WaitingForStreamStart,
 				Authenticating,
 				Initialized,
+				Finishing,
 				Finished
 			};
 
@@ -68,7 +69,7 @@ namespace Swift {
 
 			void handleElement(boost::shared_ptr<Element>);
 			void handleStreamStart(const ProtocolHeader&);
-			void handleStreamError(boost::shared_ptr<Swift::Error>);
+			void handleStreamClosed(boost::shared_ptr<Swift::Error>);
 
 			bool checkState(State);
 
@@ -76,6 +77,7 @@ namespace Swift {
 			JID jid;
 			String secret;
 			boost::shared_ptr<SessionStream> stream;
+			boost::shared_ptr<Swift::Error> error;
 			State state;
 	};
 }
diff --git a/Swiften/Component/UnitTest/ComponentSessionTest.cpp b/Swiften/Component/UnitTest/ComponentSessionTest.cpp
index 3ad52f9..86776e8 100644
--- a/Swiften/Component/UnitTest/ComponentSessionTest.cpp
+++ b/Swiften/Component/UnitTest/ComponentSessionTest.cpp
@@ -95,7 +95,11 @@ class ComponentSessionTest : public CppUnit::TestFixture {
 				MockSessionStream() : available(true), whitespacePingEnabled(false), resetCount(0) {
 				}
 
-				virtual bool isAvailable() {
+				virtual void close() {
+					onClosed(boost::shared_ptr<Error>());
+				}
+
+				virtual bool isOpen() {
 					return available;
 				}
 
diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp
index 5377e6c..03985bd 100644
--- a/Swiften/Session/BasicSessionStream.cpp
+++ b/Swiften/Session/BasicSessionStream.cpp
@@ -88,7 +88,11 @@ void BasicSessionStream::writeFooter() {
 	xmppLayer->writeFooter();
 }
 
-bool BasicSessionStream::isAvailable() {
+void BasicSessionStream::close() {
+	connection->disconnect();
+}
+
+bool BasicSessionStream::isOpen() {
 	return available;
 }
 
diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h
index 330db9d..747177a 100644
--- a/Swiften/Session/BasicSessionStream.h
+++ b/Swiften/Session/BasicSessionStream.h
@@ -36,7 +36,8 @@ namespace Swift {
 			);
 			~BasicSessionStream();
 
-			virtual bool isAvailable();
+			virtual void close();
+			virtual bool isOpen();
 
 			virtual void writeHeader(const ProtocolHeader& header);
 			virtual void writeElement(boost::shared_ptr<Element>);
diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h
index 55082f4..d0f93ee 100644
--- a/Swiften/Session/SessionStream.h
+++ b/Swiften/Session/SessionStream.h
@@ -37,7 +37,8 @@ namespace Swift {
 
 			virtual ~SessionStream();
 
-			virtual bool isAvailable() = 0;
+			virtual void close() = 0;
+			virtual bool isOpen() = 0;
 
 			virtual void writeHeader(const ProtocolHeader& header) = 0;
 			virtual void writeFooter() = 0;
-- 
cgit v0.10.2-6-g49f6