From a049c80f0862a994a76e8e63d71c633bce63f66a Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Sun, 11 Jan 2015 18:13:41 +0100
Subject: Renable SOCKS5 bytestream proxy support for Jingle file transfers.

Test-Information:

Tested interoperability with Swiften using FileTransferTest.

Change-Id: Ic13a68a91cad199be0bfc8852ff43c25c7085f12

diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp
index 2c54d88..22b4a84 100644
--- a/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp
+++ b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp
@@ -11,19 +11,20 @@
 
 #include <Swiften/Base/Log.h>
 #include <Swiften/Base/foreach.h>
-#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h>
-#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h>
+#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/FileTransfer/FileTransferOptions.h>
+#include <Swiften/FileTransfer/IBBReceiveSession.h>
+#include <Swiften/FileTransfer/IBBSendSession.h>
 #include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h>
-#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h>
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h>
 #include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h>
-#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h>
+#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h>
 #include <Swiften/FileTransfer/SOCKS5BytestreamServer.h>
-#include <Swiften/FileTransfer/IBBSendSession.h>
-#include <Swiften/FileTransfer/IBBReceiveSession.h>
+#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h>
+#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h>
 #include <Swiften/FileTransfer/TransportSession.h>
-#include <Swiften/StringCodecs/Hexify.h>
-#include <Swiften/Crypto/CryptoProvider.h>
 #include <Swiften/Queries/GenericRequest.h>
+#include <Swiften/StringCodecs/Hexify.h>
 
 using namespace Swift;
 
