/* * Copyright (c) 2013-2019 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Swift; DefaultFileTransferTransporter::DefaultFileTransferTransporter( const JID& initiator, const JID& responder, Role role, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamServerManager* s5bServerManager, SOCKS5BytestreamProxiesManager* s5bProxy, IDGenerator* idGenerator, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, CryptoProvider* crypto, IQRouter* router, const FileTransferOptions& options) : initiator(initiator), responder(responder), role(role), s5bRegistry(s5bRegistry), s5bServerManager(s5bServerManager), s5bProxy(s5bProxy), crypto(crypto), router(router) { localCandidateGenerator = new LocalJingleTransportCandidateGenerator( s5bServerManager, s5bProxy, role == Initiator ? initiator : responder, idGenerator, options); localCandidateGenerator->onLocalTransportCandidatesGenerated.connect( boost::bind(&DefaultFileTransferTransporter::handleLocalCandidatesGenerated, this, _1)); remoteCandidateSelector = new RemoteJingleTransportCandidateSelector( connectionFactory, timerFactory, options); remoteCandidateSelector->onCandidateSelectFinished.connect( boost::bind(&DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished, this, _1, _2)); } DefaultFileTransferTransporter::~DefaultFileTransferTransporter() { DefaultFileTransferTransporter::stopGeneratingLocalCandidates(); remoteCandidateSelector->onCandidateSelectFinished.disconnect( boost::bind(&DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished, this, _1, _2)); delete remoteCandidateSelector; localCandidateGenerator->onLocalTransportCandidatesGenerated.disconnect( boost::bind(&DefaultFileTransferTransporter::handleLocalCandidatesGenerated, this, _1)); delete localCandidateGenerator; } void DefaultFileTransferTransporter::initialize() { s5bSessionID = s5bRegistry->generateSessionID(); } void DefaultFileTransferTransporter::initialize(const std::string& s5bSessionID) { this->s5bSessionID = s5bSessionID; } void DefaultFileTransferTransporter::startGeneratingLocalCandidates() { localCandidateGenerator->start(); } void DefaultFileTransferTransporter::stopGeneratingLocalCandidates() { localCandidateGenerator->stop(); } void DefaultFileTransferTransporter::handleLocalCandidatesGenerated( const std::vector& candidates) { s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), true); s5bProxy->connectToProxies(getSOCKS5DstAddr()); onLocalCandidatesGenerated(s5bSessionID, candidates, getSOCKS5DstAddr()); } void DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished( const boost::optional& candidate, std::shared_ptr session) { remoteS5BClientSession = session; onRemoteCandidateSelectFinished(s5bSessionID, candidate); } void DefaultFileTransferTransporter::addRemoteCandidates( const std::vector& candidates, const std::string& dstAddr) { remoteCandidateSelector->setSOCKS5DstAddr(dstAddr.empty() ? getRemoteCandidateSOCKS5DstAddr() : dstAddr); remoteCandidateSelector->addCandidates(candidates); } void DefaultFileTransferTransporter::startTryingRemoteCandidates() { remoteCandidateSelector->startSelectingCandidate(); } void DefaultFileTransferTransporter::stopTryingRemoteCandidates() { remoteCandidateSelector->stopSelectingCandidate(); } 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 << "."; S5BProxyRequest::ref proxyRequest = std::make_shared(); proxyRequest->setSID(s5bSessionID); proxyRequest->setActivate(role == Initiator ? responder : initiator); std::shared_ptr > request = std::make_shared >(IQ::Set, proxyServiceJID, proxyRequest, router); request->onResponse.connect(boost::bind(&DefaultFileTransferTransporter::handleActivateProxySessionResult, this, s5bSessionID, _2)); request->send(); } void DefaultFileTransferTransporter::stopActivatingProxy() { // TODO assert(false); } std::shared_ptr DefaultFileTransferTransporter::createIBBSendSession( const std::string& sessionID, unsigned int blockSize, std::shared_ptr stream) { if (s5bServerManager->getServer()) { closeLocalSession(); } closeRemoteSession(); std::shared_ptr ibbSession = std::make_shared( sessionID, initiator, responder, stream, router); ibbSession->setBlockSize(blockSize); return std::make_shared(ibbSession); } std::shared_ptr DefaultFileTransferTransporter::createIBBReceiveSession( const std::string& sessionID, unsigned long long size, std::shared_ptr stream) { if (s5bServerManager->getServer()) { closeLocalSession(); } closeRemoteSession(); std::shared_ptr ibbSession = std::make_shared( sessionID, initiator, responder, size, stream, router); return std::make_shared(ibbSession); } std::shared_ptr DefaultFileTransferTransporter::createRemoteCandidateSession( std::shared_ptr stream, const JingleS5BTransportPayload::Candidate& /* candidate */) { closeLocalSession(); return std::make_shared >( remoteS5BClientSession, stream); } std::shared_ptr DefaultFileTransferTransporter::createRemoteCandidateSession( std::shared_ptr stream, const JingleS5BTransportPayload::Candidate& /* candidate */) { closeLocalSession(); return std::make_shared >( remoteS5BClientSession, stream); } std::shared_ptr DefaultFileTransferTransporter::getServerSession() { s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), false); std::vector > serverSessions = s5bServerManager->getServer()->getSessions(getSOCKS5DstAddr()); while (serverSessions.size() > 1) { std::shared_ptr session = serverSessions.back(); serverSessions.pop_back(); session->stop(); } return !serverSessions.empty() ? serverSessions.front() : std::shared_ptr(); } std::shared_ptr DefaultFileTransferTransporter::createLocalCandidateSession( std::shared_ptr stream, const JingleS5BTransportPayload::Candidate& candidate) { closeRemoteSession(); std::shared_ptr transportSession; if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { SOCKS5BytestreamClientSession::ref proxySession = s5bProxy->getProxySessionAndCloseOthers(candidate.jid, getLocalCandidateSOCKS5DstAddr()); if (proxySession) { transportSession = std::make_shared >(proxySession, stream); } else { SWIFT_LOG(error) << "Failed obtaining proxy session with candidate JID " << candidate.jid << " and dstAddr " << getLocalCandidateSOCKS5DstAddr() << "."; } } if (!transportSession) { std::shared_ptr serverSession = getServerSession(); if (serverSession) { transportSession = std::make_shared >(serverSession, stream); } } if (!transportSession) { transportSession = std::make_shared(); } return transportSession; } std::shared_ptr DefaultFileTransferTransporter::createLocalCandidateSession( std::shared_ptr stream, const JingleS5BTransportPayload::Candidate& candidate) { closeRemoteSession(); std::shared_ptr transportSession; if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { SOCKS5BytestreamClientSession::ref proxySession = s5bProxy->getProxySessionAndCloseOthers(candidate.jid, getLocalCandidateSOCKS5DstAddr()); if (proxySession) { transportSession = std::make_shared >(proxySession, stream); } else { SWIFT_LOG(error) << "Failed obtaining proxy session with candidate JID " << candidate.jid << " and dstAddr " << getLocalCandidateSOCKS5DstAddr() << "."; } } if (!transportSession) { std::shared_ptr serverSession = getServerSession(); if (serverSession) { transportSession = std::make_shared >(serverSession, stream); } } if (!transportSession) { transportSession = std::make_shared(); } return transportSession; } std::string DefaultFileTransferTransporter::getSOCKS5DstAddr() const { std::string result; if (role == Initiator) { result = getInitiatorCandidateSOCKS5DstAddr(); SWIFT_LOG(debug) << "Initiator S5B DST.ADDR = " << s5bSessionID << " + " << initiator.toString() << " + " << responder.toString() << " : " << result; } else { result = getResponderCandidateSOCKS5DstAddr(); SWIFT_LOG(debug) << "Responder S5B DST.ADDR = " << s5bSessionID << " + " << responder.toString() << " + " << initiator.toString() << " : " << result; } 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() { s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), false); if (s5bServerManager->getServer()) { std::vector > serverSessions = s5bServerManager->getServer()->getSessions(getSOCKS5DstAddr()); for (auto&& session : serverSessions) { session->stop(); } } } void DefaultFileTransferTransporter::closeRemoteSession() { if (remoteS5BClientSession) { remoteS5BClientSession->stop(); remoteS5BClientSession.reset(); } }