summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/FileTransfer/IncomingJingleFileTransfer.cpp')
-rw-r--r--Swiften/FileTransfer/IncomingJingleFileTransfer.cpp504
1 files changed, 503 insertions, 1 deletions
diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
index cb2f65c..0871568 100644
--- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
@@ -6,14 +6,516 @@
#include <Swiften/FileTransfer/IncomingJingleFileTransfer.h>
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Base/Log.h>
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Elements/JingleIBBTransportPayload.h>
+#include <Swiften/Elements/JingleS5BTransportPayload.h>
+#include <Swiften/Elements/JingleFileTransferHash.h>
+#include <Swiften/Elements/S5BProxyRequest.h>
+#include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h>
+#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h>
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h>
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h>
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h>
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h>
+#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h>
+#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h>
+#include <Swiften/Network/TimerFactory.h>
+#include <Swiften/Queries/GenericRequest.h>
+
namespace Swift {
-IncomingJingleFileTransfer::IncomingJingleFileTransfer(IncomingJingleSession::ref session) : session(session) {
+IncomingJingleFileTransfer::IncomingJingleFileTransfer(
+ const JID& ourJID,
+ JingleSession::ref session,
+ JingleContentPayload::ref content,
+ RemoteJingleTransportCandidateSelectorFactory* candidateSelectorFactory,
+ LocalJingleTransportCandidateGeneratorFactory* candidateGeneratorFactory,
+ IQRouter* router,
+ SOCKS5BytestreamRegistry* registry,
+ SOCKS5BytestreamProxy* proxy,
+ TimerFactory* timerFactory) :
+ ourJID(ourJID),
+ session(session),
+ router(router),
+ timerFactory(timerFactory),
+ initialContent(content),
+ state(Initial),
+ receivedBytes(0),
+ s5bRegistry(registry),
+ s5bProxy(proxy),
+ remoteTransportCandidateSelectFinished(false),
+ localTransportCandidateSelectFinished(false),
+ serverSession(0) {
+
+ candidateSelector = candidateSelectorFactory->createCandidateSelector();
+ candidateSelector->onRemoteTransportCandidateSelectFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1));
+
+ candidateGenerator = candidateGeneratorFactory->createCandidateGenerator();
+ candidateGenerator->onLocalTransportCandidatesGenerated.connect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1));
+
+ session->onTransportInfoReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2));
+ session->onTransportReplaceReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2));
+ session->onSessionTerminateReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this, _1));
+ session->onSessionInfoReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleSessionInfoReceived, this, _1));
+
+ description = initialContent->getDescription<JingleFileTransferDescription>();
+ assert(description);
+ assert(description->getOffers().size() == 1);
+ StreamInitiationFileInfo fileInfo = description->getOffers().front();
+ fileSizeInBytes = fileInfo.getSize();
+ filename = fileInfo.getName();
+ hash = fileInfo.getHash();
+ algo = fileInfo.getAlgo();
+
+ waitOnHashTimer = timerFactory->createTimer(5000);
+ waitOnHashTimer->onTick.connect(boost::bind(&IncomingJingleFileTransfer::finishOffTransfer, this));
+}
+
+IncomingJingleFileTransfer::~IncomingJingleFileTransfer() {
+ stream->onWrite.disconnect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1));
+ delete hashCalculator;
+
+ session->onSessionTerminateReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this));
+ session->onTransportReplaceReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2));
+ session->onTransportInfoReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2));
+
+ candidateGenerator->onLocalTransportCandidatesGenerated.disconnect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1));
+ delete candidateGenerator;
+ candidateSelector->onRemoteTransportCandidateSelectFinished.disconnect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1));
+ delete candidateSelector;
}
void IncomingJingleFileTransfer::accept(WriteBytestream::ref stream) {
+ assert(!this->stream);
this->stream = stream;
+
+ hashCalculator = new IncrementalBytestreamHashCalculator( algo == "md5" || hash.empty() , algo == "sha-1" || hash.empty() );
+ stream->onWrite.connect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1));
+ stream->onWrite.connect(boost::bind(&IncomingJingleFileTransfer::handleWriteStreamDataReceived, this, _1));
+ onStateChange(FileTransfer::State(FileTransfer::State::Negotiating));
+ if (JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>()) {
+ SWIFT_LOG(debug) << "Got IBB transport payload!" << std::endl;
+ setActiveTransport(createIBBTransport(ibbTransport));
+ session->sendAccept(getContentID(), initialContent->getDescriptions()[0], ibbTransport);
+ }
+ else if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) {
+ SWIFT_LOG(debug) << "Got S5B transport payload!" << std::endl;
+ state = CreatingInitialTransports;
+ s5bSessionID = s5bTransport->getSessionID().empty() ? idGenerator.generateID() : s5bTransport->getSessionID();
+ s5bDestination = SOCKS5BytestreamRegistry::getHostname(s5bSessionID, ourJID, session->getInitiator());
+ s5bRegistry->addWriteBytestream(s5bDestination, stream);
+ fillCandidateMap(theirCandidates, s5bTransport);
+ candidateSelector->addRemoteTransportCandidates(s5bTransport);
+ candidateSelector->setRequesterTargtet(session->getInitiator(), ourJID);
+ s5bTransport->setSessionID(s5bSessionID);
+ candidateGenerator->generateLocalTransportCandidates(s5bTransport);
+ }
+ else {
+ assert(false);
+ }
+}
+
+const JID& IncomingJingleFileTransfer::getSender() const {
+ return session->getInitiator();
+}
+
+const JID& IncomingJingleFileTransfer::getRecipient() const {
+ return ourJID;
+}
+
+void IncomingJingleFileTransfer::cancel() {
+ session->sendTerminate(JinglePayload::Reason::Cancel);
+
+ if (activeTransport) activeTransport->stop();
+ if (serverSession) serverSession->stop();
+ if (clientSession) clientSession->stop();
+ onStateChange(FileTransfer::State(FileTransfer::State::Canceled));
+}
+
+void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates) {
+ if (state == CreatingInitialTransports) {
+ if (JingleS5BTransportPayload::ref s5bCandidates = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(candidates)) {
+ //localTransportCandidateSelectFinished = true;
+ //JingleS5BTransportPayload::ref emptyCandidates = boost::make_shared<JingleS5BTransportPayload>();
+ //emptyCandidates->setSessionID(s5bCandidates->getSessionID());
+ fillCandidateMap(ourCandidates, s5bCandidates);
+ session->sendAccept(getContentID(), initialContent->getDescriptions()[0], s5bCandidates);
+
+ state = NegotiatingTransport;
+ candidateSelector->selectCandidate();
+ }
+ }
+ else {
+ SWIFT_LOG(debug) << "Unhandled state!" << std::endl;
+ }
+}
+
+
+void IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref transport) {
+ SWIFT_LOG(debug) << std::endl;
+ if (state == Terminated) {
+ return;
+ }
+ if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) {
+ //remoteTransportCandidateSelectFinished = true;
+ //selectedRemoteTransportCandidate = transport;
+ ourCandidate = s5bPayload;
+ //checkCandidateSelected();
+ decideOnUsedTransport();
+ session->sendTransportInfo(getContentID(), s5bPayload);
+ }
+ else {
+ SWIFT_LOG(debug) << "Expected something different here." << std::endl;
+ }
+}
+
+void IncomingJingleFileTransfer::checkCandidateSelected() {
+ assert(false);
+ if (localTransportCandidateSelectFinished && remoteTransportCandidateSelectFinished) {
+ if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate) && candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) {
+ if (candidateGenerator->getPriority(selectedLocalTransportCandidate) > candidateSelector->getPriority(selectedRemoteTransportCandidate)) {
+ setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate));
+ }
+ else {
+ setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate));
+ }
+ }
+ else if (candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) {
+ setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate));
+ }
+ else if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate)) {
+ setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate));
+ }
+ else {
+ state = WaitingForFallbackOrTerminate;
+ }
+ }
+}
+
+void IncomingJingleFileTransfer::setActiveTransport(JingleTransport::ref transport) {
+ state = Transferring;
+ onStateChange(FileTransfer::State(FileTransfer::State::Transferring));
+ activeTransport = transport;
+ activeTransport->onDataReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1));
+ activeTransport->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1));
+ activeTransport->start();
+}
+
+bool IncomingJingleFileTransfer::verifyReceviedData() {
+ if (algo.empty() || hash.empty()) {
+ SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl;
+ return true;
+ } else {
+ if (algo == "sha-1") {
+ SWIFT_LOG(debug) << "verify data via SHA-1 hash: " << (hash == hashCalculator->getSHA1String()) << std::endl;
+ return hash == hashCalculator->getSHA1String();
+ }
+ else if (algo == "md5") {
+ SWIFT_LOG(debug) << "verify data via MD5 hash: " << (hash == hashCalculator->getMD5String()) << std::endl;
+ return hash == hashCalculator->getMD5String();
+ }
+ else {
+ SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl;
+ return true;
+ }
+ }
+}
+
+void IncomingJingleFileTransfer::finishOffTransfer() {
+ if (verifyReceviedData()) {
+ onStateChange(FileTransfer::State(FileTransfer::State::Finished));
+ session->sendTerminate(JinglePayload::Reason::Success);
+ } else {
+ onStateChange(FileTransfer::State(FileTransfer::State::Failed, "Verification failed."));
+ session->sendTerminate(JinglePayload::Reason::MediaError);
+ }
+ state = Terminated;
+ waitOnHashTimer->stop();
+}
+
+void IncomingJingleFileTransfer::handleSessionInfoReceived(JinglePayload::ref jinglePayload) {
+ if (state == Terminated) {
+ return;
+ }
+ JingleFileTransferHash::ref transferHash = jinglePayload->getPayload<JingleFileTransferHash>();
+ if (transferHash) {
+ SWIFT_LOG(debug) << "Recevied hash information." << std::endl;
+ if (transferHash->getHashes().find("sha-1") != transferHash->getHashes().end()) {
+ algo = "sha-1";
+ hash = transferHash->getHashes().find("sha-1")->second;
+ }
+ else if (transferHash->getHashes().find("md5") != transferHash->getHashes().end()) {
+ algo = "md5";
+ hash = transferHash->getHashes().find("md5")->second;
+ }
+ checkIfAllDataReceived();
+ }
+}
+
+void IncomingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) {
+ SWIFT_LOG(debug) << "session terminate received" << std::endl;
+ if (activeTransport) activeTransport->stop();
+ if (reason && reason.get().type == JinglePayload::Reason::Cancel) {
+ onStateChange(FileTransfer::State(FileTransfer::State::Canceled, "Other user canceled the transfer."));
+ }
+ else if (reason && reason.get().type == JinglePayload::Reason::Success) {
+ /*if (verifyReceviedData()) {
+ onStateChange(FileTransfer::State(FileTransfer::State::Finished));
+ } else {
+ onStateChange(FileTransfer::State(FileTransfer::State::Failed, "Verification failed."));
+ }*/
+ }
+ state = Terminated;
+}
+
+void IncomingJingleFileTransfer::checkIfAllDataReceived() {
+ if (receivedBytes == fileSizeInBytes) {
+ SWIFT_LOG(debug) << "All data received." << std::endl;
+ if (hash.empty()) {
+ SWIFT_LOG(debug) << "No hash information yet. Waiting 5 seconds on hash info." << std::endl;
+ waitOnHashTimer->start();
+ } else {
+ SWIFT_LOG(debug) << "We already have hash info using " << algo << " algorithm. Finishing off transfer." << std::endl;
+ finishOffTransfer();
+ }
+ }
+ else if (receivedBytes > fileSizeInBytes) {
+ SWIFT_LOG(debug) << "We got more than we could handle!" << std::endl;
+ }
+}
+
+void IncomingJingleFileTransfer::handleTransportDataReceived(const std::vector<unsigned char>& data) {
+ SWIFT_LOG(debug) << data.size() << " bytes received" << std::endl;
+ onProcessedBytes(data.size());
+ stream->write(data);
+ receivedBytes += data.size();
+ checkIfAllDataReceived();
+}
+
+void IncomingJingleFileTransfer::handleWriteStreamDataReceived(const std::vector<unsigned char>& data) {
+ receivedBytes += data.size();
+ checkIfAllDataReceived();
+}
+
+void IncomingJingleFileTransfer::useOurCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate) {
+ SWIFT_LOG(debug) << std::endl;
+ if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) {
+ // get proxy client session from remoteCandidateSelector
+ clientSession = candidateSelector->getS5BSession();
+
+ // wait on <activated/> transport-info
+ } else {
+ // ask s5b client
+ clientSession = candidateSelector->getS5BSession();
+ if (clientSession) {
+ state = Transferring;
+ SWIFT_LOG(debug) << clientSession->getAddressPort().toString() << std::endl;
+ clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1));
+ clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1));
+ clientSession->startReceiving(stream);
+ } else {
+ SWIFT_LOG(debug) << "No S5B client session found!!!" << std::endl;
+ }
+ }
+}
+
+void IncomingJingleFileTransfer::useTheirCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate) {
+ SWIFT_LOG(debug) << std::endl;
+
+ if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) {
+ // get proxy client session from s5bRegistry
+ clientSession = s5bProxy->createSOCKS5BytestreamClientSession(candidate.hostPort, SOCKS5BytestreamRegistry::getHostname(s5bSessionID, ourJID, session->getInitiator()));
+ clientSession->onSessionReady.connect(boost::bind(&IncomingJingleFileTransfer::proxySessionReady, this, candidate.jid, _1));
+ clientSession->start();
+
+ // on reply send activate
+ } else {
+ // ask s5b server
+ serverSession = s5bRegistry->getConnectedSession(s5bDestination);
+ if (serverSession) {
+ state = Transferring;
+ serverSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1));
+ serverSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1));
+ serverSession->startTransfer();
+ } else {
+ SWIFT_LOG(debug) << "No S5B server session found!!!" << std::endl;
+ }
+ }
+}
+
+void IncomingJingleFileTransfer::fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload) {
+ map.clear();
+ foreach (JingleS5BTransportPayload::Candidate candidate, s5bPayload->getCandidates()) {
+ map[candidate.cid] = candidate;
+ }
+}
+
+
+void IncomingJingleFileTransfer::decideOnUsedTransport() {
+ if (ourCandidate && theirCandidate) {
+ if (ourCandidate->hasCandidateError() && theirCandidate->hasCandidateError()) {
+ state = WaitingForFallbackOrTerminate;
+ return;
+ }
+ std::string our_cid = ourCandidate->getCandidateUsed();
+ std::string their_cid = theirCandidate->getCandidateUsed();
+ if (ourCandidate->hasCandidateError() && !their_cid.empty()) {
+ useTheirCandidateChoiceForTransfer(ourCandidates[their_cid]);
+ onStateChange(FileTransfer::State(FileTransfer::State::Transferring));
+ }
+ else if (theirCandidate->hasCandidateError() && !our_cid.empty()) {
+ useOurCandidateChoiceForTransfer(theirCandidates[our_cid]);
+ onStateChange(FileTransfer::State(FileTransfer::State::Transferring));
+ }
+ else if (!our_cid.empty() && !their_cid.empty()) {
+ // compare priorites, if same they win
+ if (ourCandidates.find(their_cid) == ourCandidates.end() || theirCandidates.find(our_cid) == theirCandidates.end()) {
+ SWIFT_LOG(debug) << "Didn't recognize candidate IDs!" << std::endl;
+ session->sendTerminate(JinglePayload::Reason::FailedTransport);
+ onStateChange(FileTransfer::State(FileTransfer::State::Canceled, "Failed to negotiate candidate."));
+ onFinished(FileTransferError(FileTransferError::PeerError));
+ return;
+ }
+
+ JingleS5BTransportPayload::Candidate our_candidate = theirCandidates[our_cid];
+ JingleS5BTransportPayload::Candidate their_candidate = ourCandidates[their_cid];
+ if (our_candidate.priority > their_candidate.priority) {
+ useOurCandidateChoiceForTransfer(our_candidate);
+ }
+ else if (our_candidate.priority < their_candidate.priority) {
+ useTheirCandidateChoiceForTransfer(their_candidate);
+ }
+ else {
+ useTheirCandidateChoiceForTransfer(their_candidate);
+ }
+ onStateChange(FileTransfer::State(FileTransfer::State::Transferring));
+ }
+ else {
+ assert(false);
+ }
+ } else {
+ SWIFT_LOG(debug) << "Can't make a transport decision yet." << std::endl;
+ }
+}
+
+void IncomingJingleFileTransfer::proxySessionReady(const JID& proxy, bool error) {
+ if (error) {
+ // indicate proxy error
+ } else {
+ // activate proxy
+ activateProxySession(proxy);
+ }
+}
+
+void IncomingJingleFileTransfer::activateProxySession(const JID &proxy) {
+ S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>();
+ proxyRequest->setSID(s5bSessionID);
+ proxyRequest->setActivate(session->getInitiator());
+
+ boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Set, proxy, proxyRequest, router);
+ request->onResponse.connect(boost::bind(&IncomingJingleFileTransfer::handleActivateProxySessionResult, this, _1, _2));
+ request->send();
+}
+
+void IncomingJingleFileTransfer::handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> /*request*/, ErrorPayload::ref error) {
+ SWIFT_LOG(debug) << std::endl;
+ if (error) {
+ SWIFT_LOG(debug) << "ERROR" << std::endl;
+ } else {
+ // send activated to other jingle party
+ JingleS5BTransportPayload::ref proxyActivate = boost::make_shared<JingleS5BTransportPayload>();
+ proxyActivate->setActivated(theirCandidate->getCandidateUsed());
+ session->sendTransportInfo(getContentID(), proxyActivate);
+
+ // start transferring
+ clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1));
+ clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1));
+ clientSession->startReceiving(stream);
+ onStateChange(FileTransfer::State(FileTransfer::State::Transferring));
+ }
+}
+
+void IncomingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref transport) {
+ SWIFT_LOG(debug) << "transport info received" << std::endl;
+ if (state == Terminated) {
+ return;
+ }
+ if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) {
+ if (!s5bPayload->getActivated().empty()) {
+ if (ourCandidate->getCandidateUsed() == s5bPayload->getActivated()) {
+ clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1));
+ clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1));
+ clientSession->startReceiving(stream);
+ onStateChange(FileTransfer::State(FileTransfer::State::Transferring));
+ } else {
+ SWIFT_LOG(debug) << "ourCandidateChoice doesn't match activated proxy candidate!" << std::endl;
+ JingleS5BTransportPayload::ref proxyError = boost::make_shared<JingleS5BTransportPayload>();
+ proxyError->setProxyError(true);
+ proxyError->setSessionID(s5bSessionID);
+ session->sendTransportInfo(getContentID(), proxyError);
+ }
+ } else {
+ theirCandidate = s5bPayload;
+ decideOnUsedTransport();
+ }
+ }
+ else {
+ SWIFT_LOG(debug) << "Expected something different here." << std::endl;
+ }
+ /*localTransportCandidateSelectFinished = true;
+ selectedLocalTransportCandidate = transport;
+ if (candidateGenerator->isActualCandidate(transport)) {
+ candidateSelector->setMinimumPriority(candidateGenerator->getPriority(transport));
+ }*/
+ //checkCandidateSelected();
+}
+
+void IncomingJingleFileTransfer::handleTransportReplaceReceived(const JingleContentID& content, JingleTransportPayload::ref transport) {
+ if (state == Terminated) {
+ return;
+ }
+ if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) {
+ SWIFT_LOG(debug) << "transport replaced with IBB" << std::endl;
+ setActiveTransport(createIBBTransport(ibbTransport));
+ session->sendTransportAccept(content, ibbTransport);
+ } else {
+ SWIFT_LOG(debug) << "transport replaced failed" << std::endl;
+ session->sendTransportReject(content, transport);
+ }
+}
+
+void IncomingJingleFileTransfer::stopActiveTransport() {
+ if (activeTransport) {
+ activeTransport->stop();
+ activeTransport->onDataReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1));
+ }
+}
+
+JingleIncomingIBBTransport::ref IncomingJingleFileTransfer::createIBBTransport(JingleIBBTransportPayload::ref ibbTransport) {
+ // TODO: getOffer() -> getOffers correction
+ return boost::make_shared<JingleIncomingIBBTransport>(session->getInitiator(), getRecipient(), ibbTransport->getSessionID(), description->getOffers()[0].getSize(), router);
+}
+
+JingleContentID IncomingJingleFileTransfer::getContentID() const {
+ return JingleContentID(initialContent->getName(), initialContent->getCreator());
+}
+
+void IncomingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) {
+ if (state == Terminated) {
+ return;
+ }
+
+ if (error) {
+ session->sendTerminate(JinglePayload::Reason::ConnectivityError);
+ onStateChange(FileTransfer::State(FileTransfer::State::Failed));
+ onFinished(error);
+ }
+ //
}
}