@@ -72,6 +73,7 @@ namespace {
 	class FailingTransportSession : public TransportSession {
 		public:
 			virtual void start() SWIFTEN_OVERRIDE {
+				assert(false);
 				onFinished(FileTransferError(FileTransferError::PeerError));
 			}
 
@@ -145,6 +147,7 @@ DefaultFileTransferTransporter::DefaultFileTransferTransporter(
 			role(role),
 			s5bRegistry(s5bRegistry),
 			s5bServerManager(s5bServerManager),
+			s5bProxy(s5bProxy),
 			crypto(crypto),
 			router(router) {
 
@@ -166,6 +169,7 @@ DefaultFileTransferTransporter::DefaultFileTransferTransporter(
 }
 
 DefaultFileTransferTransporter::~DefaultFileTransferTransporter() {
+	stopGeneratingLocalCandidates();
 	delete remoteCandidateSelector;
 	delete localCandidateGenerator;
 }
@@ -189,7 +193,8 @@ void DefaultFileTransferTransporter::stopGeneratingLocalCandidates() {
 void DefaultFileTransferTransporter::handleLocalCandidatesGenerated(
 		const std::vector<JingleS5BTransportPayload::Candidate>& candidates) {
 	s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), true);
-	onLocalCandidatesGenerated(s5bSessionID, candidates);
+	s5bProxy->connectToProxies(getSOCKS5DstAddr());
+	onLocalCandidatesGenerated(s5bSessionID, candidates, getSOCKS5DstAddr());
 }
 
 void DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished(
@@ -201,8 +206,8 @@ void DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished(
 
 
 void DefaultFileTransferTransporter::addRemoteCandidates(
-		const std::vector<JingleS5BTransportPayload::Candidate>& candidates) {
-	remoteCandidateSelector->setSOCKS5DstAddr(getSOCKS5DstAddr());
+		const std::vector<JingleS5BTransportPayload::Candidate>& candidates, const std::string& dstAddr) {
+	remoteCandidateSelector->setSOCKS5DstAddr(dstAddr.empty() ? getRemoteCandidateSOCKS5DstAddr() : dstAddr);
 	remoteCandidateSelector->addCandidates(candidates);
 }
 
@@ -214,18 +219,20 @@ void DefaultFileTransferTransporter::stopTryingRemoteCandidates() {
 	remoteCandidateSelector->stopSelectingCandidate();
 }
 
-void DefaultFileTransferTransporter::startActivatingProxy(const JID&) {
-	// TODO
-	assert(false);
-	/*
+void DefaultFileTransferTransporter::handleActivateProxySessionResult(const std::string& sessionID, ErrorPayload::ref error) {
+	onProxyActivated(sessionID, error);
+}
+
+void DefaultFileTransferTransporter::startActivatingProxy(const JID& proxyServiceJID) {
+	// activate proxy
+	SWIFT_LOG(debug) << "Start activating proxy " << proxyServiceJID.toString() << " with sid = " << s5bSessionID << "." << std::endl;
 	S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>();
 	proxyRequest->setSID(s5bSessionID);
-	proxyRequest->setActivate(getTarget());
+	proxyRequest->setActivate(role == Initiator ? responder : initiator);
 
-	boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Set, proxy, proxyRequest, router);
-	request->onResponse.connect(boost::bind(&OutgoingJingleFileTransfer::handleActivateProxySessionResult, this, _1, _2));
+	boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Set, proxyServiceJID, proxyRequest, router);
+	request->onResponse.connect(boost::bind(&DefaultFileTransferTransporter::handleActivateProxySessionResult, this, s5bSessionID, _2));
 	request->send();
-	*/
 }
 
 void DefaultFileTransferTransporter::stopActivatingProxy() {
@@ -255,14 +262,14 @@ boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createIBBRec
 }
 
 boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createRemoteCandidateSession(
-		boost::shared_ptr<ReadBytestream> stream) {
+		boost::shared_ptr<ReadBytestream> stream, const JingleS5BTransportPayload::Candidate& candidate) {
 	closeLocalSession();
 	return boost::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >(
 		remoteS5BClientSession, stream);
 }
 
 boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createRemoteCandidateSession(
-		boost::shared_ptr<WriteBytestream> stream) {
+		boost::shared_ptr<WriteBytestream> stream, const JingleS5BTransportPayload::Candidate& candidate) {
 	closeLocalSession();
 	return boost::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >(
 		remoteS5BClientSession, stream);
@@ -280,34 +287,89 @@ boost::shared_ptr<SOCKS5BytestreamServerSession> DefaultFileTransferTransporter:
 	return !serverSessions.empty() ? serverSessions.front() : boost::shared_ptr<SOCKS5BytestreamServerSession>();
 }
 
-
 boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createLocalCandidateSession(
-		boost::shared_ptr<ReadBytestream> stream) {
+		boost::shared_ptr<ReadBytestream> stream, const JingleS5BTransportPayload::Candidate& candidate) {
 	closeRemoteSession();
-	boost::shared_ptr<SOCKS5BytestreamServerSession> serverSession = getServerSession();
-	if (serverSession) {
-		return boost::make_shared<S5BTransportSession<SOCKS5BytestreamServerSession> >(serverSession, stream);
+	boost::shared_ptr<TransportSession> transportSession;
+	if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) {
+		SOCKS5BytestreamClientSession::ref proxySession = s5bProxy->getProxySessionAndCloseOthers(candidate.jid, getLocalCandidateSOCKS5DstAddr());
+		assert(proxySession);
+		transportSession = boost::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >(proxySession, stream);
 	}
-	else {
-		return boost::make_shared<FailingTransportSession>();
+
+	if (!transportSession) {
+		boost::shared_ptr<SOCKS5BytestreamServerSession> serverSession = getServerSession();
+		if (serverSession) {
+			transportSession = boost::make_shared<S5BTransportSession<SOCKS5BytestreamServerSession> >(serverSession, stream);
+		}
 	}
+
+	if (!transportSession) {
+		transportSession = boost::make_shared<FailingTransportSession>();
+	}
+	return transportSession;
 }
 
 boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createLocalCandidateSession(
-		boost::shared_ptr<WriteBytestream> stream) {
+		boost::shared_ptr<WriteBytestream> stream, const JingleS5BTransportPayload::Candidate& candidate) {
 	closeRemoteSession();
-	boost::shared_ptr<SOCKS5BytestreamServerSession> serverSession = getServerSession();
-	if (serverSession) {
-		return boost::make_shared<S5BTransportSession<SOCKS5BytestreamServerSession> >(serverSession, stream);
+	boost::shared_ptr<TransportSession> transportSession;
+	if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) {
+		SOCKS5BytestreamClientSession::ref proxySession = s5bProxy->getProxySessionAndCloseOthers(candidate.jid, getLocalCandidateSOCKS5DstAddr());
+		assert(proxySession);
+		transportSession = boost::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >(proxySession, stream);
 	}
-	else {
-		return boost::make_shared<FailingTransportSession>();
+
+	if (!transportSession) {
+		boost::shared_ptr<SOCKS5BytestreamServerSession> serverSession = getServerSession();
+		if (serverSession) {
+			transportSession = boost::make_shared<S5BTransportSession<SOCKS5BytestreamServerSession> >(serverSession, stream);
+		}
+	}
+
+	if (!transportSession) {
+		transportSession = boost::make_shared<FailingTransportSession>();
 	}
+	return transportSession;
 }
 
 std::string DefaultFileTransferTransporter::getSOCKS5DstAddr() const {
-	return Hexify::hexify(crypto->getSHA1Hash(
-				createSafeByteArray(s5bSessionID + initiator.toString() + initiator.toString())));
+	std::string result;
+	if (role == Initiator) {
+		result = getInitiatorCandidateSOCKS5DstAddr();
+		SWIFT_LOG(debug) << "Initiator S5B DST.ADDR = " << s5bSessionID << " + " << initiator.toString() << " + " << responder.toString() << " : " << result << std::endl;
+	}
+	else {
+		result = getResponderCandidateSOCKS5DstAddr();
+		SWIFT_LOG(debug) << "Responder S5B DST.ADDR = " << s5bSessionID << " + " << responder.toString() << " + " << initiator.toString() << " : " << result << std::endl;
+	}
+	return result;
+}
+
+std::string DefaultFileTransferTransporter::getInitiatorCandidateSOCKS5DstAddr() const {
+	return Hexify::hexify(crypto->getSHA1Hash(createSafeByteArray(s5bSessionID + initiator.toString() + responder.toString())));
+}
+
+std::string DefaultFileTransferTransporter::getResponderCandidateSOCKS5DstAddr() const {
+	return Hexify::hexify(crypto->getSHA1Hash(createSafeByteArray(s5bSessionID + responder.toString() + initiator.toString())));
+}
+
+std::string DefaultFileTransferTransporter::getRemoteCandidateSOCKS5DstAddr() const {
+	if (role == Initiator) {
+		return getResponderCandidateSOCKS5DstAddr();
+	}
+	else {
+		return getInitiatorCandidateSOCKS5DstAddr();
+	}
+}
+
+std::string DefaultFileTransferTransporter::getLocalCandidateSOCKS5DstAddr() const {
+	if (role == Responder) {
+		return getResponderCandidateSOCKS5DstAddr();
+	}
+	else {
+		return getInitiatorCandidateSOCKS5DstAddr();
+	}
 }
 
 void DefaultFileTransferTransporter::closeLocalSession() {
diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporter.h b/Swiften/FileTransfer/DefaultFileTransferTransporter.h
index f5a4b9d..347c313 100644
--- a/Swiften/FileTransfer/DefaultFileTransferTransporter.h
+++ b/Swiften/FileTransfer/DefaultFileTransferTransporter.h
@@ -9,6 +9,7 @@
 #include <Swiften/Base/Override.h>
 #include <Swiften/Base/API.h>
 #include <Swiften/FileTransfer/FileTransferTransporter.h>
+#include <Swiften/Elements/ErrorPayload.h>
 
 namespace Swift {
 	class LocalJingleTransportCandidateGenerator;
@@ -57,7 +58,7 @@ namespace Swift {
 			virtual void stopGeneratingLocalCandidates() SWIFTEN_OVERRIDE;
 
 			virtual void addRemoteCandidates(
-					const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE;
+					const std::vector<JingleS5BTransportPayload::Candidate>&, const std::string&) SWIFTEN_OVERRIDE;
 			virtual void startTryingRemoteCandidates() SWIFTEN_OVERRIDE;
 			virtual void stopTryingRemoteCandidates() SWIFTEN_OVERRIDE;
 
@@ -69,30 +70,37 @@ namespace Swift {
 			virtual boost::shared_ptr<TransportSession> createIBBReceiveSession(
 					const std::string& sessionID, unsigned long long size, boost::shared_ptr<WriteBytestream>) SWIFTEN_OVERRIDE;
 			virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession(
-					boost::shared_ptr<ReadBytestream>) SWIFTEN_OVERRIDE;
+					boost::shared_ptr<ReadBytestream>, const JingleS5BTransportPayload::Candidate& candidate) SWIFTEN_OVERRIDE;
 			virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession(
-					boost::shared_ptr<WriteBytestream>) SWIFTEN_OVERRIDE;
+					boost::shared_ptr<WriteBytestream>, const JingleS5BTransportPayload::Candidate& candidate) SWIFTEN_OVERRIDE;
 			virtual boost::shared_ptr<TransportSession> createLocalCandidateSession(
-					boost::shared_ptr<ReadBytestream>) SWIFTEN_OVERRIDE;
+					boost::shared_ptr<ReadBytestream>, const JingleS5BTransportPayload::Candidate& candidate) SWIFTEN_OVERRIDE;
 			virtual boost::shared_ptr<TransportSession> createLocalCandidateSession(
-					boost::shared_ptr<WriteBytestream>) SWIFTEN_OVERRIDE;
+					boost::shared_ptr<WriteBytestream>, const JingleS5BTransportPayload::Candidate& candidate) SWIFTEN_OVERRIDE;
 
 		private:
 			void handleLocalCandidatesGenerated(const std::vector<JingleS5BTransportPayload::Candidate>&);
 			void handleRemoteCandidateSelectFinished(
 					const boost::optional<JingleS5BTransportPayload::Candidate>&, 
 					boost::shared_ptr<SOCKS5BytestreamClientSession>);
-			std::string getSOCKS5DstAddr() const;
+			void handleActivateProxySessionResult(const std::string& sessionID, ErrorPayload::ref error);
 			void closeLocalSession();
 			void closeRemoteSession();
 			boost::shared_ptr<SOCKS5BytestreamServerSession> getServerSession();
 
+			std::string getSOCKS5DstAddr() const;
+			std::string getInitiatorCandidateSOCKS5DstAddr() const;
+			std::string getResponderCandidateSOCKS5DstAddr() const;
+			std::string getRemoteCandidateSOCKS5DstAddr() const;
+			std::string getLocalCandidateSOCKS5DstAddr() const;
+
 		private:
 			JID initiator;
 			JID responder;
 			Role role;
 			SOCKS5BytestreamRegistry* s5bRegistry;
 			SOCKS5BytestreamServerManager* s5bServerManager;
+			SOCKS5BytestreamProxiesManager* s5bProxy;
 			CryptoProvider* crypto;
 			IQRouter* router;
 			LocalJingleTransportCandidateGenerator* localCandidateGenerator;
diff --git a/Swiften/FileTransfer/FileTransferTransporter.h b/Swiften/FileTransfer/FileTransferTransporter.h
index 2116f0d..45eb811 100644
--- a/Swiften/FileTransfer/FileTransferTransporter.h
+++ b/Swiften/FileTransfer/FileTransferTransporter.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014 Isode Limited.
+ * Copyright (c) 2013-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -33,7 +33,7 @@ namespace Swift {
 			virtual void stopGeneratingLocalCandidates() = 0;
 
 			virtual void addRemoteCandidates(
-					const std::vector<JingleS5BTransportPayload::Candidate>&) = 0;
+					const std::vector<JingleS5BTransportPayload::Candidate>&, const std::string&) = 0;
 			virtual void startTryingRemoteCandidates() = 0;
 			virtual void stopTryingRemoteCandidates() = 0;
 
@@ -45,15 +45,15 @@ namespace Swift {
 			virtual boost::shared_ptr<TransportSession> createIBBReceiveSession(
 					const std::string& sessionID, unsigned long long size, boost::shared_ptr<WriteBytestream>) = 0;
 			virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession(
-					boost::shared_ptr<ReadBytestream>) = 0;
+					boost::shared_ptr<ReadBytestream>, const JingleS5BTransportPayload::Candidate& candidate) = 0;
 			virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession(
-					boost::shared_ptr<WriteBytestream>) = 0;
+					boost::shared_ptr<WriteBytestream>, const JingleS5BTransportPayload::Candidate& candidate) = 0;
 			virtual boost::shared_ptr<TransportSession> createLocalCandidateSession(
-					boost::shared_ptr<ReadBytestream>) = 0;
+					boost::shared_ptr<ReadBytestream>, const JingleS5BTransportPayload::Candidate& candidate) = 0;
 			virtual boost::shared_ptr<TransportSession> createLocalCandidateSession(
-					boost::shared_ptr<WriteBytestream>) = 0;
+					boost::shared_ptr<WriteBytestream>, const JingleS5BTransportPayload::Candidate& candidate) = 0;
 
-			boost::signal<void (const std::string& /* sessionID */, const std::vector<JingleS5BTransportPayload::Candidate>&)> onLocalCandidatesGenerated;
+			boost::signal<void (const std::string& /* sessionID */, const std::vector<JingleS5BTransportPayload::Candidate>&, const std::string& /* dstAddr */)> onLocalCandidatesGenerated;
 			boost::signal<void (const std::string& /* sessionID */, const boost::optional<JingleS5BTransportPayload::Candidate>&)> onRemoteCandidateSelectFinished;
 			boost::signal<void (const std::string& /* sessionID */, boost::shared_ptr<ErrorPayload>)> onProxyActivated;
 	};
diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
index daecf92..a0cd47c 100644
--- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
@@ -80,7 +80,7 @@ void IncomingJingleFileTransfer::accept(
 		SWIFT_LOG(debug) << "Got S5B transport as initial payload." << std::endl;
 		setTransporter(transporterFactory->createResponderTransporter(
 				getInitiator(), getResponder(), s5bTransport->getSessionID(), options));
-		transporter->addRemoteCandidates(s5bTransport->getCandidates());
+		transporter->addRemoteCandidates(s5bTransport->getCandidates(), s5bTransport->getDstAddr());
 		setState(GeneratingInitialLocalCandidates);
 		transporter->startGeneratingLocalCandidates();
 	}
@@ -109,7 +109,8 @@ void IncomingJingleFileTransfer::cancel() {
 
 void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(
 		const std::string& s5bSessionID, 
-		const std::vector<JingleS5BTransportPayload::Candidate>& candidates) {
+		const std::vector<JingleS5BTransportPayload::Candidate>& candidates,
+		const std::string& dstAddr) {
 	SWIFT_LOG(debug) << std::endl;
 	if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; }
 
@@ -118,6 +119,7 @@ void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(
 	JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>();
 	transport->setSessionID(s5bSessionID);
 	transport->setMode(JingleS5BTransportPayload::TCPMode);
+	transport->setDstAddr(dstAddr);
 	foreach(JingleS5BTransportPayload::Candidate candidate, candidates) {
 		transport->addCandidate(candidate);	
 	}
@@ -219,7 +221,8 @@ void IncomingJingleFileTransfer::handleTransportReplaceReceived(
 		return; 
 	}
 
-	if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) {
+	JingleIBBTransportPayload::ref ibbTransport;
+	if (options.isInBandAllowed() && (ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport))) {
 		SWIFT_LOG(debug) << "transport replaced with IBB" << std::endl;
 
 		startTransferring(transporter->createIBBReceiveSession(
@@ -338,12 +341,7 @@ bool IncomingJingleFileTransfer::hasPriorityOnCandidateTie() const {
 }
 
 void IncomingJingleFileTransfer::fallback() {
-	if (options.isInBandAllowed()) {
-		setState(WaitingForFallbackOrTerminate);
-	}
-	else {
-		terminate(JinglePayload::Reason::ConnectivityError);
-	}
+	setState(WaitingForFallbackOrTerminate);
 }
 
 void IncomingJingleFileTransfer::startTransferViaRemoteCandidate() {
@@ -369,7 +367,6 @@ void IncomingJingleFileTransfer::startTransferViaLocalCandidate() {
 	}
 }
 
-
 void IncomingJingleFileTransfer::startTransferring(boost::shared_ptr<TransportSession> transportSession) {
 	SWIFT_LOG(debug) << std::endl;
 
@@ -393,11 +390,11 @@ bool IncomingJingleFileTransfer::isTryingCandidates() const {
 }
 
 boost::shared_ptr<TransportSession> IncomingJingleFileTransfer::createLocalCandidateSession() {
-	return transporter->createLocalCandidateSession(stream);
+	return transporter->createLocalCandidateSession(stream, theirCandidateChoice.get());
 }
 
 boost::shared_ptr<TransportSession> IncomingJingleFileTransfer::createRemoteCandidateSession() {
-	return transporter->createRemoteCandidateSession(stream);
+	return transporter->createRemoteCandidateSession(stream, ourCandidateChoice.get());
 }
 
 void IncomingJingleFileTransfer::terminate(JinglePayload::Reason::Type reason) {
diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.h b/Swiften/FileTransfer/IncomingJingleFileTransfer.h
index 7fc22f4..9820e34 100644
--- a/Swiften/FileTransfer/IncomingJingleFileTransfer.h
+++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2014 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -76,7 +76,8 @@ namespace Swift {
 
 			virtual void handleLocalTransportCandidatesGenerated(
 					const std::string& s5bSessionID, 
-					const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE;
+					const std::vector<JingleS5BTransportPayload::Candidate>&,
+					const std::string& dstAddr) SWIFTEN_OVERRIDE;
 
 			void handleWriteStreamDataReceived(const std::vector<unsigned char>& data);
 			void stopActiveTransport();
diff --git a/Swiften/FileTransfer/JingleFileTransfer.cpp b/Swiften/FileTransfer/JingleFileTransfer.cpp
index e2c0f3a..dbc4391 100644
--- a/Swiften/FileTransfer/JingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/JingleFileTransfer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Isode Limited.
+ * Copyright (c) 2013-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -112,9 +112,11 @@ void JingleFileTransfer::decideOnCandidates() {
 		fallback();
 	}
 	else if (ourCandidateChoice && !theirCandidateChoice) {
+		SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid << "." << std::endl;
 		startTransferViaRemoteCandidate();
 	}
 	else if (theirCandidateChoice && !ourCandidateChoice) {
+		SWIFT_LOG(debug) << "Start transfer using local candidate: " << theirCandidateChoice.get().cid << "." << std::endl;
 		startTransferViaLocalCandidate();
 	}
 	else {
@@ -122,16 +124,20 @@ void JingleFileTransfer::decideOnCandidates() {
 			<< ourCandidateChoice->cid << "(" << ourCandidateChoice->priority << ")" << " and " 
 			<< theirCandidateChoice->cid << "(" << theirCandidateChoice->priority << ")" << std::endl;
 		if (ourCandidateChoice->priority > theirCandidateChoice->priority) {
+			SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid << "." << std::endl;
 			startTransferViaRemoteCandidate();
 		}
 		else if (ourCandidateChoice->priority < theirCandidateChoice->priority) {
+			SWIFT_LOG(debug) << "Start transfer using local candidate:" << theirCandidateChoice.get().cid << "." << std::endl;
 			startTransferViaLocalCandidate();
 		}
 		else {
 			if (hasPriorityOnCandidateTie()) {
+				SWIFT_LOG(debug) << "Start transfer using remote candidate: " << ourCandidateChoice.get().cid << std::endl;
 				startTransferViaRemoteCandidate();
 			}
 			else {
+				SWIFT_LOG(debug) << "Start transfer using local candidate: " << theirCandidateChoice.get().cid << std::endl;
 				startTransferViaLocalCandidate();
 			}
 		}
@@ -156,7 +162,7 @@ void JingleFileTransfer::handleProxyActivateFinished(
 		proxyActivate->setSessionID(s5bSessionID);
 		proxyActivate->setActivated(theirCandidateChoice->cid);
 		session->sendTransportInfo(getContentID(), proxyActivate);
-		startTransferring(createRemoteCandidateSession());
+		startTransferring(createLocalCandidateSession());
 	}
 }
 
@@ -193,6 +199,10 @@ void JingleFileTransfer::handleTransportInfoReceived(
 				terminate(JinglePayload::Reason::GeneralError);
 			}
 		}
+		else if (s5bPayload->hasProxyError()) {
+			SWIFT_LOG(debug) << "Received proxy error. Trying to fall back to IBB." << std::endl;
+			fallback();
+		}
 		else {
 			SWIFT_LOG(debug) << "Ignoring unknown info" << std::endl;
 		}
@@ -205,7 +215,7 @@ void JingleFileTransfer::handleTransportInfoReceived(
 void JingleFileTransfer::setTransporter(FileTransferTransporter* transporter) {
 	this->transporter = transporter;
 	localTransportCandidatesGeneratedConnection = transporter->onLocalCandidatesGenerated.connect(
-		boost::bind(&JingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1, _2));
+		boost::bind(&JingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1, _2, _3));
 	remoteTransportCandidateSelectFinishedConnection = transporter->onRemoteCandidateSelectFinished.connect(
 		boost::bind(&JingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1, _2));
 	proxyActivatedConnection = transporter->onProxyActivated.connect(
diff --git a/Swiften/FileTransfer/JingleFileTransfer.h b/Swiften/FileTransfer/JingleFileTransfer.h
index 6ab0d86..aabeec2 100644
--- a/Swiften/FileTransfer/JingleFileTransfer.h
+++ b/Swiften/FileTransfer/JingleFileTransfer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Isode Limited.
+ * Copyright (c) 2013-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -39,7 +39,8 @@ namespace Swift {
 			virtual void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref);
 			virtual void handleLocalTransportCandidatesGenerated(
 					const std::string& s5bSessionID, 
-					const std::vector<JingleS5BTransportPayload::Candidate>&) = 0;
+					const std::vector<JingleS5BTransportPayload::Candidate>&,
+					const std::string& dstAddr) = 0;
 			virtual void handleProxyActivateFinished(
 					const std::string& s5bSessionID, 
 					ErrorPayload::ref error);
diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
index 07e927e..7ff1a08 100644
--- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
@@ -111,7 +111,7 @@ void OutgoingJingleFileTransfer::handleSessionAcceptReceived(
 	if (state != WaitingForAccept) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; }
 
 	if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload)) {
-		transporter->addRemoteCandidates(s5bPayload->getCandidates());
+		transporter->addRemoteCandidates(s5bPayload->getCandidates(), s5bPayload->getDstAddr());
 		setState(TryingCandidates);
 		transporter->startTryingRemoteCandidates();
 	}
@@ -123,7 +123,7 @@ void OutgoingJingleFileTransfer::handleSessionAcceptReceived(
 
 void OutgoingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) {
 	SWIFT_LOG(debug) << std::endl;
-	if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; }
+	if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state: " << state << std::endl; return; }
 
 	stopAll();
 	if (reason && reason->type == JinglePayload::Reason::Cancel) {
@@ -150,6 +150,12 @@ void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleConte
 	}
 }
 
+void OutgoingJingleFileTransfer::handleTransportRejectReceived(const JingleContentID &, boost::shared_ptr<JingleTransportPayload>) {
+	SWIFT_LOG(debug) << std::endl;
+
+	terminate(JinglePayload::Reason::UnsupportedTransports);
+}
+
 void OutgoingJingleFileTransfer::sendSessionInfoHash() {
 	SWIFT_LOG(debug) << std::endl;
 
@@ -160,7 +166,7 @@ void OutgoingJingleFileTransfer::sendSessionInfoHash() {
 }
 
 void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated(
-		const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>& candidates) {
+		const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>& candidates, const std::string& dstAddr) {
 	SWIFT_LOG(debug) << std::endl;
 	if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; }
 
@@ -174,6 +180,7 @@ void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated(
 	JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>();
 	transport->setSessionID(s5bSessionID);
 	transport->setMode(JingleS5BTransportPayload::TCPMode);
+	transport->setDstAddr(dstAddr);
 	foreach(JingleS5BTransportPayload::Candidate candidate, candidates) {
 		transport->addCandidate(candidate);	
 	}
@@ -182,8 +189,8 @@ void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated(
 }
 
 void OutgoingJingleFileTransfer::fallback() {
-	SWIFT_LOG(debug) << std::endl;
 	if (options.isInBandAllowed()) {
+		SWIFT_LOG(debug) << "Trying to fallback to IBB transport." << std::endl;
 		JingleIBBTransportPayload::ref ibbTransport = boost::make_shared<JingleIBBTransportPayload>();
 		ibbTransport->setBlockSize(DEFAULT_BLOCK_SIZE);
 		ibbTransport->setSessionID(idGenerator->generateID());
@@ -191,13 +198,14 @@ void OutgoingJingleFileTransfer::fallback() {
 		session->sendTransportReplace(contentID, ibbTransport);
 	}
 	else {
+		SWIFT_LOG(debug) << "Fallback to IBB transport not allowed." << std::endl;
 		terminate(JinglePayload::Reason::ConnectivityError);
 	}
 }
 
 void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) {
 	SWIFT_LOG(debug) << std::endl;
-	if (state != Transferring) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; }
+	if (state != Transferring) { SWIFT_LOG(warning) << "Incorrect state: " << state << std::endl; return; }
 
 	if (error) {
 		terminate(JinglePayload::Reason::ConnectivityError);
@@ -347,11 +355,11 @@ bool OutgoingJingleFileTransfer::isTryingCandidates() const {
 }
 
 boost::shared_ptr<TransportSession> OutgoingJingleFileTransfer::createLocalCandidateSession() {
-	return transporter->createLocalCandidateSession(stream);
+	return transporter->createLocalCandidateSession(stream, theirCandidateChoice.get());
 }
 
 boost::shared_ptr<TransportSession> OutgoingJingleFileTransfer::createRemoteCandidateSession() {
-	return transporter->createRemoteCandidateSession(stream);
+	return transporter->createRemoteCandidateSession(stream, ourCandidateChoice.get());
 }
 
 void OutgoingJingleFileTransfer::handleWaitForRemoteTerminationTimeout() {
diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h
index 52960d5..4cb2685 100644
--- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h
+++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h
@@ -54,7 +54,7 @@ namespace Swift {
 		private:
 			enum State {
 				Initial,
-				GeneratingInitialLocalCandidates,	
+				GeneratingInitialLocalCandidates,
 				WaitingForAccept,
 				TryingCandidates,
 				WaitingForPeerProxyActivate,
@@ -69,11 +69,12 @@ namespace Swift {
 			virtual void handleSessionAcceptReceived(const JingleContentID&, boost::shared_ptr<JingleDescription>, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE;
 			virtual void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) SWIFTEN_OVERRIDE;
 			virtual void handleTransportAcceptReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE;
+			virtual void handleTransportRejectReceived(const JingleContentID &, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE;
 			virtual void startTransferViaRemoteCandidate() SWIFTEN_OVERRIDE;
 			virtual void startTransferViaLocalCandidate() SWIFTEN_OVERRIDE;
 			void startTransferringIfCandidateAcknowledged();
 
-			virtual void handleLocalTransportCandidatesGenerated(const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE;
+			virtual void handleLocalTransportCandidatesGenerated(const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>&, const std::string& dstAddr) SWIFTEN_OVERRIDE;
 			virtual void handleTransportInfoAcknowledged(const std::string& id) SWIFTEN_OVERRIDE;
 
 			virtual JingleContentID getContentID() const SWIFTEN_OVERRIDE;
diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp
index 82fd17e..812adbe 100644
--- a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp
+++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp
@@ -5,7 +5,7 @@
  */
 
 /*
- * Copyright (c) 2013 Isode Limited.
+ * Copyright (c) 2013-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -36,7 +36,7 @@ SOCKS5BytestreamClientSession::SOCKS5BytestreamClientSession(
 			destination(destination), 
 			state(Initial), 
 			chunkSize(131072) {
-	weFailedTimeout = timerFactory->createTimer(2000);
+	weFailedTimeout = timerFactory->createTimer(3000);
 	weFailedTimeout->onTick.connect(
 			boost::bind(&SOCKS5BytestreamClientSession::handleWeFailedTimeout, this));
 }
@@ -55,6 +55,9 @@ void SOCKS5BytestreamClientSession::start() {
 
 void SOCKS5BytestreamClientSession::stop() {
 	SWIFT_LOG(debug) << std::endl;
+	if (state < Ready) {
+		weFailedTimeout->stop();
+	}
 	if (state == Finished) {
 		return;
 	}
@@ -201,7 +204,9 @@ void SOCKS5BytestreamClientSession::sendData() {
 
 void SOCKS5BytestreamClientSession::finish(bool error) {
 	SWIFT_LOG(debug) << std::endl;
-	weFailedTimeout->stop();
+	if (state < Ready) {
+		weFailedTimeout->stop();
+	}
 	closeConnection();
 	readBytestream.reset();
 	if (state == Initial || state == Hello || state == Authenticating) {
@@ -228,6 +233,7 @@ void SOCKS5BytestreamClientSession::handleConnectFinished(bool error) {
 				boost::bind(&SOCKS5BytestreamClientSession::handleDisconnected, this, _1));
 		dataReadConnection = connection->onDataRead.connect(
 				boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1));
+		weFailedTimeout->stop();
 		weFailedTimeout->start();
 		process();
 	}
diff --git a/Swiften/Network/BoostNetworkFactories.h b/Swiften/Network/BoostNetworkFactories.h
index baadbf1..32fdd93 100644
--- a/Swiften/Network/BoostNetworkFactories.h
+++ b/Swiften/Network/BoostNetworkFactories.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -19,7 +19,7 @@ namespace Swift {
 	class SWIFTEN_API BoostNetworkFactories : public NetworkFactories {
 		public:
 			BoostNetworkFactories(EventLoop* eventLoop);
-			~BoostNetworkFactories();
+			virtual ~BoostNetworkFactories();
 
 			virtual TimerFactory* getTimerFactory() const SWIFTEN_OVERRIDE {
 				return timerFactory;
-- 
cgit v0.10.2-6-g49f6