From f176050a50fb846bbad3fb49d6b2f7a2c81e3589 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Sun, 11 Jan 2015 16:40:09 +0100
Subject: Wait for responder to terminate the the file transfer session after
 data verification.

Test-Information:

Tested with FileTransferTest (coming with future commit) and inspected
the logs.

Change-Id: Idd2739e15ab944e8486065cb2a3bc559ce9053d1

diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp
index ab4cb5c..ab08c45 100644
--- a/Swiften/FileTransfer/FileTransferManagerImpl.cpp
+++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp
@@ -76,6 +76,7 @@ FileTransferManagerImpl::FileTransferManagerImpl(
 			jingleSessionManager, 
 			iqRouter, 
 			transporterFactory,
+			timerFactory,
 			crypto);
 	incomingFTManager = new IncomingFileTransferManager(
 			jingleSessionManager, 
diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp
index 5d0555f..0ed2395 100644
--- a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp
+++ b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp
@@ -5,7 +5,7 @@
  */
 
 /*
- * Copyright (c) 2013-2014 Isode Limited.
+ * Copyright (c) 2013-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -25,12 +25,14 @@ namespace Swift {
 
 OutgoingFileTransferManager::OutgoingFileTransferManager(
 		JingleSessionManager* jingleSessionManager, 
-		IQRouter* router, 
+		IQRouter* router,
 		FileTransferTransporterFactory* transporterFactory,
+		TimerFactory* timerFactory,
 		CryptoProvider* crypto) : 
 			jingleSessionManager(jingleSessionManager), 
 			iqRouter(router), 
 			transporterFactory(transporterFactory),
+			timerFactory(timerFactory),
 			crypto(crypto) {
 	idGenerator = new IDGenerator();
 }
@@ -53,6 +55,7 @@ boost::shared_ptr<OutgoingFileTransfer> OutgoingFileTransferManager::createOutgo
 				jingleSession, 
 				readBytestream, 
 				transporterFactory,
+				timerFactory,
 				idGenerator, 
 				fileInfo, 
 				config,
diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.h b/Swiften/FileTransfer/OutgoingFileTransferManager.h
index fd7380b..f97bc9b 100644
--- a/Swiften/FileTransfer/OutgoingFileTransferManager.h
+++ b/Swiften/FileTransfer/OutgoingFileTransferManager.h
@@ -5,7 +5,7 @@
  */
 
 /*
- * Copyright (c) 2013-2014 Isode Limited.
+ * Copyright (c) 2013-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -25,6 +25,7 @@ namespace Swift {
 	class JingleFileTransferFileInfo;
 	class CryptoProvider;
 	class FileTransferOptions;
+	class TimerFactory;
 
 	class OutgoingFileTransferManager {
 		public:
@@ -32,6 +33,7 @@ namespace Swift {
 					JingleSessionManager* jingleSessionManager, 
 					IQRouter* router, 
 					FileTransferTransporterFactory* transporterFactory,
+					TimerFactory* timerFactory,
 					CryptoProvider* crypto);
 			~OutgoingFileTransferManager();
 			
@@ -46,6 +48,7 @@ namespace Swift {
 			JingleSessionManager* jingleSessionManager;
 			IQRouter* iqRouter;
 			FileTransferTransporterFactory* transporterFactory;
+			TimerFactory* timerFactory;
 			IDGenerator* idGenerator;
 			CryptoProvider* crypto;
 	};
diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
index 4183af7..07e927e 100644
--- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
@@ -36,6 +36,7 @@
 #include <Swiften/FileTransfer/ReadBytestream.h>
 #include <Swiften/FileTransfer/TransportSession.h>
 #include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/Network/TimerFactory.h>
 
 #include <Swiften/Base/Log.h>
 
@@ -48,6 +49,7 @@ OutgoingJingleFileTransfer::OutgoingJingleFileTransfer(
 		JingleSession::ref session,
 		boost::shared_ptr<ReadBytestream> stream,
 		FileTransferTransporterFactory* transporterFactory,
+		TimerFactory* timerFactory,
 		IDGenerator* idGenerator,
 		const JingleFileTransferFileInfo& fileInfo,
 		const FileTransferOptions& options,
@@ -67,6 +69,9 @@ OutgoingJingleFileTransfer::OutgoingJingleFileTransfer(
 	hashCalculator = new IncrementalBytestreamHashCalculator(true, true, crypto);
 	stream->onRead.connect(
 			boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1));
+
+	waitForRemoteTermination = timerFactory->createTimer(5000);
+	waitForRemoteTermination->onTick.connect(boost::bind(&OutgoingJingleFileTransfer::handleWaitForRemoteTerminationTimeout, this));
 }
 
 OutgoingJingleFileTransfer::~OutgoingJingleFileTransfer() {
@@ -199,7 +204,10 @@ void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTran
 	} 
 	else {
 		sendSessionInfoHash();
-		terminate(JinglePayload::Reason::Success);
+
+		// wait for other party to terminate session after they have verified the hash
+		setState(WaitForTermination);
+		waitForRemoteTermination->start();
 	}
 }
 
@@ -241,6 +249,7 @@ FileTransfer::State::Type OutgoingJingleFileTransfer::getExternalState(State sta
 		case WaitingForCandidateAcknowledge: return FileTransfer::State::Negotiating;
 		case FallbackRequested: return FileTransfer::State::Negotiating;
 		case Transferring: return FileTransfer::State::Transferring;
+		case WaitForTermination: return FileTransfer::State::Transferring;
 		case Finished: return FileTransfer::State::Finished;
 	}
 	assert(false);
@@ -265,6 +274,8 @@ void OutgoingJingleFileTransfer::stopAll() {
 			transportSession->stop();
 			transportSession.reset();
 			break;
+		case WaitForTermination:
+			break;
 		case Finished: SWIFT_LOG(warning) << "Already finished" << std::endl; break;
 	}
 	if (state != Initial) {
@@ -343,3 +354,10 @@ boost::shared_ptr<TransportSession> OutgoingJingleFileTransfer::createRemoteCand
 	return transporter->createRemoteCandidateSession(stream);
 }
 
+void OutgoingJingleFileTransfer::handleWaitForRemoteTerminationTimeout() {
+	assert(state == WaitForTermination);
+	SWIFT_LOG(warning) << "Other party did not terminate session. Terminate it now." << std::endl;
+	waitForRemoteTermination->stop();
+	terminate(JinglePayload::Reason::MediaError);
+}
+
diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h
index f022b9f..52960d5 100644
--- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h
+++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h
@@ -5,7 +5,7 @@
  */
 
 /*
- * Copyright (c) 2013-2014 Isode Limited.
+ * Copyright (c) 2013-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -22,6 +22,7 @@
 #include <Swiften/FileTransfer/OutgoingFileTransfer.h>
 #include <Swiften/FileTransfer/JingleFileTransfer.h>
 #include <Swiften/FileTransfer/FileTransferOptions.h>
+#include <Swiften/Network/Timer.h>
 
 namespace Swift {
 	class ReadBytestream;
@@ -31,6 +32,7 @@ namespace Swift {
 	class FileTransferTransporter;
 	class FileTransferTransporterFactory;
 	class TransportSession;
+	class TimerFactory;
 
 	class SWIFTEN_API OutgoingJingleFileTransfer : public OutgoingFileTransfer, public JingleFileTransfer {
 		public:
@@ -39,6 +41,7 @@ namespace Swift {
 				boost::shared_ptr<JingleSession>,
 				boost::shared_ptr<ReadBytestream>,
 				FileTransferTransporterFactory*,
+				TimerFactory*,
 				IDGenerator*,
 				const JingleFileTransferFileInfo&,
 				const FileTransferOptions&,
@@ -59,6 +62,7 @@ namespace Swift {
 				WaitingForCandidateAcknowledge,
 				FallbackRequested,
 				Transferring,
+				WaitForTermination,
 				Finished
 			};
 
@@ -90,6 +94,8 @@ namespace Swift {
 			virtual boost::shared_ptr<TransportSession> createLocalCandidateSession() SWIFTEN_OVERRIDE;
 			virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession() SWIFTEN_OVERRIDE;
 
+			void handleWaitForRemoteTerminationTimeout();
+
 			void stopAll();
 			void setState(State state);
 			void setFinishedState(FileTransfer::State::Type, const boost::optional<FileTransferError>& error);
@@ -106,6 +112,8 @@ namespace Swift {
 			State state;
 			bool candidateAcknowledged;
 
+			Timer::ref waitForRemoteTermination;
+
 			boost::bsignals::connection processedBytesConnection;
 			boost::bsignals::connection transferFinishedConnection;
 	};
-- 
cgit v0.10.2-6-g49f6