diff options
Diffstat (limited to 'Swiften/FileTransfer/DefaultFileTransferTransporter.cpp')
-rw-r--r-- | Swiften/FileTransfer/DefaultFileTransferTransporter.cpp | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp new file mode 100644 index 0000000..af87fd2 --- /dev/null +++ b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/DefaultFileTransferTransporter.h> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> +#include <Swiften/FileTransfer/IBBSendSession.h> +#include <Swiften/FileTransfer/IBBReceiveSession.h> +#include <Swiften/FileTransfer/TransportSession.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Queries/GenericRequest.h> + +using namespace Swift; + +namespace { + class IBBSendTransportSession : public TransportSession { + public: + IBBSendTransportSession(boost::shared_ptr<IBBSendSession> session) : session(session) { + finishedConnection = session->onFinished.connect(boost::bind(boost::ref(onFinished), _1)); + bytesSentConnection = session->onBytesSent.connect(boost::bind(boost::ref(onBytesSent), _1)); + } + + virtual void start() SWIFTEN_OVERRIDE { + session->start(); + } + + virtual void stop() SWIFTEN_OVERRIDE { + session->stop(); + } + + private: + boost::shared_ptr<IBBSendSession> session; + boost::bsignals::scoped_connection finishedConnection; + boost::bsignals::scoped_connection bytesSentConnection; + }; + + class IBBReceiveTransportSession : public TransportSession { + public: + IBBReceiveTransportSession(boost::shared_ptr<IBBReceiveSession> session) : session(session) { + finishedConnection = session->onFinished.connect(boost::bind(boost::ref(onFinished), _1)); + } + + virtual void start() SWIFTEN_OVERRIDE { + session->start(); + } + + virtual void stop() SWIFTEN_OVERRIDE { + session->stop(); + } + + private: + boost::shared_ptr<IBBReceiveSession> session; + boost::bsignals::scoped_connection finishedConnection; + boost::bsignals::scoped_connection bytesSentConnection; + }; + + class FailingTransportSession : public TransportSession { + public: + virtual void start() SWIFTEN_OVERRIDE { + onFinished(FileTransferError(FileTransferError::PeerError)); + } + + virtual void stop() SWIFTEN_OVERRIDE { + } + }; + + template <typename T> + class S5BTransportSession : public TransportSession { + public: + S5BTransportSession( + boost::shared_ptr<T> session, + boost::shared_ptr<ReadBytestream> readStream) : + session(session), + readStream(readStream) { + initialize(); + } + + S5BTransportSession( + boost::shared_ptr<T> session, + boost::shared_ptr<WriteBytestream> writeStream) : + session(session), + writeStream(writeStream) { + initialize(); + } + + virtual void start() SWIFTEN_OVERRIDE { + if (readStream) { + session->startSending(readStream); + } + else { + session->startReceiving(writeStream); + } + } + + virtual void stop() SWIFTEN_OVERRIDE { + session->stop(); + } + + private: + void initialize() { + finishedConnection = session->onFinished.connect(boost::bind(boost::ref(onFinished), _1)); + bytesSentConnection = session->onBytesSent.connect(boost::bind(boost::ref(onBytesSent), _1)); + } + + private: + boost::shared_ptr<T> session; + boost::shared_ptr<ReadBytestream> readStream; + boost::shared_ptr<WriteBytestream> writeStream; + + boost::bsignals::scoped_connection finishedConnection; + boost::bsignals::scoped_connection bytesSentConnection; + }; +} + +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) : + initiator(initiator), + responder(responder), + role(role), + s5bRegistry(s5bRegistry), + s5bServerManager(s5bServerManager), + crypto(crypto), + router(router) { + + localCandidateGenerator = new LocalJingleTransportCandidateGenerator( + s5bServerManager, + s5bProxy, + role == Initiator ? initiator : responder, + idGenerator); + localCandidateGenerator->onLocalTransportCandidatesGenerated.connect( + boost::bind(&DefaultFileTransferTransporter::handleLocalCandidatesGenerated, this, _1)); + + remoteCandidateSelector = new RemoteJingleTransportCandidateSelector( + connectionFactory, + timerFactory); + remoteCandidateSelector->onCandidateSelectFinished.connect( + boost::bind(&DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished, this, _1, _2)); +} + +DefaultFileTransferTransporter::~DefaultFileTransferTransporter() { + delete remoteCandidateSelector; + 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<JingleS5BTransportPayload::Candidate>& candidates) { + s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), true); + onLocalCandidatesGenerated(s5bSessionID, candidates); +} + +void DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished( + const boost::optional<JingleS5BTransportPayload::Candidate>& candidate, + boost::shared_ptr<SOCKS5BytestreamClientSession> session) { + remoteS5BClientSession = session; + onRemoteCandidateSelectFinished(s5bSessionID, candidate); +} + + +void DefaultFileTransferTransporter::addRemoteCandidates( + const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + remoteCandidateSelector->setSOCKS5DstAddr(getSOCKS5DstAddr()); + remoteCandidateSelector->addCandidates(candidates); +} + +void DefaultFileTransferTransporter::startTryingRemoteCandidates() { + remoteCandidateSelector->startSelectingCandidate(); +} + +void DefaultFileTransferTransporter::stopTryingRemoteCandidates() { + remoteCandidateSelector->stopSelectingCandidate(); +} + +void DefaultFileTransferTransporter::startActivatingProxy(const JID&) { + // TODO + assert(false); + /* + S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); + proxyRequest->setSID(s5bSessionID); + proxyRequest->setActivate(getTarget()); + + 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)); + request->send(); + */ +} + +void DefaultFileTransferTransporter::stopActivatingProxy() { + // TODO + assert(false); +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createIBBSendSession( + const std::string& sessionID, unsigned int blockSize, boost::shared_ptr<ReadBytestream> stream) { + closeLocalSession(); + closeRemoteSession(); + boost::shared_ptr<IBBSendSession> ibbSession = boost::make_shared<IBBSendSession>( + sessionID, initiator, responder, stream, router); + ibbSession->setBlockSize(blockSize); + return boost::make_shared<IBBSendTransportSession>(ibbSession); +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createIBBReceiveSession( + const std::string& sessionID, unsigned long long size, boost::shared_ptr<WriteBytestream> stream) { + closeLocalSession(); + closeRemoteSession(); + boost::shared_ptr<IBBReceiveSession> ibbSession = boost::make_shared<IBBReceiveSession>( + sessionID, initiator, responder, size, stream, router); + return boost::make_shared<IBBReceiveTransportSession>(ibbSession); +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createRemoteCandidateSession( + boost::shared_ptr<ReadBytestream> stream) { + closeLocalSession(); + return boost::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >( + remoteS5BClientSession, stream); +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createRemoteCandidateSession( + boost::shared_ptr<WriteBytestream> stream) { + closeLocalSession(); + return boost::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >( + remoteS5BClientSession, stream); +} + +boost::shared_ptr<SOCKS5BytestreamServerSession> DefaultFileTransferTransporter::getServerSession() { + s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), false); + std::vector<boost::shared_ptr<SOCKS5BytestreamServerSession> > serverSessions = + s5bServerManager->getServer()->getSessions(getSOCKS5DstAddr()); + while (serverSessions.size() > 1) { + boost::shared_ptr<SOCKS5BytestreamServerSession> session = serverSessions.back(); + serverSessions.pop_back(); + session->stop(); + } + return !serverSessions.empty() ? serverSessions.front() : boost::shared_ptr<SOCKS5BytestreamServerSession>(); +} + + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createLocalCandidateSession( + boost::shared_ptr<ReadBytestream> stream) { + closeRemoteSession(); + boost::shared_ptr<SOCKS5BytestreamServerSession> serverSession = getServerSession(); + if (serverSession) { + return boost::make_shared<S5BTransportSession<SOCKS5BytestreamServerSession> >(serverSession, stream); + } + else { + return boost::make_shared<FailingTransportSession>(); + } +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createLocalCandidateSession( + boost::shared_ptr<WriteBytestream> stream) { + closeRemoteSession(); + boost::shared_ptr<SOCKS5BytestreamServerSession> serverSession = getServerSession(); + if (serverSession) { + return boost::make_shared<S5BTransportSession<SOCKS5BytestreamServerSession> >(serverSession, stream); + } + else { + return boost::make_shared<FailingTransportSession>(); + } +} + +std::string DefaultFileTransferTransporter::getSOCKS5DstAddr() const { + return Hexify::hexify(crypto->getSHA1Hash( + createSafeByteArray(s5bSessionID + initiator.toString() + initiator.toString()))); +} + +void DefaultFileTransferTransporter::closeLocalSession() { + s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), false); + std::vector<boost::shared_ptr<SOCKS5BytestreamServerSession> > serverSessions = + s5bServerManager->getServer()->getSessions(getSOCKS5DstAddr()); + foreach(boost::shared_ptr<SOCKS5BytestreamServerSession> session, serverSessions) { + session->stop(); + } +} + +void DefaultFileTransferTransporter::closeRemoteSession() { + if (remoteS5BClientSession) { + remoteS5BClientSession->stop(); + remoteS5BClientSession.reset(); + } +} |