diff options
Diffstat (limited to 'Swiften/FileTransfer')
87 files changed, 3227 insertions, 2362 deletions
diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.cpp b/Swiften/FileTransfer/ByteArrayReadBytestream.cpp new file mode 100644 index 0000000..4ba791f --- /dev/null +++ b/Swiften/FileTransfer/ByteArrayReadBytestream.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/ByteArrayReadBytestream.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Swiften/Base/Algorithm.h> + +using namespace Swift; + +boost::shared_ptr<ByteArray> ByteArrayReadBytestream::read(size_t size) { + size_t readSize = size; + if (position + readSize > data.size()) { + readSize = data.size() - position; + } + boost::shared_ptr<ByteArray> result = boost::make_shared<ByteArray>( + data.begin() + boost::numeric_cast<long long>(position), + data.begin() + boost::numeric_cast<long long>(position) + boost::numeric_cast<long long>(readSize)); + + onRead(*result); + position += readSize; + return result; +} + +void ByteArrayReadBytestream::addData(const std::vector<unsigned char>& moreData) { + append(data, moreData); + onDataAvailable(); +} diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.h b/Swiften/FileTransfer/ByteArrayReadBytestream.h index 9311099..664698a 100644 --- a/Swiften/FileTransfer/ByteArrayReadBytestream.h +++ b/Swiften/FileTransfer/ByteArrayReadBytestream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,9 +7,7 @@ #pragma once #include <vector> -#include <boost/smart_ptr/make_shared.hpp> -#include <Swiften/Base/Algorithm.h> #include <Swiften/FileTransfer/ReadBytestream.h> #include <Swiften/Base/ByteArray.h> @@ -19,17 +17,7 @@ namespace Swift { ByteArrayReadBytestream(const std::vector<unsigned char>& data) : data(data), position(0), dataComplete(true) { } - virtual boost::shared_ptr<ByteArray> read(size_t size) { - size_t readSize = size; - if (position + readSize > data.size()) { - readSize = data.size() - position; - } - boost::shared_ptr<ByteArray> result = boost::make_shared<ByteArray>(data.begin() + position, data.begin() + position + readSize); - - onRead(*result); - position += readSize; - return result; - } + virtual boost::shared_ptr<ByteArray> read(size_t size); virtual bool isFinished() const { return position >= data.size() && dataComplete; @@ -39,10 +27,7 @@ namespace Swift { dataComplete = b; } - void addData(const std::vector<unsigned char>& moreData) { - append(data, moreData); - onDataAvailable(); - } + void addData(const std::vector<unsigned char>& moreData); private: std::vector<unsigned char> data; diff --git a/Swiften/FileTransfer/ConnectivityManager.cpp b/Swiften/FileTransfer/ConnectivityManager.cpp deleted file mode 100644 index 7d25991..0000000 --- a/Swiften/FileTransfer/ConnectivityManager.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "ConnectivityManager.h" - -#include <boost/bind.hpp> - -#include <Swiften/Base/foreach.h> -#include <Swiften/Base/Log.h> -#include <Swiften/Network/NetworkInterface.h> -#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> -#include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> -#include <Swiften/Network/NATTraverser.h> -#include <Swiften/Network/PlatformNetworkEnvironment.h> - -namespace Swift { - -ConnectivityManager::ConnectivityManager(NATTraverser* worker) : natTraversalWorker(worker) { - -} - -ConnectivityManager::~ConnectivityManager() { - std::set<int> leftOpenPorts = ports; - foreach(int port, leftOpenPorts) { - removeListeningPort(port); - } -} - -void ConnectivityManager::addListeningPort(int port) { - ports.insert(port); - boost::shared_ptr<NATTraversalGetPublicIPRequest> getIPRequest = natTraversalWorker->createGetPublicIPRequest(); - if (getIPRequest) { - getIPRequest->onResult.connect(boost::bind(&ConnectivityManager::natTraversalGetPublicIPResult, this, _1)); - getIPRequest->run(); - } - - boost::shared_ptr<NATTraversalForwardPortRequest> forwardPortRequest = natTraversalWorker->createForwardPortRequest(port, port); - if (forwardPortRequest) { - forwardPortRequest->onResult.connect(boost::bind(&ConnectivityManager::natTraversalForwardPortResult, this, _1)); - forwardPortRequest->run(); - } -} - -void ConnectivityManager::removeListeningPort(int port) { - SWIFT_LOG(debug) << "remove listening port " << port << std::endl; - ports.erase(port); - boost::shared_ptr<NATTraversalRemovePortForwardingRequest> removePortForwardingRequest = natTraversalWorker->createRemovePortForwardingRequest(port, port); - if (removePortForwardingRequest) { - removePortForwardingRequest->run(); - } -} - -std::vector<HostAddressPort> ConnectivityManager::getHostAddressPorts() const { - PlatformNetworkEnvironment env; - std::vector<HostAddressPort> results; - - std::vector<HostAddress> addresses; - - std::vector<NetworkInterface> networkInterfaces; - foreach (const NetworkInterface& iface, networkInterfaces) { - foreach (const HostAddress& address, iface.getAddresses()) { - foreach (int port, ports) { - results.push_back(HostAddressPort(address, port)); - } - } - } - - return results; -} - -std::vector<HostAddressPort> ConnectivityManager::getAssistedHostAddressPorts() const { - std::vector<HostAddressPort> results; - - if (publicAddress) { - foreach (int port, ports) { - results.push_back(HostAddressPort(publicAddress.get(), port)); - } - } - - return results; -} - -void ConnectivityManager::natTraversalGetPublicIPResult(boost::optional<HostAddress> address) { - if (address) { - publicAddress = address; - SWIFT_LOG(debug) << "Public IP discovered as " << publicAddress.get().toString() << "." << std::endl; - } else { - SWIFT_LOG(debug) << "No public IP discoverable." << std::endl; - } -} - -void ConnectivityManager::natTraversalForwardPortResult(boost::optional<NATPortMapping> mapping) { - if (mapping) { - SWIFT_LOG(debug) << "Mapping port was successful." << std::endl; - } else { - SWIFT_LOG(debug) << "Mapping port has failed." << std::endl; - } -} - - -} diff --git a/Swiften/FileTransfer/ConnectivityManager.h b/Swiften/FileTransfer/ConnectivityManager.h deleted file mode 100644 index c094c02..0000000 --- a/Swiften/FileTransfer/ConnectivityManager.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <vector> -#include <set> - -#include <boost/optional.hpp> - -#include <Swiften/Network/HostAddressPort.h> -#include <Swiften/Network/NATTraverser.h> -#include <Swiften/Network/NATTraversalForwardPortRequest.h> -#include <Swiften/Network/NATPortMapping.h> - -namespace Swift { - -class NATTraverser; - -class ConnectivityManager { -public: - ConnectivityManager(NATTraverser*); - ~ConnectivityManager(); -public: - void addListeningPort(int port); - void removeListeningPort(int port); - - std::vector<HostAddressPort> getHostAddressPorts() const; - std::vector<HostAddressPort> getAssistedHostAddressPorts() const; - -private: - void natTraversalGetPublicIPResult(boost::optional<HostAddress> address); - void natTraversalForwardPortResult(boost::optional<NATPortMapping> mapping); - -private: - NATTraverser* natTraversalWorker; - - std::set<int> ports; - boost::optional<HostAddress> publicAddress; -}; - -} 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(); + } +} diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporter.h b/Swiften/FileTransfer/DefaultFileTransferTransporter.h new file mode 100644 index 0000000..ef982c0 --- /dev/null +++ b/Swiften/FileTransfer/DefaultFileTransferTransporter.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/FileTransfer/FileTransferTransporter.h> + +namespace Swift { + class LocalJingleTransportCandidateGenerator; + class RemoteJingleTransportCandidateSelector; + class SOCKS5BytestreamRegistry; + class SOCKS5BytestreamServerManager; + class SOCKS5BytestreamProxiesManager; + class SOCKS5BytestreamClientSession; + class SOCKS5BytestreamServerSession; + class IDGenerator; + class IQRouter; + class ReadBytestream; + class WriteBytestream; + class ConnectionFactory; + class TimerFactory; + class CryptoProvider; + + class SWIFTEN_API DefaultFileTransferTransporter : public FileTransferTransporter { + public: + enum Role { + Initiator, + Responder + }; + + DefaultFileTransferTransporter( + const JID& initiator, + const JID& responder, + Role role, + SOCKS5BytestreamRegistry*, + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + IDGenerator* idGenerator, + ConnectionFactory*, + TimerFactory*, + CryptoProvider*, + IQRouter*); + virtual ~DefaultFileTransferTransporter(); + + + virtual void initialize(); + virtual void initialize(const std::string& s5bSessionID); + + virtual void startGeneratingLocalCandidates() SWIFTEN_OVERRIDE; + virtual void stopGeneratingLocalCandidates() SWIFTEN_OVERRIDE; + + virtual void addRemoteCandidates( + const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE; + virtual void startTryingRemoteCandidates() SWIFTEN_OVERRIDE; + virtual void stopTryingRemoteCandidates() SWIFTEN_OVERRIDE; + + virtual void startActivatingProxy(const JID& jid); + virtual void stopActivatingProxy(); + + virtual boost::shared_ptr<TransportSession> createIBBSendSession( + const std::string& sessionID, unsigned int blockSize, boost::shared_ptr<ReadBytestream>) SWIFTEN_OVERRIDE; + 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; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession( + boost::shared_ptr<WriteBytestream>) SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession( + boost::shared_ptr<ReadBytestream>) SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession( + boost::shared_ptr<WriteBytestream>) 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 closeLocalSession(); + void closeRemoteSession(); + boost::shared_ptr<SOCKS5BytestreamServerSession> getServerSession(); + + private: + JID initiator; + JID responder; + Role role; + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamServerManager* s5bServerManager; + CryptoProvider* crypto; + IQRouter* router; + LocalJingleTransportCandidateGenerator* localCandidateGenerator; + RemoteJingleTransportCandidateSelector* remoteCandidateSelector; + std::string s5bSessionID; + boost::shared_ptr<SOCKS5BytestreamClientSession> remoteS5BClientSession; + }; +} + diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.cpp b/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.cpp new file mode 100644 index 0000000..4c8a55e --- /dev/null +++ b/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h> + +#include <Swiften/FileTransfer/DefaultFileTransferTransporter.h> + +using namespace Swift; + +DefaultFileTransferTransporterFactory::DefaultFileTransferTransporterFactory( + SOCKS5BytestreamRegistry* s5bRegistry, + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxiesManager, + IDGenerator* idGenerator, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + CryptoProvider* cryptoProvider, + IQRouter* iqRouter) : + s5bRegistry(s5bRegistry), + s5bServerManager(s5bServerManager), + s5bProxiesManager(s5bProxiesManager), + idGenerator(idGenerator), + connectionFactory(connectionFactory), + timerFactory(timerFactory), + cryptoProvider(cryptoProvider), + iqRouter(iqRouter) +{ +} + +DefaultFileTransferTransporterFactory::~DefaultFileTransferTransporterFactory() { +} + +FileTransferTransporter* DefaultFileTransferTransporterFactory::createInitiatorTransporter( + const JID& initiator, const JID& responder) { + DefaultFileTransferTransporter* transporter = new DefaultFileTransferTransporter( + initiator, + responder, + DefaultFileTransferTransporter::Initiator, + s5bRegistry, + s5bServerManager, + s5bProxiesManager, + idGenerator, + connectionFactory, + timerFactory, + cryptoProvider, + iqRouter); + transporter->initialize(); + return transporter; +} + +FileTransferTransporter* DefaultFileTransferTransporterFactory::createResponderTransporter( + const JID& initiator, const JID& responder, const std::string& s5bSessionID) { + DefaultFileTransferTransporter* transporter = new DefaultFileTransferTransporter( + initiator, + responder, + DefaultFileTransferTransporter::Initiator, + s5bRegistry, + s5bServerManager, + s5bProxiesManager, + idGenerator, + connectionFactory, + timerFactory, + cryptoProvider, + iqRouter); + transporter->initialize(s5bSessionID); + return transporter; +} diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h b/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h new file mode 100644 index 0000000..b5e8f95 --- /dev/null +++ b/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/FileTransfer/FileTransferTransporterFactory.h> + +namespace Swift { + class SOCKS5BytestreamRegistry; + class SOCKS5BytestreamServerManager; + class SOCKS5BytestreamProxiesManager; + class IDGenerator; + class ConnectionFactory; + class TimerFactory; + class CryptoProvider; + class IQRouter; + + class SWIFTEN_API DefaultFileTransferTransporterFactory : public FileTransferTransporterFactory { + public: + DefaultFileTransferTransporterFactory( + SOCKS5BytestreamRegistry*, + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + IDGenerator* idGenerator, + ConnectionFactory*, + TimerFactory*, + CryptoProvider*, + IQRouter*); + virtual ~DefaultFileTransferTransporterFactory(); + + virtual FileTransferTransporter* createInitiatorTransporter( + const JID& initiator, const JID& responder) SWIFTEN_OVERRIDE; + virtual FileTransferTransporter* createResponderTransporter( + const JID& initiator, const JID& responder, const std::string& s5bSessionID) SWIFTEN_OVERRIDE; + + private: + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamServerManager* s5bServerManager; + SOCKS5BytestreamProxiesManager* s5bProxiesManager; + IDGenerator* idGenerator; + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; + CryptoProvider* cryptoProvider; + IQRouter* iqRouter; + }; +} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp deleted file mode 100644 index 4b205cb..0000000 --- a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "DefaultLocalJingleTransportCandidateGenerator.h" - -#include <vector> - -#include <boost/shared_ptr.hpp> -#include <boost/smart_ptr/make_shared.hpp> - -#include <Swiften/Base/foreach.h> -#include <Swiften/Base/Log.h> -#include <Swiften/Elements/JingleIBBTransportPayload.h> -#include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/FileTransfer/ConnectivityManager.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> - -namespace Swift { - -DefaultLocalJingleTransportCandidateGenerator::DefaultLocalJingleTransportCandidateGenerator(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, JID& ownJID) : connectivityManager(connectivityManager), s5bRegistry(s5bRegistry), s5bProxy(s5bProxy), ownJID(ownJID) { -} - -DefaultLocalJingleTransportCandidateGenerator::~DefaultLocalJingleTransportCandidateGenerator() { -} - -void DefaultLocalJingleTransportCandidateGenerator::generateLocalTransportCandidates(JingleTransportPayload::ref transportPayload) { - if (boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transportPayload)) { - JingleTransportPayload::ref payL = boost::make_shared<JingleTransportPayload>(); - payL->setSessionID(transportPayload->getSessionID()); - onLocalTransportCandidatesGenerated(payL); - } - if (boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload)) { - JingleS5BTransportPayload::ref payL = boost::make_shared<JingleS5BTransportPayload>(); - payL->setSessionID(transportPayload->getSessionID()); - payL->setMode(JingleS5BTransportPayload::TCPMode); - - const unsigned long localPreference = 0; - - // get direct candidates - std::vector<HostAddressPort> directCandidates = connectivityManager->getHostAddressPorts(); - foreach(HostAddressPort addressPort, directCandidates) { - JingleS5BTransportPayload::Candidate candidate; - candidate.type = JingleS5BTransportPayload::Candidate::DirectType; - candidate.jid = ownJID; - candidate.hostPort = addressPort; - candidate.priority = 65536 * 126 + localPreference; - candidate.cid = idGenerator.generateID(); - payL->addCandidate(candidate); - } - - // get assissted candidates - std::vector<HostAddressPort> assisstedCandidates = connectivityManager->getAssistedHostAddressPorts(); - foreach(HostAddressPort addressPort, assisstedCandidates) { - JingleS5BTransportPayload::Candidate candidate; - candidate.type = JingleS5BTransportPayload::Candidate::AssistedType; - candidate.jid = ownJID; - candidate.hostPort = addressPort; - candidate.priority = 65536 * 120 + localPreference; - candidate.cid = idGenerator.generateID(); - payL->addCandidate(candidate); - } - - // get proxy candidates - std::vector<S5BProxyRequest::ref> proxyCandidates = s5bProxy->getS5BProxies(); - foreach(S5BProxyRequest::ref proxy, proxyCandidates) { - if (proxy->getStreamHost()) { // FIXME: Added this test, because there were cases where this wasn't initialized. Investigate this. (Remko) - JingleS5BTransportPayload::Candidate candidate; - candidate.type = JingleS5BTransportPayload::Candidate::ProxyType; - candidate.jid = (*proxy->getStreamHost()).jid; - candidate.hostPort = (*proxy->getStreamHost()).addressPort; - candidate.priority = 65536 * 10 + localPreference; - candidate.cid = idGenerator.generateID(); - payL->addCandidate(candidate); - } - } - - onLocalTransportCandidatesGenerated(payL); - } - -} - -bool DefaultLocalJingleTransportCandidateGenerator::isActualCandidate(JingleTransportPayload::ref transportPayload) { - if (!transportPayload.get()) return false; - return false; -} - -int DefaultLocalJingleTransportCandidateGenerator::getPriority(JingleTransportPayload::ref /* transportPayload */) { - return 0; -} - -JingleTransport::ref DefaultLocalJingleTransportCandidateGenerator::selectTransport(JingleTransportPayload::ref /* transportPayload */) { - return JingleTransport::ref(); -} - -} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h deleted file mode 100644 index 7d45491..0000000 --- a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> - -#include <Swiften/Base/IDGenerator.h> -#include <Swiften/JID/JID.h> - -namespace Swift { - -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; -class ConnectivityManager; - -class DefaultLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { -public: - DefaultLocalJingleTransportCandidateGenerator(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, JID& ownJID); - virtual ~DefaultLocalJingleTransportCandidateGenerator(); - - virtual void generateLocalTransportCandidates(JingleTransportPayload::ref); - - virtual bool isActualCandidate(JingleTransportPayload::ref); - virtual int getPriority(JingleTransportPayload::ref); - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref); - -private: - IDGenerator idGenerator; - ConnectivityManager* connectivityManager; - SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; - JID ownJID; -}; - -} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp deleted file mode 100644 index ed0386e..0000000 --- a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "DefaultLocalJingleTransportCandidateGeneratorFactory.h" - -#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h> -#include <Swiften/Base/Log.h> - -namespace Swift { - -DefaultLocalJingleTransportCandidateGeneratorFactory::DefaultLocalJingleTransportCandidateGeneratorFactory(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, const JID& ownJID) : connectivityManager(connectivityManager), s5bRegistry(s5bRegistry), s5bProxy(s5bProxy), ownJID(ownJID) { -} - -DefaultLocalJingleTransportCandidateGeneratorFactory::~DefaultLocalJingleTransportCandidateGeneratorFactory() { -} - -LocalJingleTransportCandidateGenerator* DefaultLocalJingleTransportCandidateGeneratorFactory::createCandidateGenerator() { - return new DefaultLocalJingleTransportCandidateGenerator(connectivityManager, s5bRegistry, s5bProxy, ownJID); -} - - -} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h deleted file mode 100644 index 511d0a1..0000000 --- a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> - -#include <Swiften/JID/JID.h> - -namespace Swift { - -class ConnectivityManager; -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; - -class DefaultLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory{ -public: - DefaultLocalJingleTransportCandidateGeneratorFactory(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, const JID& ownJID); - virtual ~DefaultLocalJingleTransportCandidateGeneratorFactory(); - - LocalJingleTransportCandidateGenerator* createCandidateGenerator(); - -private: - ConnectivityManager* connectivityManager; - SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; - JID ownJID; -}; - -} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp deleted file mode 100644 index 32b4df8..0000000 --- a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "DefaultRemoteJingleTransportCandidateSelector.h" - -#include <boost/smart_ptr/make_shared.hpp> -#include <boost/bind.hpp> - -#include <Swiften/Base/Log.h> -#include <Swiften/Base/boost_bsignals.h> -#include <Swiften/Base/foreach.h> -#include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/Network/ConnectionFactory.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> - -namespace Swift { - -DefaultRemoteJingleTransportCandidateSelector::DefaultRemoteJingleTransportCandidateSelector(ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : connectionFactory(connectionFactory), timerFactory(timerFactory) { -} - -DefaultRemoteJingleTransportCandidateSelector::~DefaultRemoteJingleTransportCandidateSelector() { -} - -void DefaultRemoteJingleTransportCandidateSelector::addRemoteTransportCandidates(JingleTransportPayload::ref transportPayload) { - JingleS5BTransportPayload::ref s5bPayload; - transportSID = transportPayload->getSessionID(); - if ((s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload))) { - foreach(JingleS5BTransportPayload::Candidate c, s5bPayload->getCandidates()) { - candidates.push(c); - } - } -} - -void DefaultRemoteJingleTransportCandidateSelector::selectCandidate() { - tryNextCandidate(true); -} - -void DefaultRemoteJingleTransportCandidateSelector::tryNextCandidate(bool error) { - if (error) { - if (s5bSession) { - SWIFT_LOG(debug) << "failed to connect" << std::endl; - } - if (candidates.empty()) { - // failed to connect to any of the candidates - // issue an error - SWIFT_LOG(debug) << "out of candidates )=" << std::endl; - JingleS5BTransportPayload::ref failed = boost::make_shared<JingleS5BTransportPayload>(); - failed->setCandidateError(true); - failed->setSessionID(transportSID); - onRemoteTransportCandidateSelectFinished(failed); - } else { - lastCandidate = candidates.top(); - // only try direct or assisted for now - if (lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType || - lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType || lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType ) { - // create connection - connection = connectionFactory->createConnection(); - s5bSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, lastCandidate.hostPort, SOCKS5BytestreamRegistry::getHostname(transportSID, requester, target), timerFactory); - - // bind onReady to this method - s5bSession->onSessionReady.connect(boost::bind(&DefaultRemoteJingleTransportCandidateSelector::tryNextCandidate, this, _1)); - - std::string candidateType; - if (lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType) { - candidateType = "direct"; - } else if (lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType) { - candidateType = "assisted"; - } else if (lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { - candidateType = "proxy"; - } - - // initiate connect - SWIFT_LOG(debug) << "try to connect to candidate of type " << candidateType << " : " << lastCandidate.hostPort.toString() << std::endl; - s5bSession->start(); - - // that's it. we're gonna be called back - candidates.pop(); - } else { - s5bSession.reset(); - candidates.pop(); - tryNextCandidate(true); - } - } - } else { - // we have a working connection, hooray - JingleS5BTransportPayload::ref success = boost::make_shared<JingleS5BTransportPayload>(); - success->setCandidateUsed(lastCandidate.cid); - success->setSessionID(transportSID); - onRemoteTransportCandidateSelectFinished(success); - } -} - -void DefaultRemoteJingleTransportCandidateSelector::setMinimumPriority(int priority) { - SWIFT_LOG(debug) << "priority: " << priority << std::endl; -} - -void DefaultRemoteJingleTransportCandidateSelector::setRequesterTargtet(const JID& requester, const JID& target) { - this->requester = requester; - this->target = target; -} - -SOCKS5BytestreamClientSession::ref DefaultRemoteJingleTransportCandidateSelector::getS5BSession() { - return s5bSession; -} - -bool DefaultRemoteJingleTransportCandidateSelector::isActualCandidate(JingleTransportPayload::ref /* transportPayload */) { - return false; -} - -int DefaultRemoteJingleTransportCandidateSelector::getPriority(JingleTransportPayload::ref /* transportPayload */) { - return 0; -} - -JingleTransport::ref DefaultRemoteJingleTransportCandidateSelector::selectTransport(JingleTransportPayload::ref /* transportPayload */) { - return JingleTransport::ref(); -} - -} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h deleted file mode 100644 index 255acd9..0000000 --- a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <queue> -#include <vector> - -#include <boost/shared_ptr.hpp> - -#include <Swiften/JID/JID.h> -#include <Swiften/Network/Connection.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -#include <Swiften/Elements/JingleS5BTransportPayload.h> - - -namespace Swift { - -class ConnectionFactory; -class TimerFactory; - -class DefaultRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector { -public: - DefaultRemoteJingleTransportCandidateSelector(ConnectionFactory*, TimerFactory*); - virtual ~DefaultRemoteJingleTransportCandidateSelector(); - - virtual void addRemoteTransportCandidates(JingleTransportPayload::ref); - virtual void selectCandidate(); - virtual void setMinimumPriority(int); - void setRequesterTargtet(const JID& requester, const JID& target); - virtual SOCKS5BytestreamClientSession::ref getS5BSession(); - - virtual bool isActualCandidate(JingleTransportPayload::ref); - virtual int getPriority(JingleTransportPayload::ref); - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref); - -private: - void tryNextCandidate(bool error); - -private: - ConnectionFactory* connectionFactory; - TimerFactory* timerFactory; - - std::priority_queue<JingleS5BTransportPayload::Candidate, std::vector<JingleS5BTransportPayload::Candidate>, JingleS5BTransportPayload::CompareCandidate> candidates; - - std::string transportSID; - boost::shared_ptr<Connection> connection; - boost::shared_ptr<SOCKS5BytestreamClientSession> s5bSession; - JingleS5BTransportPayload::Candidate lastCandidate; - JID requester; - JID target; -}; - -} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp deleted file mode 100644 index 8ebbf46..0000000 --- a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "DefaultRemoteJingleTransportCandidateSelectorFactory.h" - -#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h> - -#include <Swiften/Base/Log.h> - -namespace Swift { - -DefaultRemoteJingleTransportCandidateSelectorFactory::DefaultRemoteJingleTransportCandidateSelectorFactory(ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : connectionFactory(connectionFactory), timerFactory(timerFactory) { -} - -DefaultRemoteJingleTransportCandidateSelectorFactory::~DefaultRemoteJingleTransportCandidateSelectorFactory() { -} - -RemoteJingleTransportCandidateSelector* DefaultRemoteJingleTransportCandidateSelectorFactory::createCandidateSelector() { - return new DefaultRemoteJingleTransportCandidateSelector(connectionFactory, timerFactory); -} - -} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h deleted file mode 100644 index ca29e1f..0000000 --- a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> - -namespace Swift { - -class ConnectionFactory; -class TimerFactory; - -class DefaultRemoteJingleTransportCandidateSelectorFactory : public RemoteJingleTransportCandidateSelectorFactory { -public: - DefaultRemoteJingleTransportCandidateSelectorFactory(ConnectionFactory*, TimerFactory*); - virtual ~DefaultRemoteJingleTransportCandidateSelectorFactory(); - - RemoteJingleTransportCandidateSelector* createCandidateSelector(); - -private: - ConnectionFactory* connectionFactory; - TimerFactory* timerFactory; -}; - -} diff --git a/Swiften/FileTransfer/FileReadBytestream.cpp b/Swiften/FileTransfer/FileReadBytestream.cpp index a8946a0..4257f8b 100644 --- a/Swiften/FileTransfer/FileReadBytestream.cpp +++ b/Swiften/FileTransfer/FileReadBytestream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,7 @@ #include <boost/filesystem/fstream.hpp> #include <cassert> #include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/FileTransfer/FileReadBytestream.h> #include <Swiften/Base/ByteArray.h> @@ -30,8 +31,8 @@ boost::shared_ptr<ByteArray> FileReadBytestream::read(size_t size) { boost::shared_ptr<ByteArray> result = boost::make_shared<ByteArray>(); result->resize(size); assert(stream->good()); - stream->read(reinterpret_cast<char*>(vecptr(*result)), size); - result->resize(stream->gcount()); + stream->read(reinterpret_cast<char*>(vecptr(*result)), boost::numeric_cast<std::streamsize>(size)); + result->resize(boost::numeric_cast<size_t>(stream->gcount())); onRead(*result); return result; } diff --git a/Swiften/FileTransfer/FileTransfer.cpp b/Swiften/FileTransfer/FileTransfer.cpp new file mode 100644 index 0000000..c11e8e4 --- /dev/null +++ b/Swiften/FileTransfer/FileTransfer.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/FileTransfer.h> + +using namespace Swift; + +FileTransfer::FileTransfer() { +} + +FileTransfer::~FileTransfer() { +} + +void FileTransfer::setFileInfo(const std::string& name, boost::uintmax_t size) { + filename = name; + fileSizeInBytes = size; +} diff --git a/Swiften/FileTransfer/FileTransfer.h b/Swiften/FileTransfer/FileTransfer.h index 336c51c..c01aadb 100644 --- a/Swiften/FileTransfer/FileTransfer.h +++ b/Swiften/FileTransfer/FileTransfer.h @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once #include <boost/cstdint.hpp> @@ -14,46 +20,51 @@ #include <Swiften/FileTransfer/FileTransferError.h> namespace Swift { + class FileTransfer { + public: + struct State { + enum Type { + Initial, + WaitingForStart, + Negotiating, + WaitingForAccept, + Transferring, + Canceled, + Failed, + Finished + }; -class FileTransfer { -public: - struct State { - enum FTState { - Canceled, - Failed, - Finished, - Negotiating, - Transferring, - WaitingForStart, - WaitingForAccept, - }; - - FTState state; - std::string message; - - State(FTState state) : state(state), message("") {} - State(FTState state, std::string message) : state(state), message(message) {} - }; + State(Type type, const std::string& message = "") : type(type), message(message) {} -public: - typedef boost::shared_ptr<FileTransfer> ref; + Type type; + std::string message; + }; + typedef boost::shared_ptr<FileTransfer> ref; -public: - boost::uintmax_t fileSizeInBytes; - std::string filename; - std::string algo; - std::string hash; + public: + FileTransfer(); + virtual ~FileTransfer(); -public: - virtual void cancel() = 0; + virtual void cancel() = 0; -public: - boost::signal<void (int /* proccessedBytes */)> onProcessedBytes; - boost::signal<void (State)> onStateChange; - boost::signal<void (boost::optional<FileTransferError>)> onFinished; + const std::string& getFileName() const { + return filename; + } -public: - virtual ~FileTransfer() {} -}; + boost::uintmax_t getFileSizeInBytes() const { + return fileSizeInBytes; + } + public: + boost::signal<void (size_t /* proccessedBytes */)> onProcessedBytes; + boost::signal<void (const State&)> onStateChanged; + boost::signal<void (boost::optional<FileTransferError>)> onFinished; + + protected: + void setFileInfo(const std::string& name, boost::uintmax_t size); + + private: + boost::uintmax_t fileSizeInBytes; + std::string filename; + }; } diff --git a/Swiften/FileTransfer/FileTransferError.h b/Swiften/FileTransfer/FileTransferError.h index 6a6b454..eb1e8f8 100644 --- a/Swiften/FileTransfer/FileTransferError.h +++ b/Swiften/FileTransfer/FileTransferError.h @@ -13,7 +13,7 @@ namespace Swift { UnknownError, PeerError, ReadError, - ClosedError, + ClosedError }; FileTransferError(Type type = UnknownError) : type(type) {} diff --git a/Swiften/FileTransfer/FileTransferManager.h b/Swiften/FileTransfer/FileTransferManager.h index 30d9faf..3b793c5 100644 --- a/Swiften/FileTransfer/FileTransferManager.h +++ b/Swiften/FileTransfer/FileTransferManager.h @@ -4,30 +4,46 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once #include <string> -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/JID/JID.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> #include <Swiften/FileTransfer/OutgoingFileTransfer.h> #include <Swiften/FileTransfer/IncomingFileTransfer.h> namespace Swift { class ReadBytestream; - class S5BProxyRequest; class SWIFTEN_API FileTransferManager { public: virtual ~FileTransferManager(); - virtual void startListeningOnPort(int port) = 0; - - virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream) = 0; - virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream) = 0; + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID& to, + const boost::filesystem::path& filepath, + const std::string& description, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions& = FileTransferOptions()) = 0; + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID& to, + const std::string& filename, + const std::string& description, + const boost::uintmax_t sizeInBytes, + const boost::posix_time::ptime& lastModified, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions& = FileTransferOptions()) = 0; boost::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer; }; diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp index 84b2061..b832d7e 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.cpp +++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp @@ -4,24 +4,30 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <Swiften/FileTransfer/FileTransferManagerImpl.h> #include <boost/bind.hpp> +#include <boost/filesystem.hpp> #include <boost/cstdint.hpp> #include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Base/Path.h> #include "Swiften/Disco/EntityCapsProvider.h" #include <Swiften/JID/JID.h> #include <Swiften/Elements/StreamInitiationFileInfo.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> -#include <Swiften/FileTransfer/ConnectivityManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> #include <Swiften/FileTransfer/OutgoingFileTransferManager.h> #include <Swiften/FileTransfer/IncomingFileTransferManager.h> -#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <Swiften/Presence/PresenceOracle.h> #include <Swiften/Elements/Presence.h> #include <Swiften/Network/ConnectionFactory.h> @@ -33,52 +39,64 @@ namespace Swift { -FileTransferManagerImpl::FileTransferManagerImpl(const JID& ownFullJID, JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, PresenceOracle* presOracle, ConnectionFactory* connectionFactory, ConnectionServerFactory* connectionServerFactory, TimerFactory* timerFactory, NATTraverser* natTraverser) : ownJID(ownFullJID), jingleSM(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), presenceOracle(presOracle), connectionServerFactory(connectionServerFactory), bytestreamServer(NULL), s5bProxyFinder(NULL) { +FileTransferManagerImpl::FileTransferManagerImpl( + const JID& ownFullJID, + JingleSessionManager* jingleSessionManager, + IQRouter* router, + EntityCapsProvider* capsProvider, + PresenceOracle* presOracle, + ConnectionFactory* connectionFactory, + ConnectionServerFactory* connectionServerFactory, + TimerFactory* timerFactory, + NetworkEnvironment* networkEnvironment, + NATTraverser* natTraverser, + CryptoProvider* crypto) : + ownJID(ownFullJID), + iqRouter(router), + capsProvider(capsProvider), + presenceOracle(presOracle) { assert(!ownFullJID.isBare()); - connectivityManager = new ConnectivityManager(natTraverser); bytestreamRegistry = new SOCKS5BytestreamRegistry(); - bytestreamProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); - - localCandidateGeneratorFactory = new DefaultLocalJingleTransportCandidateGeneratorFactory(connectivityManager, bytestreamRegistry, bytestreamProxy, ownFullJID); - remoteCandidateSelectorFactory = new DefaultRemoteJingleTransportCandidateSelectorFactory(connectionFactory, timerFactory); - outgoingFTManager = new OutgoingFileTransferManager(jingleSM, iqRouter, capsProvider, remoteCandidateSelectorFactory, localCandidateGeneratorFactory, bytestreamRegistry, bytestreamProxy); - incomingFTManager = new IncomingFileTransferManager(jingleSM, iqRouter, remoteCandidateSelectorFactory, localCandidateGeneratorFactory, bytestreamRegistry, bytestreamProxy, timerFactory); + s5bServerManager = new SOCKS5BytestreamServerManager( + bytestreamRegistry, connectionServerFactory, networkEnvironment, natTraverser); + bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); + + transporterFactory = new DefaultFileTransferTransporterFactory( + bytestreamRegistry, + s5bServerManager, + bytestreamProxy, + &idGenerator, + connectionFactory, + timerFactory, + crypto, + iqRouter); + outgoingFTManager = new OutgoingFileTransferManager( + jingleSessionManager, + iqRouter, + transporterFactory, + crypto); + incomingFTManager = new IncomingFileTransferManager( + jingleSessionManager, + iqRouter, + transporterFactory, + timerFactory, + crypto); incomingFTManager->onIncomingFileTransfer.connect(onIncomingFileTransfer); } FileTransferManagerImpl::~FileTransferManagerImpl() { - if (s5bProxyFinder) { - s5bProxyFinder->stop(); - delete s5bProxyFinder; - } - if (bytestreamServer) { - bytestreamServer->stop(); - delete bytestreamServer; - } + delete s5bServerManager; delete incomingFTManager; delete outgoingFTManager; - delete remoteCandidateSelectorFactory; - delete localCandidateGeneratorFactory; - delete connectivityManager; + delete transporterFactory; } -void FileTransferManagerImpl::startListeningOnPort(int port) { - // TODO: create a server for each interface we're on - SWIFT_LOG(debug) << "Start listening on port " << port << " and hope it's not in use." << std::endl; - boost::shared_ptr<ConnectionServer> server = connectionServerFactory->createConnectionServer(HostAddress("0.0.0.0"), port); - server->start(); - bytestreamServer = new SOCKS5BytestreamServer(server, bytestreamRegistry); - bytestreamServer->start(); - connectivityManager->addListeningPort(port); - - s5bProxyFinder = new SOCKS5BytestreamProxyFinder(ownJID.getDomain(), iqRouter); - s5bProxyFinder->onProxyFound.connect(boost::bind(&FileTransferManagerImpl::addS5BProxy, this, _1)); - s5bProxyFinder->start(); +void FileTransferManagerImpl::start() { } -void FileTransferManagerImpl::addS5BProxy(S5BProxyRequest::ref proxy) { - bytestreamProxy->addS5BProxy(proxy); +void FileTransferManagerImpl::stop() { + s5bServerManager->stop(); } boost::optional<JID> FileTransferManagerImpl::highestPriorityJIDSupportingFileTransfer(const JID& bareJID) { @@ -104,19 +122,31 @@ boost::optional<JID> FileTransferManagerImpl::highestPriorityJIDSupportingFileTr return fullReceipientJID.isValid() ? boost::optional<JID>(fullReceipientJID) : boost::optional<JID>(); } -OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream) { +OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer( + const JID& to, + const boost::filesystem::path& filepath, + const std::string& description, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions& config) { #if BOOST_FILESYSTEM_VERSION == 2 // TODO: Delete this when boost 1.44 becomes a minimum requirement, and we no longer need v2 std::string filename = filepath.filename(); #else - std::string filename = filepath.filename().string(); + std::string filename = pathToString(filepath.filename()); #endif boost::uintmax_t sizeInBytes = boost::filesystem::file_size(filepath); boost::posix_time::ptime lastModified = boost::posix_time::from_time_t(boost::filesystem::last_write_time(filepath)); - return createOutgoingFileTransfer(to, filename, description, sizeInBytes, lastModified, bytestream); + return createOutgoingFileTransfer(to, filename, description, sizeInBytes, lastModified, bytestream, config); } -OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream) { +OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer( + const JID& to, + const std::string& filename, + const std::string& description, + const boost::uintmax_t sizeInBytes, + const boost::posix_time::ptime& lastModified, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions& config) { StreamInitiationFileInfo fileInfo; fileInfo.setDate(lastModified); fileInfo.setSize(sizeInBytes); @@ -134,7 +164,7 @@ OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(co } } - return outgoingFTManager->createOutgoingFileTransfer(ownJID, receipient, bytestream, fileInfo); + return outgoingFTManager->createOutgoingFileTransfer(ownJID, receipient, bytestream, fileInfo, config); } } diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.h b/Swiften/FileTransfer/FileTransferManagerImpl.h index ecc692d..addbbd7 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.h +++ b/Swiften/FileTransfer/FileTransferManagerImpl.h @@ -4,53 +4,84 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once #include <vector> #include <string> -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/optional.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> #include <Swiften/FileTransfer/FileTransferManager.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/IDGenerator.h> #include <Swiften/JID/JID.h> #include <Swiften/FileTransfer/OutgoingFileTransfer.h> #include <Swiften/FileTransfer/IncomingFileTransfer.h> #include <Swiften/Elements/S5BProxyRequest.h> namespace Swift { - class Client; class ConnectionFactory; class ConnectionServerFactory; - class ConnectivityManager; + class SOCKS5BytestreamServerManager; class EntityCapsProvider; class IQRouter; class IncomingFileTransferManager; class JingleSessionManager; - class LocalJingleTransportCandidateGeneratorFactory; class OutgoingFileTransferManager; class NATTraverser; class PresenceOracle; class ReadBytestream; - class RemoteJingleTransportCandidateSelectorFactory; + class FileTransferTransporterFactory; class SOCKS5BytestreamRegistry; - class SOCKS5BytestreamServer; - class SOCKS5BytestreamProxy; + class SOCKS5BytestreamProxiesManager; class TimerFactory; - class SOCKS5BytestreamProxyFinder; + class CryptoProvider; + class NetworkEnvironment; - class FileTransferManagerImpl : public FileTransferManager { + class SWIFTEN_API FileTransferManagerImpl : public FileTransferManager { public: - FileTransferManagerImpl(const JID& ownFullJID, JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, PresenceOracle* presOracle, ConnectionFactory* connectionFactory, ConnectionServerFactory* connectionServerFactory, TimerFactory* timerFactory, NATTraverser* natTraverser); + FileTransferManagerImpl( + const JID& ownFullJID, + JingleSessionManager* jingleSessionManager, + IQRouter* router, + EntityCapsProvider* capsProvider, + PresenceOracle* presOracle, + ConnectionFactory* connectionFactory, + ConnectionServerFactory* connectionServerFactory, + TimerFactory* timerFactory, + NetworkEnvironment* networkEnvironment, + NATTraverser* natTraverser, + CryptoProvider* crypto); ~FileTransferManagerImpl(); - void startListeningOnPort(int port); - void addS5BProxy(S5BProxyRequest::ref proxy); + OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID& to, + const boost::filesystem::path& filepath, + const std::string& description, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions&) SWIFTEN_OVERRIDE; + OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID& to, + const std::string& filename, + const std::string& description, + const boost::uintmax_t sizeInBytes, + const boost::posix_time::ptime& lastModified, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions&) SWIFTEN_OVERRIDE; - OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream); - OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream); + void start(); + void stop(); private: boost::optional<JID> highestPriorityJIDSupportingFileTransfer(const JID& bareJID); @@ -60,19 +91,13 @@ namespace Swift { OutgoingFileTransferManager* outgoingFTManager; IncomingFileTransferManager* incomingFTManager; - RemoteJingleTransportCandidateSelectorFactory* remoteCandidateSelectorFactory; - LocalJingleTransportCandidateGeneratorFactory* localCandidateGeneratorFactory; - JingleSessionManager* jingleSM; + FileTransferTransporterFactory* transporterFactory; IQRouter* iqRouter; EntityCapsProvider* capsProvider; PresenceOracle* presenceOracle; - - ConnectionServerFactory* connectionServerFactory; + IDGenerator idGenerator; SOCKS5BytestreamRegistry* bytestreamRegistry; - SOCKS5BytestreamServer* bytestreamServer; - SOCKS5BytestreamProxy* bytestreamProxy; - ConnectivityManager* connectivityManager; - SOCKS5BytestreamProxyFinder* s5bProxyFinder; + SOCKS5BytestreamProxiesManager* bytestreamProxy; + SOCKS5BytestreamServerManager* s5bServerManager; }; - } diff --git a/Swiften/FileTransfer/FileTransferOptions.cpp b/Swiften/FileTransfer/FileTransferOptions.cpp new file mode 100644 index 0000000..af816ec --- /dev/null +++ b/Swiften/FileTransfer/FileTransferOptions.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/FileTransferOptions.h> + +using namespace Swift; + +FileTransferOptions::~FileTransferOptions() { +} diff --git a/Swiften/FileTransfer/FileTransferOptions.h b/Swiften/FileTransfer/FileTransferOptions.h new file mode 100644 index 0000000..304ced8 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferOptions.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> + +namespace Swift { + class SWIFTEN_API FileTransferOptions { + public: + FileTransferOptions() : allowInBand(false) { + } + + ~FileTransferOptions(); + + FileTransferOptions& withInBandAllowed(bool b) { + allowInBand = b; + return *this; + } + + bool isInBandAllowed() const { + return allowInBand; + } + + private: + bool allowInBand; + }; +} diff --git a/Swiften/FileTransfer/FileTransferTransporter.cpp b/Swiften/FileTransfer/FileTransferTransporter.cpp new file mode 100644 index 0000000..30966c4 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferTransporter.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/FileTransferTransporter.h> + +using namespace Swift; + +FileTransferTransporter::~FileTransferTransporter() { +} diff --git a/Swiften/FileTransfer/FileTransferTransporter.h b/Swiften/FileTransfer/FileTransferTransporter.h new file mode 100644 index 0000000..b7b7090 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferTransporter.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <vector> + +#include <boost/optional/optional_fwd.hpp> + +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class TransportSession; + class ErrorPayload; + class ReadBytestream; + class WriteBytestream; + + class SWIFTEN_API FileTransferTransporter { + public: + virtual ~FileTransferTransporter(); + + virtual void startGeneratingLocalCandidates() = 0; + virtual void stopGeneratingLocalCandidates() = 0; + + virtual void addRemoteCandidates( + const std::vector<JingleS5BTransportPayload::Candidate>&) = 0; + virtual void startTryingRemoteCandidates() = 0; + virtual void stopTryingRemoteCandidates() = 0; + + virtual void startActivatingProxy(const JID& proxy) = 0; + virtual void stopActivatingProxy() = 0; + + virtual boost::shared_ptr<TransportSession> createIBBSendSession( + const std::string& sessionID, unsigned int blockSize, boost::shared_ptr<ReadBytestream>) = 0; + 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; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession( + boost::shared_ptr<WriteBytestream>) = 0; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession( + boost::shared_ptr<ReadBytestream>) = 0; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession( + boost::shared_ptr<WriteBytestream>) = 0; + + boost::signal<void (const std::string& /* sessionID */, const std::vector<JingleS5BTransportPayload::Candidate>&)> 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/FileTransferTransporterFactory.cpp b/Swiften/FileTransfer/FileTransferTransporterFactory.cpp new file mode 100644 index 0000000..0acc016 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferTransporterFactory.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/FileTransferTransporterFactory.h> + +using namespace Swift; + +FileTransferTransporterFactory::~FileTransferTransporterFactory() { +} diff --git a/Swiften/FileTransfer/FileTransferTransporterFactory.h b/Swiften/FileTransfer/FileTransferTransporterFactory.h new file mode 100644 index 0000000..f7f9acc --- /dev/null +++ b/Swiften/FileTransfer/FileTransferTransporterFactory.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <string> + +#include <Swiften/Base/API.h> + +namespace Swift { + class JID; + class FileTransferTransporter; + + class SWIFTEN_API FileTransferTransporterFactory { + public: + virtual ~FileTransferTransporterFactory(); + + virtual FileTransferTransporter* createInitiatorTransporter( + const JID& initiator, + const JID& responder) = 0; + virtual FileTransferTransporter* createResponderTransporter( + const JID& initiator, + const JID& responder, + const std::string& s5bSessionID) = 0; + }; +} diff --git a/Swiften/FileTransfer/FileWriteBytestream.cpp b/Swiften/FileTransfer/FileWriteBytestream.cpp index 6a22c6a..6c11eb0 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.cpp +++ b/Swiften/FileTransfer/FileWriteBytestream.cpp @@ -1,11 +1,12 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <boost/filesystem/fstream.hpp> #include <cassert> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/FileTransfer/FileWriteBytestream.h> @@ -22,11 +23,14 @@ FileWriteBytestream::~FileWriteBytestream() { } void FileWriteBytestream::write(const std::vector<unsigned char>& data) { + if (data.empty()) { + return; + } if (!stream) { stream = new boost::filesystem::ofstream(file, std::ios_base::out|std::ios_base::binary); } assert(stream->good()); - stream->write(reinterpret_cast<const char*>(&data[0]), data.size()); + stream->write(reinterpret_cast<const char*>(&data[0]), boost::numeric_cast<std::streamsize>(data.size())); onWrite(data); } diff --git a/Swiften/FileTransfer/IBBReceiveSession.cpp b/Swiften/FileTransfer/IBBReceiveSession.cpp index 1a2bb3a..3aa6fdc 100644 --- a/Swiften/FileTransfer/IBBReceiveSession.cpp +++ b/Swiften/FileTransfer/IBBReceiveSession.cpp @@ -27,7 +27,7 @@ class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { if (from == session->from && ibb->getStreamID() == session->id) { if (ibb->getAction() == IBB::Data) { if (sequenceNumber == ibb->getSequenceNumber()) { - session->onDataReceived(ibb->getData()); + session->bytestream->write(ibb->getData()); receivedSize += ibb->getData().size(); sequenceNumber++; sendResponse(from, id, IBB::ref()); @@ -62,7 +62,7 @@ class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { private: IBBReceiveSession* session; int sequenceNumber; - size_t receivedSize; + unsigned long long receivedSize; }; @@ -70,12 +70,14 @@ IBBReceiveSession::IBBReceiveSession( const std::string& id, const JID& from, const JID& to, - size_t size, + unsigned long long size, + boost::shared_ptr<WriteBytestream> bytestream, IQRouter* router) : id(id), from(from), to(to), size(size), + bytestream(bytestream), router(router), active(false) { assert(!id.empty()); diff --git a/Swiften/FileTransfer/IBBReceiveSession.h b/Swiften/FileTransfer/IBBReceiveSession.h index f075fe2..23d9648 100644 --- a/Swiften/FileTransfer/IBBReceiveSession.h +++ b/Swiften/FileTransfer/IBBReceiveSession.h @@ -25,7 +25,8 @@ namespace Swift { const std::string& id, const JID& from, const JID& to, - size_t size, + unsigned long long size, + boost::shared_ptr<WriteBytestream> bytestream, IQRouter* router); ~IBBReceiveSession(); @@ -40,7 +41,6 @@ namespace Swift { return to; } - boost::signal<void (const std::vector<unsigned char>&)> onDataReceived; boost::signal<void (boost::optional<FileTransferError>)> onFinished; private: @@ -54,7 +54,8 @@ namespace Swift { std::string id; JID from; JID to; - size_t size; + unsigned long long size; + boost::shared_ptr<WriteBytestream> bytestream; IQRouter* router; IBBResponder* responder; bool active; diff --git a/Swiften/FileTransfer/IBBSendSession.cpp b/Swiften/FileTransfer/IBBSendSession.cpp index c24cc0a..d8b7c7b 100644 --- a/Swiften/FileTransfer/IBBSendSession.cpp +++ b/Swiften/FileTransfer/IBBSendSession.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,7 @@ #include <Swiften/FileTransfer/IBBSendSession.h> #include <boost/bind.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/ByteArray.h> #include <Swiften/Queries/IQRouter.h> @@ -15,7 +16,21 @@ namespace Swift { -IBBSendSession::IBBSendSession(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* router) : id(id), from(from), to(to), bytestream(bytestream), router(router), blockSize(4096), sequenceNumber(0), active(false), waitingForData(false) { +IBBSendSession::IBBSendSession( + const std::string& id, + const JID& from, + const JID& to, + boost::shared_ptr<ReadBytestream> bytestream, + IQRouter* router) : + id(id), + from(from), + to(to), + bytestream(bytestream), + router(router), + blockSize(4096), + sequenceNumber(0), + active(false), + waitingForData(false) { bytestream->onDataAvailable.connect(boost::bind(&IBBSendSession::handleDataAvailable, this)); } @@ -24,7 +39,8 @@ IBBSendSession::~IBBSendSession() { } void IBBSendSession::start() { - IBBRequest::ref request = IBBRequest::create(from, to, IBB::createIBBOpen(id, blockSize), router); + IBBRequest::ref request = IBBRequest::create( + from, to, IBB::createIBBOpen(id, boost::numeric_cast<int>(blockSize)), router); request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); active = true; request->send(); diff --git a/Swiften/FileTransfer/IBBSendSession.h b/Swiften/FileTransfer/IBBSendSession.h index a535382..f6ba7b3 100644 --- a/Swiften/FileTransfer/IBBSendSession.h +++ b/Swiften/FileTransfer/IBBSendSession.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -22,7 +22,12 @@ namespace Swift { class SWIFTEN_API IBBSendSession { public: - IBBSendSession(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* router); + IBBSendSession( + const std::string& id, + const JID& from, + const JID& to, + boost::shared_ptr<ReadBytestream> bytestream, + IQRouter* router); ~IBBSendSession(); void start(); @@ -36,12 +41,12 @@ namespace Swift { return to; } - void setBlockSize(int blockSize) { + void setBlockSize(unsigned int blockSize) { this->blockSize = blockSize; } boost::signal<void (boost::optional<FileTransferError>)> onFinished; - boost::signal<void (int)> onBytesSent; + boost::signal<void (size_t)> onBytesSent; private: void handleIBBResponse(IBB::ref, ErrorPayload::ref); @@ -55,7 +60,7 @@ namespace Swift { JID to; boost::shared_ptr<ReadBytestream> bytestream; IQRouter* router; - int blockSize; + unsigned int blockSize; int sequenceNumber; bool active; bool waitingForData; diff --git a/Swiften/FileTransfer/IncomingFileTransfer.h b/Swiften/FileTransfer/IncomingFileTransfer.h index 5b53d54..698a588 100644 --- a/Swiften/FileTransfer/IncomingFileTransfer.h +++ b/Swiften/FileTransfer/IncomingFileTransfer.h @@ -9,18 +9,22 @@ #include <boost/shared_ptr.hpp> #include <Swiften/Base/boost_bsignals.h> -#include <Swiften/JID/JID.h> #include <Swiften/FileTransfer/FileTransfer.h> -#include <Swiften/FileTransfer/WriteBytestream.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> namespace Swift { + class WriteBytestream; + class JID; + class IncomingFileTransfer : public FileTransfer { public: typedef boost::shared_ptr<IncomingFileTransfer> ref; virtual ~IncomingFileTransfer(); - virtual void accept(WriteBytestream::ref) = 0; + virtual void accept( + boost::shared_ptr<WriteBytestream>, + const FileTransferOptions& = FileTransferOptions()) = 0; virtual const JID& getSender() const = 0; virtual const JID& getRecipient() const = 0; diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.cpp b/Swiften/FileTransfer/IncomingFileTransferManager.cpp index 22e8bf9..d40c5de 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.cpp +++ b/Swiften/FileTransfer/IncomingFileTransferManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -18,9 +18,17 @@ namespace Swift { -IncomingFileTransferManager::IncomingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, - RemoteJingleTransportCandidateSelectorFactory* remoteFactory, - LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, TimerFactory* timerFactory) : jingleSessionManager(jingleSessionManager), router(router), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), timerFactory(timerFactory) { +IncomingFileTransferManager::IncomingFileTransferManager( + JingleSessionManager* jingleSessionManager, + IQRouter* router, + FileTransferTransporterFactory* transporterFactory, + TimerFactory* timerFactory, + CryptoProvider* crypto) : + jingleSessionManager(jingleSessionManager), + router(router), + transporterFactory(transporterFactory), + timerFactory(timerFactory), + crypto(crypto) { jingleSessionManager->addIncomingSessionHandler(this); } @@ -28,16 +36,19 @@ IncomingFileTransferManager::~IncomingFileTransferManager() { jingleSessionManager->removeIncomingSessionHandler(this); } -bool IncomingFileTransferManager::handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents, const JID& recipient) { +bool IncomingFileTransferManager::handleIncomingJingleSession( + JingleSession::ref session, + const std::vector<JingleContentPayload::ref>& contents, + const JID& recipient) { if (JingleContentPayload::ref content = Jingle::getContentWithDescription<JingleFileTransferDescription>(contents)) { - if (content->getTransport<JingleIBBTransportPayload>() || content->getTransport<JingleS5BTransportPayload>()) { - + if (content->getTransport<JingleS5BTransportPayload>()) { JingleFileTransferDescription::ref description = content->getDescription<JingleFileTransferDescription>(); - if (description && description->getOffers().size() == 1) { - IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(recipient, session, content, remoteFactory, localFactory, router, bytestreamRegistry, bytestreamProxy, timerFactory); + IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>( + recipient, session, content, transporterFactory, timerFactory, crypto); onIncomingFileTransfer(transfer); - } else { + } + else { std::cerr << "Received a file-transfer request with no description or more than one file!" << std::endl; session->sendTerminate(JinglePayload::Reason::FailedApplication); } diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.h b/Swiften/FileTransfer/IncomingFileTransferManager.h index 2d1c07f..9570def 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.h +++ b/Swiften/FileTransfer/IncomingFileTransferManager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -15,29 +15,33 @@ namespace Swift { class IQRouter; class JingleSessionManager; - class RemoteJingleTransportCandidateSelectorFactory; - class LocalJingleTransportCandidateGeneratorFactory; - class SOCKS5BytestreamRegistry; - class SOCKS5BytestreamProxy; + class FileTransferTransporterFactory; class TimerFactory; + class CryptoProvider; class IncomingFileTransferManager : public IncomingJingleSessionHandler { public: - IncomingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, TimerFactory* timerFactory); + IncomingFileTransferManager( + JingleSessionManager* jingleSessionManager, + IQRouter* router, + FileTransferTransporterFactory* transporterFactory, + TimerFactory* timerFactory, + CryptoProvider* crypto); ~IncomingFileTransferManager(); boost::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer; private: - bool handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents, const JID& recipient); + bool handleIncomingJingleSession( + JingleSession::ref session, + const std::vector<JingleContentPayload::ref>& contents, + const JID& recipient); private: JingleSessionManager* jingleSessionManager; IQRouter* router; - RemoteJingleTransportCandidateSelectorFactory* remoteFactory; - LocalJingleTransportCandidateGeneratorFactory* localFactory; - SOCKS5BytestreamRegistry* bytestreamRegistry; - SOCKS5BytestreamProxy* bytestreamProxy; + FileTransferTransporterFactory* transporterFactory; TimerFactory* timerFactory; + CryptoProvider* crypto; }; } diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp index 808ff58..b64e333 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,510 +11,384 @@ #include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> +#include <Swiften/Jingle/JingleSession.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/FileTransfer/FileTransferTransporter.h> +#include <Swiften/FileTransfer/FileTransferTransporterFactory.h> +#include <Swiften/FileTransfer/WriteBytestream.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> #include <Swiften/Network/TimerFactory.h> #include <Swiften/Queries/GenericRequest.h> +#include <Swiften/FileTransfer/TransportSession.h> -namespace Swift { +using namespace Swift; + +// TODO: ALlow terminate when already terminated. IncomingJingleFileTransfer::IncomingJingleFileTransfer( - const JID& ourJID, + const JID& toJID, JingleSession::ref session, JingleContentPayload::ref content, - RemoteJingleTransportCandidateSelectorFactory* candidateSelectorFactory, - LocalJingleTransportCandidateGeneratorFactory* candidateGeneratorFactory, - IQRouter* router, - SOCKS5BytestreamRegistry* registry, - SOCKS5BytestreamProxy* proxy, - TimerFactory* timerFactory) : - ourJID(ourJID), - session(session), - router(router), + FileTransferTransporterFactory* transporterFactory, + TimerFactory* timerFactory, + CryptoProvider* crypto) : + JingleFileTransfer(session, toJID, transporterFactory), initialContent(content), + crypto(crypto), 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)); - + hashCalculator(NULL) { description = initialContent->getDescription<JingleFileTransferDescription>(); assert(description); assert(description->getOffers().size() == 1); StreamInitiationFileInfo fileInfo = description->getOffers().front(); - fileSizeInBytes = fileInfo.getSize(); - filename = fileInfo.getName(); + setFileInfo(fileInfo.getName(), fileInfo.getSize()); hash = fileInfo.getHash(); - algo = fileInfo.getAlgo(); + hashAlgorithm = fileInfo.getAlgo(); waitOnHashTimer = timerFactory->createTimer(5000); - waitOnHashTimer->onTick.connect(boost::bind(&IncomingJingleFileTransfer::finishOffTransfer, this)); + waitOnHashTimerTickedConnection = waitOnHashTimer->onTick.connect( + boost::bind(&IncomingJingleFileTransfer::handleWaitOnHashTimerTicked, this)); } IncomingJingleFileTransfer::~IncomingJingleFileTransfer() { - stream->onWrite.disconnect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); - delete hashCalculator; - - session->onSessionTerminateReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this, _1)); - 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) { +void IncomingJingleFileTransfer::accept( + boost::shared_ptr<WriteBytestream> stream, + const FileTransferOptions& options) { + SWIFT_LOG(debug) << std::endl; + if (state != Initial) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + assert(!this->stream); this->stream = stream; + this->options = options; - 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>()) { + assert(!hashCalculator); + hashCalculator = new IncrementalBytestreamHashCalculator( + hashAlgorithm == "md5" || hash.empty(), hashAlgorithm == "sha-1" || hash.empty(), crypto); + + writeStreamDataReceivedConnection = stream->onWrite.connect( + boost::bind(&IncomingJingleFileTransfer::handleWriteStreamDataReceived, this, _1)); + + 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); + setTransporter(transporterFactory->createResponderTransporter( + getInitiator(), getResponder(), s5bTransport->getSessionID())); + transporter->addRemoteCandidates(s5bTransport->getCandidates()); + setState(GeneratingInitialLocalCandidates); + transporter->startGeneratingLocalCandidates(); } else { + // Can't happen, because the transfer would have been rejected automatically 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; - } + terminate(state == Initial ? JinglePayload::Reason::Decline : JinglePayload::Reason::Cancel); } -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::handleLocalTransportCandidatesGenerated( + const std::string& s5bSessionID, + const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + SWIFT_LOG(debug) << std::endl; + if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } -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(); -} + fillCandidateMap(localCandidates, candidates); -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; - } + JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); + transport->setSessionID(s5bSessionID); + transport->setMode(JingleS5BTransportPayload::TCPMode); + foreach(JingleS5BTransportPayload::Candidate candidate, candidates) { + transport->addCandidate(candidate); } -} + session->sendAccept(getContentID(), initialContent->getDescriptions()[0], transport); -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(); + setState(TryingCandidates); + transporter->startTryingRemoteCandidates(); } + void IncomingJingleFileTransfer::handleSessionInfoReceived(JinglePayload::ref jinglePayload) { - if (state == Terminated) { - return; - } + SWIFT_LOG(debug) << std::endl; + JingleFileTransferHash::ref transferHash = jinglePayload->getPayload<JingleFileTransferHash>(); if (transferHash) { - SWIFT_LOG(debug) << "Recevied hash information." << std::endl; + SWIFT_LOG(debug) << "Received hash information." << std::endl; + waitOnHashTimer->stop(); if (transferHash->getHashes().find("sha-1") != transferHash->getHashes().end()) { - algo = "sha-1"; + hashAlgorithm = "sha-1"; hash = transferHash->getHashes().find("sha-1")->second; } else if (transferHash->getHashes().find("md5") != transferHash->getHashes().end()) { - algo = "md5"; + hashAlgorithm = "md5"; hash = transferHash->getHashes().find("md5")->second; } - checkIfAllDataReceived(); + if (state == WaitingForHash) { + checkHashAndTerminate(); + } + } + else { + SWIFT_LOG(debug) << "Ignoring unknown session info" << std::endl; } } 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.")); + SWIFT_LOG(debug) << std::endl; + if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + if (state == Finished) { + SWIFT_LOG(debug) << "Already terminated" << std::endl; + return; + } + + stopAll(); + if (reason && reason->type == JinglePayload::Reason::Cancel) { + setFinishedState(FileTransfer::State::Canceled, FileTransferError(FileTransferError::PeerError)); + } + else if (reason && reason->type == JinglePayload::Reason::Success) { + setFinishedState(FileTransfer::State::Finished, boost::optional<FileTransferError>()); + } + else { + setFinishedState(FileTransfer::State::Failed, FileTransferError(FileTransferError::PeerError)); + } +} + +void IncomingJingleFileTransfer::checkHashAndTerminate() { + if (verifyData()) { + terminate(JinglePayload::Reason::Success); } - 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.")); - }*/ + else { + SWIFT_LOG(warning) << "Hash verification failed" << std::endl; + terminate(JinglePayload::Reason::MediaError); } - state = Terminated; } void IncomingJingleFileTransfer::checkIfAllDataReceived() { - if (receivedBytes == fileSizeInBytes) { + if (receivedBytes == getFileSizeInBytes()) { 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; + SWIFT_LOG(debug) << "No hash information yet. Waiting a while on hash info." << std::endl; + setState(WaitingForHash); waitOnHashTimer->start(); - } else { - SWIFT_LOG(debug) << "We already have hash info using " << algo << " algorithm. Finishing off transfer." << std::endl; - finishOffTransfer(); + } + else { + checkHashAndTerminate(); } } - else if (receivedBytes > fileSizeInBytes) { + else if (receivedBytes > getFileSizeInBytes()) { SWIFT_LOG(debug) << "We got more than we could handle!" << std::endl; + terminate(JinglePayload::Reason::MediaError); } } -void IncomingJingleFileTransfer::handleTransportDataReceived(const std::vector<unsigned char>& data) { - SWIFT_LOG(debug) << data.size() << " bytes received" << std::endl; - onProcessedBytes(data.size()); - stream->write(data); +void IncomingJingleFileTransfer::handleWriteStreamDataReceived( + const std::vector<unsigned char>& data) { + hashCalculator->feedData(data); receivedBytes += data.size(); checkIfAllDataReceived(); } -void IncomingJingleFileTransfer::handleWriteStreamDataReceived(const std::vector<unsigned char>& data) { - receivedBytes += data.size(); - checkIfAllDataReceived(); -} - -void IncomingJingleFileTransfer::useOurCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate) { +void IncomingJingleFileTransfer::handleTransportReplaceReceived( + const JingleContentID& content, JingleTransportPayload::ref transport) { 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; - } + if (state != WaitingForFallbackOrTerminate) { + SWIFT_LOG(warning) << "Incorrect state" << std::endl; + return; } -} -void IncomingJingleFileTransfer::useTheirCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate) { - SWIFT_LOG(debug) << std::endl; + if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { + SWIFT_LOG(debug) << "transport replaced with IBB" << 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; - } + startTransferring(transporter->createIBBReceiveSession( + ibbTransport->getSessionID(), + description->getOffers()[0].getSize(), + stream)); + session->sendTransportAccept(content, ibbTransport); + } + else { + SWIFT_LOG(debug) << "Unknown replace transport" << std::endl; + session->sendTransportReject(content, transport); } } -void IncomingJingleFileTransfer::fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload) { - map.clear(); - foreach (JingleS5BTransportPayload::Candidate candidate, s5bPayload->getCandidates()) { - map[candidate.cid] = candidate; - } +JingleContentID IncomingJingleFileTransfer::getContentID() const { + return JingleContentID(initialContent->getName(), initialContent->getCreator()); } - -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; +bool IncomingJingleFileTransfer::verifyData() { + if (hashAlgorithm.empty() || hash.empty()) { + SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl; + return true; + } + if (hashAlgorithm == "sha-1") { + SWIFT_LOG(debug) << "Verify SHA-1 hash: " << (hash == hashCalculator->getSHA1String()) << std::endl; + return hash == hashCalculator->getSHA1String(); + } + else if (hashAlgorithm == "md5") { + SWIFT_LOG(debug) << "Verify MD5 hash: " << (hash == hashCalculator->getMD5String()) << std::endl; + return hash == hashCalculator->getMD5String(); + } + else { + SWIFT_LOG(debug) << "Unknown hash, skipping" << std::endl; + return true; } } -void IncomingJingleFileTransfer::proxySessionReady(const JID& proxy, bool error) { - if (error) { - // indicate proxy error - } else { - // activate proxy - activateProxySession(proxy); - } +void IncomingJingleFileTransfer::handleWaitOnHashTimerTicked() { + SWIFT_LOG(debug) << std::endl; + waitOnHashTimer->stop(); + terminate(JinglePayload::Reason::Success); } -void IncomingJingleFileTransfer::activateProxySession(const JID &proxy) { - S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); - proxyRequest->setSID(s5bSessionID); - proxyRequest->setActivate(session->getInitiator()); +const JID& IncomingJingleFileTransfer::getSender() const { + return getInitiator(); +} + +const JID& IncomingJingleFileTransfer::getRecipient() const { + return getResponder(); +} - 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::setState(State state) { + SWIFT_LOG(debug) << state << std::endl; + this->state = state; + onStateChanged(FileTransfer::State(getExternalState(state))); } -void IncomingJingleFileTransfer::handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> /*request*/, ErrorPayload::ref error) { +void IncomingJingleFileTransfer::setFinishedState( + FileTransfer::State::Type type, const boost::optional<FileTransferError>& 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)); + this->state = Finished; + onStateChanged(type); + onFinished(error); +} + +void IncomingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { + if (error && state != WaitingForHash) { + terminate(JinglePayload::Reason::MediaError); } } -void IncomingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref transport) { - SWIFT_LOG(debug) << "transport info received" << std::endl; - if (state == Terminated) { - return; +FileTransfer::State::Type IncomingJingleFileTransfer::getExternalState(State state) { + switch (state) { + case Initial: return FileTransfer::State::Initial; + case GeneratingInitialLocalCandidates: return FileTransfer::State::WaitingForStart; + case TryingCandidates: return FileTransfer::State::Negotiating; + case WaitingForPeerProxyActivate: return FileTransfer::State::Negotiating; + case WaitingForLocalProxyActivate: return FileTransfer::State::Negotiating; + case WaitingForFallbackOrTerminate: return FileTransfer::State::Negotiating; + case Transferring: return FileTransfer::State::Transferring; + case WaitingForHash: return FileTransfer::State::Transferring; + case Finished: return FileTransfer::State::Finished; } - 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(); - } + assert(false); + return FileTransfer::State::Initial; +} + +void IncomingJingleFileTransfer::stopAll() { + if (state != Initial) { + writeStreamDataReceivedConnection.disconnect(); + delete hashCalculator; } - else { - SWIFT_LOG(debug) << "Expected something different here." << std::endl; + switch (state) { + case Initial: break; + case GeneratingInitialLocalCandidates: transporter->stopGeneratingLocalCandidates(); break; + case TryingCandidates: transporter->stopTryingRemoteCandidates(); break; + case WaitingForFallbackOrTerminate: break; + case WaitingForPeerProxyActivate: break; + case WaitingForLocalProxyActivate: transporter->stopActivatingProxy(); break; + case WaitingForHash: // Fallthrough + case Transferring: + assert(transportSession); + transferFinishedConnection.disconnect(); + transportSession->stop(); + transportSession.reset(); + break; + case Finished: SWIFT_LOG(warning) << "Already finished" << std::endl; break; + } + if (state != Initial) { + delete transporter; } - /*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; +bool IncomingJingleFileTransfer::hasPriorityOnCandidateTie() const { + return false; +} + +void IncomingJingleFileTransfer::fallback() { + if (options.isInBandAllowed()) { + setState(WaitingForFallbackOrTerminate); } - 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); + else { + terminate(JinglePayload::Reason::ConnectivityError); + } +} + +void IncomingJingleFileTransfer::startTransferViaRemoteCandidate() { + SWIFT_LOG(debug) << std::endl; + + if (ourCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { + setState(WaitingForPeerProxyActivate); + } + else { + startTransferring(createRemoteCandidateSession()); } } -void IncomingJingleFileTransfer::stopActiveTransport() { - if (activeTransport) { - activeTransport->stop(); - activeTransport->onDataReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1)); +void IncomingJingleFileTransfer::startTransferViaLocalCandidate() { + SWIFT_LOG(debug) << std::endl; + + if (theirCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { + setState(WaitingForLocalProxyActivate); + transporter->startActivatingProxy(theirCandidateChoice->jid); + } + else { + startTransferring(createLocalCandidateSession()); } } -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); + +void IncomingJingleFileTransfer::startTransferring(boost::shared_ptr<TransportSession> transportSession) { + SWIFT_LOG(debug) << std::endl; + + this->transportSession = transportSession; + transferFinishedConnection = transportSession->onFinished.connect( + boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); + setState(Transferring); + transportSession->start(); } -JingleContentID IncomingJingleFileTransfer::getContentID() const { - return JingleContentID(initialContent->getName(), initialContent->getCreator()); +bool IncomingJingleFileTransfer::isWaitingForPeerProxyActivate() const { + return state == WaitingForPeerProxyActivate; } -void IncomingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { - if (state == Terminated) { - return; - } +bool IncomingJingleFileTransfer::isWaitingForLocalProxyActivate() const { + return state == WaitingForLocalProxyActivate; +} - if (error) { - session->sendTerminate(JinglePayload::Reason::ConnectivityError); - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); - onFinished(error); - } - // +bool IncomingJingleFileTransfer::isTryingCandidates() const { + return state == TryingCandidates; +} + +boost::shared_ptr<TransportSession> IncomingJingleFileTransfer::createLocalCandidateSession() { + return transporter->createLocalCandidateSession(stream); } +boost::shared_ptr<TransportSession> IncomingJingleFileTransfer::createRemoteCandidateSession() { + return transporter->createRemoteCandidateSession(stream); +} + +void IncomingJingleFileTransfer::terminate(JinglePayload::Reason::Type reason) { + SWIFT_LOG(debug) << reason << std::endl; + + if (state != Finished) { + session->sendTerminate(reason); + } + stopAll(); + setFinishedState(getExternalFinishedState(reason), getFileTransferError(reason)); } diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.h b/Swiften/FileTransfer/IncomingJingleFileTransfer.h index 0731e04..a691d5b 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.h +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -8,127 +8,112 @@ #include <boost/shared_ptr.hpp> #include <boost/cstdint.hpp> +#include <string> #include <Swiften/Base/API.h> -#include <Swiften/Base/IDGenerator.h> -#include <Swiften/Network/Timer.h> -#include <Swiften/Jingle/JingleSession.h> +#include <Swiften/Base/Override.h> #include <Swiften/Jingle/JingleContentID.h> #include <Swiften/FileTransfer/IncomingFileTransfer.h> -#include <Swiften/FileTransfer/JingleTransport.h> -#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> -#include <Swiften/Elements/JingleContentPayload.h> -#include <Swiften/Elements/JingleFileTransferDescription.h> -#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/FileTransfer/JingleFileTransfer.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/Elements/S5BProxyRequest.h> -#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> namespace Swift { - class IQRouter; - class RemoteJingleTransportCandidateSelectorFactory; - class LocalJingleTransportCandidateGeneratorFactory; - class RemoteJingleTransportCandidateSelector; - class LocalJingleTransportCandidateGenerator; - class SOCKS5BytestreamRegistry; - class SOCKS5BytestreamProxy; + class JID; + class JingleSession; + class JingleContentPayload; + class FileTransferTransporter; + class FileTransferTransporterFactory; + class TimerFactory; + class Timer; + class CryptoProvider; class IncrementalBytestreamHashCalculator; + class JingleFileTransferDescription; - class SWIFTEN_API IncomingJingleFileTransfer : public IncomingFileTransfer { + class SWIFTEN_API IncomingJingleFileTransfer : public IncomingFileTransfer, public JingleFileTransfer { public: typedef boost::shared_ptr<IncomingJingleFileTransfer> ref; - enum State { - Initial, - CreatingInitialTransports, - NegotiatingTransport, - Transferring, - WaitingForFallbackOrTerminate, - Terminated - }; IncomingJingleFileTransfer( - const JID& recipient, - JingleSession::ref, - JingleContentPayload::ref content, - RemoteJingleTransportCandidateSelectorFactory*, - LocalJingleTransportCandidateGeneratorFactory*, - IQRouter* router, - SOCKS5BytestreamRegistry* bytestreamRegistry, - SOCKS5BytestreamProxy* bytestreamProxy, - TimerFactory*); + const JID& recipient, + boost::shared_ptr<JingleSession>, + boost::shared_ptr<JingleContentPayload> content, + FileTransferTransporterFactory*, + TimerFactory*, + CryptoProvider*); ~IncomingJingleFileTransfer(); - virtual void accept(WriteBytestream::ref); - virtual const JID& getSender() const; - virtual const JID& getRecipient() const; + virtual void accept(boost::shared_ptr<WriteBytestream>, const FileTransferOptions&) SWIFTEN_OVERRIDE; void cancel(); private: - void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason>); - void handleSessionInfoReceived(JinglePayload::ref); - void handleTransportReplaceReceived(const JingleContentID&, JingleTransportPayload::ref); - void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref); - void handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates); - void handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref candidate); - void setActiveTransport(JingleTransport::ref transport); - void handleTransportDataReceived(const std::vector<unsigned char>& data); + enum State { + Initial, + GeneratingInitialLocalCandidates, + TryingCandidates, + WaitingForPeerProxyActivate, + WaitingForLocalProxyActivate, + WaitingForFallbackOrTerminate, + Transferring, + WaitingForHash, + Finished + }; + + virtual void handleSessionTerminateReceived( + boost::optional<JinglePayload::Reason> reason) SWIFTEN_OVERRIDE; + virtual void handleSessionInfoReceived(boost::shared_ptr<JinglePayload>) SWIFTEN_OVERRIDE; + virtual void handleTransportReplaceReceived( + const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + + virtual void handleLocalTransportCandidatesGenerated( + const std::string& s5bSessionID, + const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE; + void handleWriteStreamDataReceived(const std::vector<unsigned char>& data); void stopActiveTransport(); void checkCandidateSelected(); - JingleIncomingIBBTransport::ref createIBBTransport(JingleIBBTransportPayload::ref ibbTransport); - JingleContentID getContentID() const; + virtual JingleContentID getContentID() const SWIFTEN_OVERRIDE; void checkIfAllDataReceived(); - bool verifyReceviedData(); - void finishOffTransfer(); + bool verifyData(); + void handleWaitOnHashTimerTicked(); void handleTransferFinished(boost::optional<FileTransferError>); private: - typedef std::map<std::string, JingleS5BTransportPayload::Candidate> CandidateMap; + void startTransferViaRemoteCandidate(); + void startTransferViaLocalCandidate(); + void checkHashAndTerminate(); + void stopAll(); + void setState(State state); + void setFinishedState(FileTransfer::State::Type, const boost::optional<FileTransferError>& error); + const JID& getSender() const SWIFTEN_OVERRIDE; + const JID& getRecipient() const SWIFTEN_OVERRIDE; + static FileTransfer::State::Type getExternalState(State state); + virtual bool hasPriorityOnCandidateTie() const SWIFTEN_OVERRIDE; + virtual void fallback() SWIFTEN_OVERRIDE; + virtual void startTransferring(boost::shared_ptr<TransportSession>) SWIFTEN_OVERRIDE; + virtual bool isWaitingForPeerProxyActivate() const SWIFTEN_OVERRIDE; + virtual bool isWaitingForLocalProxyActivate() const SWIFTEN_OVERRIDE; + virtual bool isTryingCandidates() const SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession() SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession() SWIFTEN_OVERRIDE; + virtual void terminate(JinglePayload::Reason::Type reason) SWIFTEN_OVERRIDE; - private: - void activateProxySession(const JID &proxy); - void handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error); - void proxySessionReady(const JID& proxy, bool error); private: - void useOurCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate); - void useTheirCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate); - void decideOnUsedTransport(); - void fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload); - - private: - JID ourJID; - JingleSession::ref session; - IQRouter* router; - JingleContentPayload::ref initialContent; + boost::shared_ptr<JingleContentPayload> initialContent; + CryptoProvider* crypto; State state; - JingleFileTransferDescription::ref description; - WriteBytestream::ref stream; + boost::shared_ptr<JingleFileTransferDescription> description; + boost::shared_ptr<WriteBytestream> stream; boost::uintmax_t receivedBytes; IncrementalBytestreamHashCalculator* hashCalculator; - Timer::ref waitOnHashTimer; - IDGenerator idGenerator; - - RemoteJingleTransportCandidateSelector* candidateSelector; - LocalJingleTransportCandidateGenerator* candidateGenerator; - SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; - bool remoteTransportCandidateSelectFinished; - JingleTransportPayload::ref selectedRemoteTransportCandidate; - bool localTransportCandidateSelectFinished; - JingleTransportPayload::ref selectedLocalTransportCandidate; - - JingleS5BTransportPayload::ref ourCandidate; - JingleS5BTransportPayload::ref theirCandidate; - CandidateMap ourCandidates; - CandidateMap theirCandidates; - SOCKS5BytestreamClientSession::ref clientSession; - std::string s5bDestination; - std::string s5bSessionID; - SOCKS5BytestreamServerSession* serverSession; + boost::shared_ptr<Timer> waitOnHashTimer; + std::string hashAlgorithm; + std::string hash; + FileTransferOptions options; - JingleTransport::ref activeTransport; + boost::bsignals::scoped_connection writeStreamDataReceivedConnection; + boost::bsignals::scoped_connection waitOnHashTimerTickedConnection; + boost::bsignals::connection transferFinishedConnection; }; } diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp index 6b53a1b..601a97f 100644 --- a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp @@ -4,17 +4,23 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + + #include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h> #include <Swiften/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/MD5.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> namespace Swift { -IncrementalBytestreamHashCalculator::IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1) { - md5Hasher = doMD5 ? new MD5() : NULL; - sha1Hasher = doSHA1 ? new SHA1() : NULL; +IncrementalBytestreamHashCalculator::IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1, CryptoProvider* crypto) { + md5Hasher = doMD5 ? crypto->createMD5() : NULL; + sha1Hasher = doSHA1 ? crypto->createSHA1() : NULL; } IncrementalBytestreamHashCalculator::~IncrementalBytestreamHashCalculator() { @@ -41,21 +47,19 @@ void IncrementalBytestreamHashCalculator::feedData(const SafeByteArray& data) { }*/ std::string IncrementalBytestreamHashCalculator::getSHA1String() { - if (sha1Hasher) { - ByteArray result = sha1Hasher->getHash(); - return Hexify::hexify(result); - } else { - return std::string(); + assert(sha1Hasher); + if (!sha1Hash) { + sha1Hash = Hexify::hexify(sha1Hasher->getHash()); } + return *sha1Hash; } std::string IncrementalBytestreamHashCalculator::getMD5String() { - if (md5Hasher) { - ByteArray result = md5Hasher->getHash(); - return Hexify::hexify(result); - } else { - return std::string(); + assert(md5Hasher); + if (!md5Hash) { + md5Hash = Hexify::hexify(md5Hasher->getHash()); } + return *md5Hash; } } diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h index 64f4b5f..7b4e124 100644 --- a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h @@ -4,30 +4,40 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once +#include <string> + #include <Swiften/Base/ByteArray.h> #include <Swiften/Base/SafeByteArray.h> +#include <boost/optional.hpp> namespace Swift { - -class MD5; -class SHA1; - -class IncrementalBytestreamHashCalculator { -public: - IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1); - ~IncrementalBytestreamHashCalculator(); - - void feedData(const ByteArray& data); - //void feedData(const SafeByteArray& data); - - std::string getSHA1String(); - std::string getMD5String(); - -private: - MD5* md5Hasher; - SHA1* sha1Hasher; -}; + class Hash; + class CryptoProvider; + + class IncrementalBytestreamHashCalculator { + public: + IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1, CryptoProvider* crypto); + ~IncrementalBytestreamHashCalculator(); + + void feedData(const ByteArray& data); + //void feedData(const SafeByteArray& data); + + std::string getSHA1String(); + std::string getMD5String(); + + private: + Hash* md5Hasher; + Hash* sha1Hasher; + boost::optional<std::string> md5Hash; + boost::optional<std::string> sha1Hash; + }; } diff --git a/Swiften/FileTransfer/JingleFileTransfer.cpp b/Swiften/FileTransfer/JingleFileTransfer.cpp new file mode 100644 index 0000000..6eecaa2 --- /dev/null +++ b/Swiften/FileTransfer/JingleFileTransfer.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/JingleFileTransfer.h> + +#include <boost/typeof/typeof.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Jingle/JingleSession.h> +#include <Swiften/FileTransfer/FileTransferTransporter.h> +#include <Swiften/Base/Log.h> + +using namespace Swift; + +JingleFileTransfer::JingleFileTransfer( + boost::shared_ptr<JingleSession> session, + const JID& target, + FileTransferTransporterFactory* transporterFactory) : + session(session), + target(target), + transporterFactory(transporterFactory), + transporter(NULL), + ourCandidateSelectFinished(false), + theirCandidateSelectFinished(false) { + + session->addListener(this); + +} + +JingleFileTransfer::~JingleFileTransfer() { + session->removeListener(this); +} + +void JingleFileTransfer::fillCandidateMap(CandidateMap& map, const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + map.clear(); + foreach (JingleS5BTransportPayload::Candidate candidate, candidates) { + map[candidate.cid] = candidate; + } +} + +/* +std::string JingleFileTransfer::getS5BDstAddr(const JID& requester, const JID& target) const { + return Hexify::hexify(crypto->getSHA1Hash( + createSafeByteArray(s5bSessionID + requester.toString() + target.toString()))); +} +*/ + +const JID& JingleFileTransfer::getInitiator() const { + return session->getInitiator(); +} + +const JID& JingleFileTransfer::getResponder() const { + return target; +} + +FileTransfer::State::Type JingleFileTransfer::getExternalFinishedState(JinglePayload::Reason::Type reason) { + if (reason == JinglePayload::Reason::Cancel || reason == JinglePayload::Reason::Decline) { + return FileTransfer::State::Canceled; + } + else if (reason == JinglePayload::Reason::Success) { + return FileTransfer::State::Finished; + } + else { + return FileTransfer::State::Failed; + } +} + +boost::optional<FileTransferError> JingleFileTransfer::getFileTransferError(JinglePayload::Reason::Type reason) { + if (reason == JinglePayload::Reason::Success) { + return boost::optional<FileTransferError>(); + } + else { + return boost::optional<FileTransferError>(FileTransferError::UnknownError); + } +} + +void JingleFileTransfer::handleRemoteTransportCandidateSelectFinished( + const std::string& s5bSessionID, const boost::optional<JingleS5BTransportPayload::Candidate>& candidate) { + SWIFT_LOG(debug) << std::endl; + + ourCandidateChoice = candidate; + ourCandidateSelectFinished = true; + + JingleS5BTransportPayload::ref s5bPayload = boost::make_shared<JingleS5BTransportPayload>(); + s5bPayload->setSessionID(s5bSessionID); + if (candidate) { + s5bPayload->setCandidateUsed(candidate->cid); + } + else { + s5bPayload->setCandidateError(true); + } + candidateSelectRequestID = session->sendTransportInfo(getContentID(), s5bPayload); + + decideOnCandidates(); +} + +// decide on candidates according to http://xmpp.org/extensions/xep-0260.html#complete +void JingleFileTransfer::decideOnCandidates() { + SWIFT_LOG(debug) << std::endl; + if (!ourCandidateSelectFinished || !theirCandidateSelectFinished) { + SWIFT_LOG(debug) << "Can't make a decision yet!" << std::endl; + return; + } + if (!ourCandidateChoice && !theirCandidateChoice) { + SWIFT_LOG(debug) << "No candidates succeeded." << std::endl; + fallback(); + } + else if (ourCandidateChoice && !theirCandidateChoice) { + startTransferViaRemoteCandidate(); + } + else if (theirCandidateChoice && !ourCandidateChoice) { + startTransferViaLocalCandidate(); + } + else { + SWIFT_LOG(debug) << "Choosing between candidates " + << ourCandidateChoice->cid << "(" << ourCandidateChoice->priority << ")" << " and " + << theirCandidateChoice->cid << "(" << theirCandidateChoice->priority << ")" << std::endl; + if (ourCandidateChoice->priority > theirCandidateChoice->priority) { + startTransferViaRemoteCandidate(); + } + else if (ourCandidateChoice->priority < theirCandidateChoice->priority) { + startTransferViaLocalCandidate(); + } + else { + if (hasPriorityOnCandidateTie()) { + startTransferViaRemoteCandidate(); + } + else { + startTransferViaLocalCandidate(); + } + } + } +} + +void JingleFileTransfer::handleProxyActivateFinished( + const std::string& s5bSessionID, ErrorPayload::ref error) { + SWIFT_LOG(debug) << std::endl; + if (!isWaitingForLocalProxyActivate()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + if (error) { + SWIFT_LOG(debug) << "Error activating proxy" << std::endl; + JingleS5BTransportPayload::ref proxyError = boost::make_shared<JingleS5BTransportPayload>(); + proxyError->setSessionID(s5bSessionID); + proxyError->setProxyError(true); + session->sendTransportInfo(getContentID(), proxyError); + fallback(); + } + else { + JingleS5BTransportPayload::ref proxyActivate = boost::make_shared<JingleS5BTransportPayload>(); + proxyActivate->setSessionID(s5bSessionID); + proxyActivate->setActivated(theirCandidateChoice->cid); + session->sendTransportInfo(getContentID(), proxyActivate); + startTransferring(createRemoteCandidateSession()); + } +} + +void JingleFileTransfer::handleTransportInfoReceived( + const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { + SWIFT_LOG(debug) << std::endl; + + if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { + if (s5bPayload->hasCandidateError() || !s5bPayload->getCandidateUsed().empty()) { + SWIFT_LOG(debug) << "Received candidate decision from peer" << std::endl; + if (!isTryingCandidates()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + theirCandidateSelectFinished = true; + if (!s5bPayload->hasCandidateError()) { + BOOST_AUTO(theirCandidate, localCandidates.find(s5bPayload->getCandidateUsed())); + if (theirCandidate == localCandidates.end()) { + SWIFT_LOG(warning) << "Got invalid candidate" << std::endl; + terminate(JinglePayload::Reason::GeneralError); + return; + } + theirCandidateChoice = theirCandidate->second; + } + decideOnCandidates(); + } + else if (!s5bPayload->getActivated().empty()) { + SWIFT_LOG(debug) << "Received peer activate from peer" << std::endl; + if (!isWaitingForPeerProxyActivate()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + if (ourCandidateChoice->cid == s5bPayload->getActivated()) { + startTransferring(createRemoteCandidateSession()); + } + else { + SWIFT_LOG(warning) << "ourCandidateChoice doesn't match activated proxy candidate!" << std::endl; + terminate(JinglePayload::Reason::GeneralError); + } + } + else { + SWIFT_LOG(debug) << "Ignoring unknown info" << std::endl; + } + } + else { + SWIFT_LOG(debug) << "Ignoring unknown info" << std::endl; + } +} + +void JingleFileTransfer::setTransporter(FileTransferTransporter* transporter) { + this->transporter = transporter; + localTransportCandidatesGeneratedConnection = transporter->onLocalCandidatesGenerated.connect( + boost::bind(&JingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1, _2)); + remoteTransportCandidateSelectFinishedConnection = transporter->onRemoteCandidateSelectFinished.connect( + boost::bind(&JingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1, _2)); + proxyActivatedConnection = transporter->onProxyActivated.connect( + boost::bind(&JingleFileTransfer::handleProxyActivateFinished, this, _1, _2)); +} + diff --git a/Swiften/FileTransfer/JingleFileTransfer.h b/Swiften/FileTransfer/JingleFileTransfer.h new file mode 100644 index 0000000..ee646c1 --- /dev/null +++ b/Swiften/FileTransfer/JingleFileTransfer.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> + +#include <boost/shared_ptr.hpp> +#include <vector> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/FileTransfer/FileTransfer.h> +#include <Swiften/Jingle/AbstractJingleSessionListener.h> +#include <Swiften/Jingle/JingleContentID.h> + +namespace Swift { + class CryptoProvider; + class IQRouter; + class RemoteJingleTransportCandidateSelector; + class LocalJingleTransportCandidateGenerator; + class JingleSession; + class FileTransferTransporter; + class FileTransferTransporterFactory; + class TransportSession; + + class SWIFTEN_API JingleFileTransfer : public AbstractJingleSessionListener { + public: + JingleFileTransfer( + boost::shared_ptr<JingleSession>, + const JID& target, + FileTransferTransporterFactory*); + virtual ~JingleFileTransfer(); + + protected: + virtual void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref); + virtual void handleLocalTransportCandidatesGenerated( + const std::string& s5bSessionID, + const std::vector<JingleS5BTransportPayload::Candidate>&) = 0; + virtual void handleProxyActivateFinished( + const std::string& s5bSessionID, + ErrorPayload::ref error); + virtual void decideOnCandidates(); + void handleRemoteTransportCandidateSelectFinished( + const std::string& s5bSessionID, const boost::optional<JingleS5BTransportPayload::Candidate>&); + virtual JingleContentID getContentID() const = 0; + virtual void startTransferring(boost::shared_ptr<TransportSession>) = 0; + virtual void terminate(JinglePayload::Reason::Type reason) = 0; + virtual void fallback() = 0; + virtual bool hasPriorityOnCandidateTie() const = 0; + virtual bool isWaitingForPeerProxyActivate() const = 0; + virtual bool isWaitingForLocalProxyActivate() const = 0; + virtual bool isTryingCandidates() const = 0; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession() = 0; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession() = 0; + virtual void startTransferViaLocalCandidate() = 0; + virtual void startTransferViaRemoteCandidate() = 0; + + protected: + typedef std::map<std::string, JingleS5BTransportPayload::Candidate> CandidateMap; + + void setTransporter(FileTransferTransporter* transporter); + void fillCandidateMap( + CandidateMap& map, + const std::vector<JingleS5BTransportPayload::Candidate>&); + const JID& getInitiator() const; + const JID& getResponder() const; + + static FileTransfer::State::Type getExternalFinishedState(JinglePayload::Reason::Type); + static boost::optional<FileTransferError> getFileTransferError(JinglePayload::Reason::Type); + + boost::shared_ptr<JingleSession> session; + JID target; + FileTransferTransporterFactory* transporterFactory; + FileTransferTransporter* transporter; + + std::string candidateSelectRequestID; + bool ourCandidateSelectFinished; + boost::optional<JingleS5BTransportPayload::Candidate> ourCandidateChoice; + bool theirCandidateSelectFinished; + boost::optional<JingleS5BTransportPayload::Candidate> theirCandidateChoice; + CandidateMap localCandidates; + + boost::shared_ptr<TransportSession> transportSession; + + boost::bsignals::scoped_connection localTransportCandidatesGeneratedConnection; + boost::bsignals::scoped_connection remoteTransportCandidateSelectFinishedConnection; + boost::bsignals::scoped_connection proxyActivatedConnection; + }; +} diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp deleted file mode 100644 index ccca641..0000000 --- a/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> - -namespace Swift { - -JingleIncomingIBBTransport::JingleIncomingIBBTransport(const JID& from, const JID& to, const std::string& id, size_t size, IQRouter* router) : ibbSession(id, from, to, size, router) { - ibbSession.onDataReceived.connect(boost::ref(onDataReceived)); - ibbSession.onFinished.connect(boost::ref(onFinished)); -} - -void JingleIncomingIBBTransport::start() { - ibbSession.start(); -} - -void JingleIncomingIBBTransport::stop() { - ibbSession.stop(); -} - -} diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.h b/Swiften/FileTransfer/JingleIncomingIBBTransport.h deleted file mode 100644 index be18a2d..0000000 --- a/Swiften/FileTransfer/JingleIncomingIBBTransport.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <boost/shared_ptr.hpp> - -#include <Swiften/FileTransfer/JingleTransport.h> -#include <Swiften/FileTransfer/IBBReceiveSession.h> - -namespace Swift { - class JingleIncomingIBBTransport : public JingleTransport { - public: - typedef boost::shared_ptr<JingleIncomingIBBTransport> ref; - - JingleIncomingIBBTransport(const JID& from, const JID& to, const std::string& id, size_t size, IQRouter* router); - - virtual void start(); - virtual void stop(); - - private: - IBBReceiveSession ibbSession; - }; -} diff --git a/Swiften/FileTransfer/JingleTransport.cpp b/Swiften/FileTransfer/JingleTransport.cpp deleted file mode 100644 index c507922..0000000 --- a/Swiften/FileTransfer/JingleTransport.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/FileTransfer/JingleTransport.h> - -namespace Swift { - -JingleTransport::~JingleTransport() { - -} - -} diff --git a/Swiften/FileTransfer/JingleTransport.h b/Swiften/FileTransfer/JingleTransport.h deleted file mode 100644 index fa296e8..0000000 --- a/Swiften/FileTransfer/JingleTransport.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <boost/shared_ptr.hpp> - -#include <Swiften/Base/boost_bsignals.h> -#include <Swiften/FileTransfer/FileTransfer.h> - -namespace Swift { - class JingleTransport { - public: - typedef boost::shared_ptr<JingleTransport> ref; - - virtual ~JingleTransport(); - - virtual void start() = 0; - virtual void stop() = 0; - - boost::signal<void (const std::vector<unsigned char>&)> onDataReceived; - boost::signal<void (boost::optional<FileTransferError>)> onFinished; - }; -} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp index 852902b..53ad53a 100644 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp @@ -1,14 +1,120 @@ /* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. */ #include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> +#include <vector> + +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h> + +static const unsigned int LOCAL_PREFERENCE = 0; + namespace Swift { +LocalJingleTransportCandidateGenerator::LocalJingleTransportCandidateGenerator( + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + const JID& ownJID, + IDGenerator* idGenerator) : + s5bServerManager(s5bServerManager), + s5bProxy(s5bProxy), + ownJID(ownJID), + idGenerator(idGenerator) { +} + LocalJingleTransportCandidateGenerator::~LocalJingleTransportCandidateGenerator() { + SWIFT_LOG_ASSERT(!s5bServerInitializeRequest, warning) << std::endl; +} + +void LocalJingleTransportCandidateGenerator::start() { + assert(!s5bServerInitializeRequest); + s5bServerInitializeRequest = s5bServerManager->createInitializeRequest(); + s5bServerInitializeRequest->onFinished.connect( + boost::bind(&LocalJingleTransportCandidateGenerator::handleS5BServerInitialized, this, _1)); + + s5bServerInitializeRequest->start(); +} + +void LocalJingleTransportCandidateGenerator::stop() { + if (s5bServerInitializeRequest) { + s5bServerInitializeRequest->stop(); + s5bServerInitializeRequest.reset(); + } } +void LocalJingleTransportCandidateGenerator::handleS5BServerInitialized(bool success) { + std::vector<JingleS5BTransportPayload::Candidate> candidates; + if (success) { + // get direct candidates + std::vector<HostAddressPort> directCandidates = s5bServerManager->getHostAddressPorts(); + foreach(HostAddressPort addressPort, directCandidates) { + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::DirectType; + candidate.jid = ownJID; + candidate.hostPort = addressPort; + candidate.priority = 65536 * 126 + LOCAL_PREFERENCE; + candidate.cid = idGenerator->generateID(); + candidates.push_back(candidate); + } + + // get assissted candidates + std::vector<HostAddressPort> assisstedCandidates = s5bServerManager->getAssistedHostAddressPorts(); + foreach(HostAddressPort addressPort, assisstedCandidates) { + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::AssistedType; + candidate.jid = ownJID; + candidate.hostPort = addressPort; + candidate.priority = 65536 * 120 + LOCAL_PREFERENCE; + candidate.cid = idGenerator->generateID(); + candidates.push_back(candidate); + } + } + else { + SWIFT_LOG(warning) << "Unable to start SOCKS5 server" << std::endl; + } + + s5bServerInitializeRequest->stop(); + s5bServerInitializeRequest.reset(); + + onLocalTransportCandidatesGenerated(candidates); +} + +/*void LocalJingleTransportCandidateGenerator::handleS5BProxiesDiscovered() { + foreach(S5BProxyRequest::ref proxy, s5bProxiesDiscoverRequest->getS5BProxies()) { + if (proxy->getStreamHost()) { // FIXME: Added this test, because there were cases where this wasn't initialized. Investigate this. (Remko) + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::ProxyType; + candidate.jid = (*proxy->getStreamHost()).jid; + candidate.hostPort = (*proxy->getStreamHost()).addressPort; + candidate.priority = 65536 * 10 + LOCAL_PREFERENCE; + candidate.cid = idGenerator.generateID(); + s5bCandidatesPayload->addCandidate(candidate); + } + } + + haveS5BProxyCandidates = true; + s5bProxiesDiscoverRequest->stop(); + s5bProxiesDiscoverRequest.reset(); + + checkS5BCandidatesReady(); +}*/ + } diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h index 14c128a..02dfef5 100644 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h @@ -1,30 +1,54 @@ /* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. */ #pragma once #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> -#include <Swiften/Base/API.h> -#include <Swiften/Elements/JingleTransportPayload.h> -#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/Base/Override.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> namespace Swift { - class SWIFTEN_API LocalJingleTransportCandidateGenerator { + class SOCKS5BytestreamServerManager; + class SOCKS5BytestreamProxiesManager; + class SOCKS5BytestreamServerInitializeRequest; + class JingleS5BTransportPayload; + + class LocalJingleTransportCandidateGenerator { public: + LocalJingleTransportCandidateGenerator( + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + const JID& ownJID, + IDGenerator* idGenerator); virtual ~LocalJingleTransportCandidateGenerator(); - /** - * Should call onLocalTransportCandidatesGenerated if it has finished discovering local candidates. - */ - virtual void generateLocalTransportCandidates(JingleTransportPayload::ref) = 0; - virtual bool isActualCandidate(JingleTransportPayload::ref) = 0; - virtual int getPriority(JingleTransportPayload::ref) = 0; - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0; + virtual void start(); + virtual void stop(); + + boost::signal<void (const std::vector<JingleS5BTransportPayload::Candidate>&)> onLocalTransportCandidatesGenerated; + + private: + void handleS5BServerInitialized(bool success); + void checkS5BCandidatesReady(); - boost::signal<void (JingleTransportPayload::ref)> onLocalTransportCandidatesGenerated; + private: + SOCKS5BytestreamServerManager* s5bServerManager; + SOCKS5BytestreamProxiesManager* s5bProxy; + JID ownJID; + IDGenerator* idGenerator; + boost::shared_ptr<SOCKS5BytestreamServerInitializeRequest> s5bServerInitializeRequest; }; } diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp deleted file mode 100644 index a1e3874..0000000 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> - -namespace Swift { - -LocalJingleTransportCandidateGeneratorFactory::~LocalJingleTransportCandidateGeneratorFactory() { -} - -} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h deleted file mode 100644 index 422e006..0000000 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <Swiften/Base/API.h> - -namespace Swift { - class LocalJingleTransportCandidateGenerator; - - class SWIFTEN_API LocalJingleTransportCandidateGeneratorFactory { - public: - virtual ~LocalJingleTransportCandidateGeneratorFactory(); - - virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() = 0; - }; -} diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.h b/Swiften/FileTransfer/OutgoingFileTransfer.h index 1ec1ae3..59dc718 100644 --- a/Swiften/FileTransfer/OutgoingFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingFileTransfer.h @@ -18,6 +18,5 @@ namespace Swift { virtual ~OutgoingFileTransfer(); virtual void start() = 0; - virtual void stop() = 0; }; } diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp index 6f23bb7..4b3c6b5 100644 --- a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp +++ b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp @@ -4,7 +4,13 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ -#include "OutgoingFileTransferManager.h" +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/OutgoingFileTransferManager.h> #include <boost/smart_ptr/make_shared.hpp> @@ -17,7 +23,15 @@ namespace Swift { -OutgoingFileTransferManager::OutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy) { +OutgoingFileTransferManager::OutgoingFileTransferManager( + JingleSessionManager* jingleSessionManager, + IQRouter* router, + FileTransferTransporterFactory* transporterFactory, + CryptoProvider* crypto) : + jingleSessionManager(jingleSessionManager), + iqRouter(router), + transporterFactory(transporterFactory), + crypto(crypto) { idGenerator = new IDGenerator(); } @@ -25,22 +39,24 @@ OutgoingFileTransferManager::~OutgoingFileTransferManager() { delete idGenerator; } -boost::shared_ptr<OutgoingFileTransfer> OutgoingFileTransferManager::createOutgoingFileTransfer(const JID& from, const JID& receipient, boost::shared_ptr<ReadBytestream> readBytestream, const StreamInitiationFileInfo& fileInfo) { - // check if receipient support Jingle FT - - - JingleSessionImpl::ref jingleSession = boost::make_shared<JingleSessionImpl>(from, receipient, idGenerator->generateID(), iqRouter); - - //jsManager->getSession(receipient, idGenerator->generateID()); - assert(jingleSession); - jsManager->registerOutgoingSession(from, jingleSession); - boost::shared_ptr<OutgoingJingleFileTransfer> jingleFT = boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(jingleSession, remoteFactory, localFactory, iqRouter, idGenerator, from, receipient, readBytestream, fileInfo, bytestreamRegistry, bytestreamProxy)); - - // otherwise try SI - - // else fail - - return jingleFT; +boost::shared_ptr<OutgoingFileTransfer> OutgoingFileTransferManager::createOutgoingFileTransfer( + const JID& from, + const JID& recipient, + boost::shared_ptr<ReadBytestream> readBytestream, + const StreamInitiationFileInfo& fileInfo, + const FileTransferOptions& config) { + JingleSessionImpl::ref jingleSession = boost::make_shared<JingleSessionImpl>( + from, recipient, idGenerator->generateID(), iqRouter); + jingleSessionManager->registerOutgoingSession(from, jingleSession); + return boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer( + recipient, + jingleSession, + readBytestream, + transporterFactory, + idGenerator, + fileInfo, + config, + crypto)); } } diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.h b/Swiften/FileTransfer/OutgoingFileTransferManager.h index c686001..17a489d 100644 --- a/Swiften/FileTransfer/OutgoingFileTransferManager.h +++ b/Swiften/FileTransfer/OutgoingFileTransferManager.h @@ -4,43 +4,49 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once #include <boost/shared_ptr.hpp> -#include <Swiften/JID/JID.h> - namespace Swift { - -class JingleSessionManager; -class IQRouter; -class EntityCapsProvider; -class RemoteJingleTransportCandidateSelectorFactory; -class LocalJingleTransportCandidateGeneratorFactory; -class OutgoingFileTransfer; -class JID; -class IDGenerator; -class ReadBytestream; -class StreamInitiationFileInfo; -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; - -class OutgoingFileTransferManager { -public: - OutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy); - ~OutgoingFileTransferManager(); - - boost::shared_ptr<OutgoingFileTransfer> createOutgoingFileTransfer(const JID& from, const JID& to, boost::shared_ptr<ReadBytestream>, const StreamInitiationFileInfo&); - -private: - JingleSessionManager* jsManager; - IQRouter* iqRouter; - EntityCapsProvider* capsProvider; - RemoteJingleTransportCandidateSelectorFactory* remoteFactory; - LocalJingleTransportCandidateGeneratorFactory* localFactory; - IDGenerator *idGenerator; - SOCKS5BytestreamRegistry* bytestreamRegistry; - SOCKS5BytestreamProxy* bytestreamProxy; -}; - + class JingleSessionManager; + class IQRouter; + class FileTransferTransporterFactory; + class OutgoingFileTransfer; + class JID; + class IDGenerator; + class ReadBytestream; + class StreamInitiationFileInfo; + class CryptoProvider; + class FileTransferOptions; + + class OutgoingFileTransferManager { + public: + OutgoingFileTransferManager( + JingleSessionManager* jingleSessionManager, + IQRouter* router, + FileTransferTransporterFactory* transporterFactory, + CryptoProvider* crypto); + ~OutgoingFileTransferManager(); + + boost::shared_ptr<OutgoingFileTransfer> createOutgoingFileTransfer( + const JID& from, + const JID& to, + boost::shared_ptr<ReadBytestream>, + const StreamInitiationFileInfo&, + const FileTransferOptions&); + + private: + JingleSessionManager* jingleSessionManager; + IQRouter* iqRouter; + FileTransferTransporterFactory* transporterFactory; + IDGenerator* idGenerator; + CryptoProvider* crypto; + }; } diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp index e22260e..7bcee4b 100644 --- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp @@ -4,399 +4,340 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ -#include "OutgoingJingleFileTransfer.h" +/* + * Copyright (C) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +// TODO: +// - We should handle incoming terminates after we have terminated, so the other +// side can warn that he didn't receive all bytes correctly. +// - Should the proby stuff also wait for candidate used acknowledgement? + +#include <Swiften/FileTransfer/OutgoingJingleFileTransfer.h> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> +#include <boost/typeof/typeof.hpp> -#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/foreach.h> #include <Swiften/Base/IDGenerator.h> #include <Swiften/Jingle/JingleContentID.h> +#include <Swiften/Jingle/JingleSession.h> #include <Swiften/Elements/JingleFileTransferDescription.h> #include <Swiften/Elements/JingleFileTransferHash.h> #include <Swiften/Elements/JingleTransportPayload.h> #include <Swiften/Elements/JingleIBBTransportPayload.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/Queries/GenericRequest.h> -#include <Swiften/FileTransfer/IBBSendSession.h> #include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.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/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/FileTransfer/FileTransferTransporter.h> +#include <Swiften/FileTransfer/FileTransferTransporterFactory.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/FileTransfer/TransportSession.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/Base/Log.h> -namespace Swift { - -OutgoingJingleFileTransfer::OutgoingJingleFileTransfer(JingleSession::ref session, - RemoteJingleTransportCandidateSelectorFactory* remoteFactory, - LocalJingleTransportCandidateGeneratorFactory* localFactory, - IQRouter* router, - IDGenerator *idGenerator, - const JID& fromJID, - const JID& toJID, - boost::shared_ptr<ReadBytestream> readStream, - const StreamInitiationFileInfo &fileInfo, - SOCKS5BytestreamRegistry* bytestreamRegistry, - SOCKS5BytestreamProxy* bytestreamProxy) : - session(session), router(router), idGenerator(idGenerator), fromJID(fromJID), toJID(toJID), readStream(readStream), fileInfo(fileInfo), s5bRegistry(bytestreamRegistry), s5bProxy(bytestreamProxy), serverSession(NULL), contentID(JingleContentID(idGenerator->generateID(), JingleContentPayload::InitiatorCreator)), canceled(false) { - session->onSessionAcceptReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleSessionAcceptReceived, this, _1, _2, _3)); - session->onSessionTerminateReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleSessionTerminateReceived, this, _1)); - session->onTransportInfoReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2)); - session->onTransportAcceptReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransportAcceptReceived, this, _1, _2)); - fileSizeInBytes = fileInfo.getSize(); - filename = fileInfo.getName(); - - localCandidateGenerator = localFactory->createCandidateGenerator(); - localCandidateGenerator->onLocalTransportCandidatesGenerated.connect(boost::bind(&OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1)); - - remoteCandidateSelector = remoteFactory->createCandidateSelector(); - remoteCandidateSelector->onRemoteTransportCandidateSelectFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1)); +using namespace Swift; + +static const int DEFAULT_BLOCK_SIZE = 4096; + +OutgoingJingleFileTransfer::OutgoingJingleFileTransfer( + const JID& toJID, + JingleSession::ref session, + boost::shared_ptr<ReadBytestream> stream, + FileTransferTransporterFactory* transporterFactory, + IDGenerator* idGenerator, + const StreamInitiationFileInfo& fileInfo, + const FileTransferOptions& options, + CryptoProvider* crypto) : + JingleFileTransfer(session, toJID, transporterFactory), + idGenerator(idGenerator), + stream(stream), + fileInfo(fileInfo), + options(options), + contentID(idGenerator->generateID(), JingleContentPayload::InitiatorCreator), + state(Initial), + candidateAcknowledged(false) { + + setFileInfo(fileInfo.getName(), fileInfo.getSize()); + // calculate both, MD5 and SHA-1 since we don't know which one the other side supports - hashCalculator = new IncrementalBytestreamHashCalculator(true, true); - this->readStream->onRead.connect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); + hashCalculator = new IncrementalBytestreamHashCalculator(true, true, crypto); + stream->onRead.connect( + boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); } OutgoingJingleFileTransfer::~OutgoingJingleFileTransfer() { - readStream->onRead.disconnect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); + stream->onRead.disconnect( + boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); delete hashCalculator; } void OutgoingJingleFileTransfer::start() { - onStateChange(FileTransfer::State(FileTransfer::State::WaitingForStart)); - - s5bSessionID = s5bRegistry->generateSessionID(); - SWIFT_LOG(debug) << "S5B SessionID: " << s5bSessionID << std::endl; - - //s5bProxy->connectToProxies(s5bSessionID); + SWIFT_LOG(debug) << std::endl; + if (state != Initial) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } - JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); - localCandidateGenerator->generateLocalTransportCandidates(transport); + setTransporter(transporterFactory->createInitiatorTransporter(getInitiator(), getResponder())); + setState(GeneratingInitialLocalCandidates); + transporter->startGeneratingLocalCandidates(); } -void OutgoingJingleFileTransfer::stop() { - +void OutgoingJingleFileTransfer::cancel() { + terminate(JinglePayload::Reason::Cancel); } -void OutgoingJingleFileTransfer::cancel() { - canceled = true; - session->sendTerminate(JinglePayload::Reason::Cancel); +void OutgoingJingleFileTransfer::terminate(JinglePayload::Reason::Type reason) { + SWIFT_LOG(debug) << reason << std::endl; - if (ibbSession) { - ibbSession->stop(); + if (state != Initial && state != GeneratingInitialLocalCandidates && state != Finished) { + session->sendTerminate(reason); } - SOCKS5BytestreamServerSession *serverSession = s5bRegistry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); - if (serverSession) { - serverSession->stop(); - } - if (clientSession) { - clientSession->stop(); - } - onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); + stopAll(); + setFinishedState(getExternalFinishedState(reason), getFileTransferError(reason)); } -void OutgoingJingleFileTransfer::handleSessionAcceptReceived(const JingleContentID& id, JingleDescription::ref /* decription */, JingleTransportPayload::ref transportPayload) { - if (canceled) { - return; - } - onStateChange(FileTransfer::State(FileTransfer::State::Negotiating)); - - JingleIBBTransportPayload::ref ibbPayload; - JingleS5BTransportPayload::ref s5bPayload; - if ((ibbPayload = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transportPayload))) { - ibbSession = boost::make_shared<IBBSendSession>(ibbPayload->getSessionID(), fromJID, toJID, readStream, router); - ibbSession->setBlockSize(ibbPayload->getBlockSize()); - ibbSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - ibbSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - ibbSession->start(); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } - else if ((s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload))) { - fillCandidateMap(theirCandidates, s5bPayload); - remoteCandidateSelector->setRequesterTargtet(toJID, session->getInitiator()); - remoteCandidateSelector->addRemoteTransportCandidates(s5bPayload); - remoteCandidateSelector->selectCandidate(); +void OutgoingJingleFileTransfer::handleSessionAcceptReceived( + const JingleContentID&, + JingleDescription::ref, + JingleTransportPayload::ref transportPayload) { + SWIFT_LOG(debug) << std::endl; + 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()); + setState(TryingCandidates); + transporter->startTryingRemoteCandidates(); } else { - // TODO: error handling - SWIFT_LOG(debug) << "Unknown transport payload! Try replaceing with IBB." << std::endl; - replaceTransportWithIBB(id); + SWIFT_LOG(debug) << "Unknown transport payload. Falling back." << std::endl; + fallback(); } } void OutgoingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) { - if (canceled) { - return; - } + SWIFT_LOG(debug) << std::endl; + if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } - if (ibbSession) { - ibbSession->stop(); - } - if (clientSession) { - clientSession->stop(); + stopAll(); + if (reason && reason->type == JinglePayload::Reason::Cancel) { + setFinishedState(FileTransfer::State::Canceled, FileTransferError(FileTransferError::PeerError)); } - if (serverSession) { - serverSession->stop(); - } - - if (reason.is_initialized() && reason.get().type == JinglePayload::Reason::Cancel) { - onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); - onFinished(FileTransferError(FileTransferError::PeerError)); - } else if (reason.is_initialized() && reason.get().type == JinglePayload::Reason::Success) { - onStateChange(FileTransfer::State(FileTransfer::State::Finished)); - onFinished(boost::optional<FileTransferError>()); - } else { - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); - onFinished(FileTransferError(FileTransferError::PeerError)); + else if (reason && reason->type == JinglePayload::Reason::Success) { + setFinishedState(FileTransfer::State::Finished, boost::optional<FileTransferError>()); + } + else { + setFinishedState(FileTransfer::State::Failed, FileTransferError(FileTransferError::PeerError)); } - canceled = true; } -void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { - if (canceled) { - return; - } +void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleContentID&, JingleTransportPayload::ref transport) { + SWIFT_LOG(debug) << std::endl; + if (state != FallbackRequested) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } if (JingleIBBTransportPayload::ref ibbPayload = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { - ibbSession = boost::make_shared<IBBSendSession>(ibbPayload->getSessionID(), fromJID, toJID, readStream, router); - ibbSession->setBlockSize(ibbPayload->getBlockSize()); - ibbSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - ibbSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - ibbSession->start(); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } else { - // error handling - SWIFT_LOG(debug) << "Replacing with anything other than IBB isn't supported yet." << std::endl; - session->sendTerminate(JinglePayload::Reason::FailedTransport); - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); + startTransferring(transporter->createIBBSendSession(ibbPayload->getSessionID(), ibbPayload->getBlockSize().get_value_or(DEFAULT_BLOCK_SIZE), stream)); + } + else { + SWIFT_LOG(debug) << "Unknown transport replacement" << std::endl; + terminate(JinglePayload::Reason::FailedTransport); } } -void OutgoingJingleFileTransfer::startTransferViaOurCandidateChoice(JingleS5BTransportPayload::Candidate candidate) { - SWIFT_LOG(debug) << "Transferring data using our candidate." << std::endl; - if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { - // get proxy client session from remoteCandidateSelector - clientSession = remoteCandidateSelector->getS5BSession(); - - // wait on <activated/> transport-info - } else { - clientSession = remoteCandidateSelector->getS5BSession(); - clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startSending(readStream); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } - assert(clientSession); -} +void OutgoingJingleFileTransfer::sendSessionInfoHash() { + SWIFT_LOG(debug) << std::endl; -void OutgoingJingleFileTransfer::startTransferViaTheirCandidateChoice(JingleS5BTransportPayload::Candidate candidate) { - SWIFT_LOG(debug) << "Transferring data using their candidate." << std::endl; - if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { - // connect to proxy - clientSession = s5bProxy->createSOCKS5BytestreamClientSession(candidate.hostPort, SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); - clientSession->onSessionReady.connect(boost::bind(&OutgoingJingleFileTransfer::proxySessionReady, this, candidate.jid, _1)); - clientSession->start(); - - // on reply send activate - - } else { - serverSession = s5bRegistry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); - serverSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - serverSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - serverSession->startTransfer(); - } - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + JingleFileTransferHash::ref hashElement = boost::make_shared<JingleFileTransferHash>(); + hashElement->setHash("sha-1", hashCalculator->getSHA1String()); + hashElement->setHash("md5", hashCalculator->getMD5String()); + session->sendInfo(hashElement); } -// decide on candidates according to http://xmpp.org/extensions/xep-0260.html#complete -void OutgoingJingleFileTransfer::decideOnCandidates() { - if (ourCandidateChoice && theirCandidateChoice) { - std::string our_cid = ourCandidateChoice->getCandidateUsed(); - std::string their_cid = theirCandidateChoice->getCandidateUsed(); - if (ourCandidateChoice->hasCandidateError() && theirCandidateChoice->hasCandidateError()) { - replaceTransportWithIBB(contentID); - } - else if (!our_cid.empty() && theirCandidateChoice->hasCandidateError()) { - // use our candidate - startTransferViaOurCandidateChoice(theirCandidates[our_cid]); - } - else if (!their_cid.empty() && ourCandidateChoice->hasCandidateError()) { - // use their candidate - startTransferViaTheirCandidateChoice(ourCandidates[their_cid]); - } - else if (!our_cid.empty() && !their_cid.empty()) { - // compare priorites, if same we 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::Failed)); - onFinished(FileTransferError(FileTransferError::PeerError)); - return; - } - - JingleS5BTransportPayload::Candidate ourCandidate = theirCandidates[our_cid]; - JingleS5BTransportPayload::Candidate theirCandidate = ourCandidates[their_cid]; - if (ourCandidate.priority > theirCandidate.priority) { - startTransferViaOurCandidateChoice(ourCandidate); - } - else if (ourCandidate.priority < theirCandidate.priority) { - startTransferViaTheirCandidateChoice(theirCandidate); - } - else { - startTransferViaOurCandidateChoice(ourCandidate); - } - } - } else { - SWIFT_LOG(debug) << "Can't make a decision yet!" << std::endl; +void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated( + const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + SWIFT_LOG(debug) << std::endl; + if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + fillCandidateMap(localCandidates, candidates); + + JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>(); + description->addOffer(fileInfo); + + JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); + transport->setSessionID(s5bSessionID); + transport->setMode(JingleS5BTransportPayload::TCPMode); + foreach(JingleS5BTransportPayload::Candidate candidate, candidates) { + transport->addCandidate(candidate); } + setState(WaitingForAccept); + session->sendInitiate(contentID, description, transport); } -void OutgoingJingleFileTransfer::fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload) { - map.clear(); - foreach (JingleS5BTransportPayload::Candidate candidate, s5bPayload->getCandidates()) { - map[candidate.cid] = candidate; +void OutgoingJingleFileTransfer::fallback() { + SWIFT_LOG(debug) << std::endl; + if (options.isInBandAllowed()) { + JingleIBBTransportPayload::ref ibbTransport = boost::make_shared<JingleIBBTransportPayload>(); + ibbTransport->setBlockSize(DEFAULT_BLOCK_SIZE); + ibbTransport->setSessionID(idGenerator->generateID()); + setState(FallbackRequested); + session->sendTransportReplace(contentID, ibbTransport); + } + else { + terminate(JinglePayload::Reason::ConnectivityError); } } -void OutgoingJingleFileTransfer::proxySessionReady(const JID& proxy, bool error) { +void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { + SWIFT_LOG(debug) << std::endl; + if (state != Transferring) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + if (error) { - // indicate proxy error - } else { - // activate proxy - activateProxySession(proxy); + terminate(JinglePayload::Reason::ConnectivityError); + } + else { + sendSessionInfoHash(); + terminate(JinglePayload::Reason::Success); } } -void OutgoingJingleFileTransfer::activateProxySession(const JID& proxy) { - S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); - proxyRequest->setSID(s5bSessionID); - proxyRequest->setActivate(toJID); +void OutgoingJingleFileTransfer::startTransferring(boost::shared_ptr<TransportSession> transportSession) { + SWIFT_LOG(debug) << std::endl; - 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(); + this->transportSession = transportSession; + processedBytesConnection = transportSession->onBytesSent.connect( + boost::bind(boost::ref(onProcessedBytes), _1)); + transferFinishedConnection = transportSession->onFinished.connect( + boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + setState(Transferring); + transportSession->start(); } -void OutgoingJingleFileTransfer::handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> /*request*/, ErrorPayload::ref error) { - if (error) { - SWIFT_LOG(debug) << "ERROR" << std::endl; - } else { - // send activated to other jingle party - JingleS5BTransportPayload::ref proxyActivate = boost::make_shared<JingleS5BTransportPayload>(); - proxyActivate->setActivated(theirCandidateChoice->getCandidateUsed()); - session->sendTransportInfo(contentID, proxyActivate); - - // start transferring - clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startSending(readStream); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } + +void OutgoingJingleFileTransfer::setState(State state) { + SWIFT_LOG(debug) << state << std::endl; + this->state = state; + onStateChanged(FileTransfer::State(getExternalState(state))); } -void OutgoingJingleFileTransfer::sendSessionInfoHash() { +void OutgoingJingleFileTransfer::setFinishedState( + FileTransfer::State::Type type, const boost::optional<FileTransferError>& error) { SWIFT_LOG(debug) << std::endl; - JingleFileTransferHash::ref hashElement = boost::make_shared<JingleFileTransferHash>(); - hashElement->setHash("sha-1", hashCalculator->getSHA1String()); - hashElement->setHash("md5", hashCalculator->getMD5String()); - session->sendInfo(hashElement); + this->state = Finished; + onStateChanged(type); + onFinished(error); } -void OutgoingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { - if (canceled) { - return; - } - if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { - if (s5bPayload->hasCandidateError() || !s5bPayload->getCandidateUsed().empty()) { - theirCandidateChoice = s5bPayload; - decideOnCandidates(); - } else if(!s5bPayload->getActivated().empty()) { - if (ourCandidateChoice->getCandidateUsed() == s5bPayload->getActivated()) { - clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startSending(readStream); - 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(contentID, proxyError); - } - } +FileTransfer::State::Type OutgoingJingleFileTransfer::getExternalState(State state) { + switch (state) { + case Initial: return FileTransfer::State::Initial; + case GeneratingInitialLocalCandidates: return FileTransfer::State::WaitingForStart; + case WaitingForAccept: return FileTransfer::State::WaitingForAccept; + case TryingCandidates: return FileTransfer::State::Negotiating; + case WaitingForPeerProxyActivate: return FileTransfer::State::Negotiating; + case WaitingForLocalProxyActivate: return FileTransfer::State::Negotiating; + case WaitingForCandidateAcknowledge: return FileTransfer::State::Negotiating; + case FallbackRequested: return FileTransfer::State::Negotiating; + case Transferring: return FileTransfer::State::Transferring; + case Finished: return FileTransfer::State::Finished; } + assert(false); + return FileTransfer::State::Initial; } -void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { - if (canceled) { - return; +void OutgoingJingleFileTransfer::stopAll() { + SWIFT_LOG(debug) << state << std::endl; + switch (state) { + case Initial: SWIFT_LOG(warning) << "Not yet started" << std::endl; break; + case GeneratingInitialLocalCandidates: transporter->stopGeneratingLocalCandidates(); break; + case WaitingForAccept: break; + case TryingCandidates: transporter->stopTryingRemoteCandidates(); break; + case FallbackRequested: break; + case WaitingForPeerProxyActivate: break; + case WaitingForLocalProxyActivate: transporter->stopActivatingProxy(); break; + case WaitingForCandidateAcknowledge: // Fallthrough + case Transferring: + assert(transportSession); + processedBytesConnection.disconnect(); + transferFinishedConnection.disconnect(); + transportSession->stop(); + transportSession.reset(); + break; + case Finished: SWIFT_LOG(warning) << "Already finished" << std::endl; break; } - JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>(); - description->addOffer(fileInfo); + if (state != Initial) { + delete transporter; + } +} - JingleTransportPayload::ref transport; - if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(payload)) { - ibbTransport->setBlockSize(4096); - ibbTransport->setSessionID(idGenerator->generateID()); - transport = ibbTransport; +void OutgoingJingleFileTransfer::startTransferViaRemoteCandidate() { + SWIFT_LOG(debug) << std::endl; + + if (ourCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { + setState(WaitingForPeerProxyActivate); + } + else { + transportSession = createRemoteCandidateSession(); + startTransferringIfCandidateAcknowledged(); } - else if (JingleS5BTransportPayload::ref s5bTransport = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(payload)) { - //fillCandidateMap(ourCandidates, s5bTransport); - //s5bTransport->setSessionID(s5bSessionID); +} - JingleS5BTransportPayload::ref emptyCandidates = boost::make_shared<JingleS5BTransportPayload>(); - emptyCandidates->setSessionID(s5bTransport->getSessionID()); - fillCandidateMap(ourCandidates, emptyCandidates); +void OutgoingJingleFileTransfer::startTransferViaLocalCandidate() { + SWIFT_LOG(debug) << std::endl; - transport = emptyCandidates; - s5bRegistry->addReadBytestream(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID), readStream); + if (theirCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { + setState(WaitingForLocalProxyActivate); + transporter->startActivatingProxy(theirCandidateChoice->jid); + } + else { + transportSession = createLocalCandidateSession(); + startTransferringIfCandidateAcknowledged(); + } +} + +void OutgoingJingleFileTransfer::startTransferringIfCandidateAcknowledged() { + if (candidateAcknowledged) { + startTransferring(transportSession); } else { - SWIFT_LOG(debug) << "Unknown tranport payload: " << typeid(*payload).name() << std::endl; - return; + setState(WaitingForCandidateAcknowledge); } - session->sendInitiate(contentID, description, transport); - onStateChange(FileTransfer::State(FileTransfer::State::WaitingForAccept)); } -void OutgoingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref payload) { - if (canceled) { - return; +void OutgoingJingleFileTransfer::handleTransportInfoAcknowledged(const std::string& id) { + if (id == candidateSelectRequestID) { + candidateAcknowledged = true; } - if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(payload)) { - ourCandidateChoice = s5bPayload; - session->sendTransportInfo(contentID, s5bPayload); - decideOnCandidates(); + if (state == WaitingForCandidateAcknowledge) { + startTransferring(transportSession); } } -void OutgoingJingleFileTransfer::replaceTransportWithIBB(const JingleContentID& id) { - SWIFT_LOG(debug) << "Both parties failed. Replace transport with IBB." << std::endl; - JingleIBBTransportPayload::ref ibbTransport = boost::make_shared<JingleIBBTransportPayload>(); - ibbTransport->setBlockSize(4096); - ibbTransport->setSessionID(idGenerator->generateID()); - session->sendTransportReplace(id, ibbTransport); +JingleContentID OutgoingJingleFileTransfer::getContentID() const { + return contentID; } -void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { - if (error) { - session->sendTerminate(JinglePayload::Reason::ConnectivityError); - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); - onFinished(error); - } else { - sendSessionInfoHash(); - /* - session->terminate(JinglePayload::Reason::Success); - onStateChange(FileTransfer::State(FileTransfer::State::Finished)); - */ - } - // +bool OutgoingJingleFileTransfer::hasPriorityOnCandidateTie() const { + return true; +} + +bool OutgoingJingleFileTransfer::isWaitingForPeerProxyActivate() const { + return state == WaitingForPeerProxyActivate; +} + +bool OutgoingJingleFileTransfer::isWaitingForLocalProxyActivate() const { + return state == WaitingForLocalProxyActivate; } +bool OutgoingJingleFileTransfer::isTryingCandidates() const { + return state == TryingCandidates; } + +boost::shared_ptr<TransportSession> OutgoingJingleFileTransfer::createLocalCandidateSession() { + return transporter->createLocalCandidateSession(stream); +} + +boost::shared_ptr<TransportSession> OutgoingJingleFileTransfer::createRemoteCandidateSession() { + return transporter->createRemoteCandidateSession(stream); +} + diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h index e18b5c3..d1f4dc4 100644 --- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h @@ -4,113 +4,110 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once #include <boost/shared_ptr.hpp> +#include <boost/optional/optional.hpp> #include <Swiften/Base/API.h> -#include <Swiften/Elements/JingleContentPayload.h> -#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Base/Override.h> +#include <Swiften/Jingle/JingleContentID.h> #include <Swiften/Elements/StreamInitiationFileInfo.h> -#include <Swiften/Elements/S5BProxyRequest.h> -#include <Swiften/Elements/ErrorPayload.h> #include <Swiften/FileTransfer/OutgoingFileTransfer.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> -#include <Swiften/Jingle/JingleContentID.h> -#include <Swiften/Jingle/JingleSession.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/FileTransfer/JingleFileTransfer.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> namespace Swift { - -class RemoteJingleTransportCandidateSelectorFactory; -class RemoteJingleTransportCandidateSelector; -class LocalJingleTransportCandidateGeneratorFactory; -class LocalJingleTransportCandidateGenerator; -class IQRouter; -class ReadBytestream; -class IBBSendSession; -class IDGenerator; -class IncrementalBytestreamHashCalculator; -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; - -class SWIFTEN_API OutgoingJingleFileTransfer : public OutgoingFileTransfer { -public: - OutgoingJingleFileTransfer(JingleSession::ref, - RemoteJingleTransportCandidateSelectorFactory*, - LocalJingleTransportCandidateGeneratorFactory*, - IQRouter*, - IDGenerator*, - const JID& from, - const JID& to, - boost::shared_ptr<ReadBytestream>, - const StreamInitiationFileInfo&, - SOCKS5BytestreamRegistry*, - SOCKS5BytestreamProxy*); - virtual ~OutgoingJingleFileTransfer(); - - void start(); - void stop(); - - void cancel(); - -private: - void handleSessionAcceptReceived(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref); - void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason); - void handleTransportAcceptReceived(const JingleContentID&, JingleTransportPayload::ref); - void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref); - - void handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref); - void handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref); - -private: - void replaceTransportWithIBB(const JingleContentID&); - void handleTransferFinished(boost::optional<FileTransferError>); - void activateProxySession(const JID &proxy); - void handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error); - void proxySessionReady(const JID& proxy, bool error); - -private: - typedef std::map<std::string, JingleS5BTransportPayload::Candidate> CandidateMap; - -private: - void startTransferViaOurCandidateChoice(JingleS5BTransportPayload::Candidate); - void startTransferViaTheirCandidateChoice(JingleS5BTransportPayload::Candidate); - void decideOnCandidates(); - void fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload); - -private: - void sendSessionInfoHash(); - -private: - JingleSession::ref session; - RemoteJingleTransportCandidateSelector* remoteCandidateSelector; - LocalJingleTransportCandidateGenerator* localCandidateGenerator; - - IQRouter* router; - IDGenerator* idGenerator; - JID fromJID; - JID toJID; - boost::shared_ptr<ReadBytestream> readStream; - StreamInitiationFileInfo fileInfo; - IncrementalBytestreamHashCalculator *hashCalculator; - - boost::shared_ptr<IBBSendSession> ibbSession; - - JingleS5BTransportPayload::ref ourCandidateChoice; - JingleS5BTransportPayload::ref theirCandidateChoice; - CandidateMap ourCandidates; - CandidateMap theirCandidates; - - SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; - SOCKS5BytestreamClientSession::ref clientSession; - SOCKS5BytestreamServerSession* serverSession; - JingleContentID contentID; - std::string s5bSessionID; - - bool canceled; -}; + class ReadBytestream; + class IDGenerator; + class IncrementalBytestreamHashCalculator; + class CryptoProvider; + class FileTransferTransporter; + class FileTransferTransporterFactory; + class TransportSession; + + class SWIFTEN_API OutgoingJingleFileTransfer : public OutgoingFileTransfer, public JingleFileTransfer { + public: + OutgoingJingleFileTransfer( + const JID& to, + boost::shared_ptr<JingleSession>, + boost::shared_ptr<ReadBytestream>, + FileTransferTransporterFactory*, + IDGenerator*, + const StreamInitiationFileInfo&, + const FileTransferOptions&, + CryptoProvider*); + virtual ~OutgoingJingleFileTransfer(); + + void start(); + void cancel(); + + private: + enum State { + Initial, + GeneratingInitialLocalCandidates, + WaitingForAccept, + TryingCandidates, + WaitingForPeerProxyActivate, + WaitingForLocalProxyActivate, + WaitingForCandidateAcknowledge, + FallbackRequested, + Transferring, + Finished + }; + + 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; + void startTransferViaRemoteCandidate(); + void startTransferViaLocalCandidate(); + void startTransferringIfCandidateAcknowledged(); + + virtual void handleLocalTransportCandidatesGenerated(const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE; + virtual void handleTransportInfoAcknowledged(const std::string& id) SWIFTEN_OVERRIDE; + + virtual JingleContentID getContentID() const SWIFTEN_OVERRIDE; + + virtual void terminate(JinglePayload::Reason::Type reason) SWIFTEN_OVERRIDE; + + virtual void fallback() SWIFTEN_OVERRIDE; + void handleTransferFinished(boost::optional<FileTransferError>); + + void sendSessionInfoHash(); + + virtual void startTransferring(boost::shared_ptr<TransportSession>) SWIFTEN_OVERRIDE; + + virtual bool hasPriorityOnCandidateTie() const SWIFTEN_OVERRIDE; + virtual bool isWaitingForPeerProxyActivate() const SWIFTEN_OVERRIDE; + virtual bool isWaitingForLocalProxyActivate() const SWIFTEN_OVERRIDE; + virtual bool isTryingCandidates() const SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession() SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession() SWIFTEN_OVERRIDE; + + void stopAll(); + void setState(State state); + void setFinishedState(FileTransfer::State::Type, const boost::optional<FileTransferError>& error); + + static FileTransfer::State::Type getExternalState(State state); + + private: + IDGenerator* idGenerator; + boost::shared_ptr<ReadBytestream> stream; + StreamInitiationFileInfo fileInfo; + FileTransferOptions options; + JingleContentID contentID; + IncrementalBytestreamHashCalculator* hashCalculator; + State state; + bool candidateAcknowledged; + + boost::bsignals::connection processedBytesConnection; + boost::bsignals::connection transferFinishedConnection; + }; } diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp index fc0a551..1c60469 100644 --- a/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp +++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -16,10 +16,11 @@ namespace Swift { -OutgoingSIFileTransfer::OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) { +OutgoingSIFileTransfer::OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, unsigned long long size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) { } void OutgoingSIFileTransfer::start() { + /* StreamInitiation::ref streamInitiation(new StreamInitiation()); streamInitiation->setID(id); streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size)); @@ -28,12 +29,14 @@ void OutgoingSIFileTransfer::start() { StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter); request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2)); request->send(); + */ } void OutgoingSIFileTransfer::stop() { } -void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) { +void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref) { + /* if (error) { finish(FileTransferError()); } @@ -54,26 +57,31 @@ void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiat ibbSession->start(); } } + */ } -void OutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) { +void OutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref) { + /* if (error) { finish(FileTransferError()); } + */ //socksServer->onTransferFinished.connect(); } -void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError> error) { +void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError>) { + /* if (ibbSession) { ibbSession->onFinished.disconnect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); ibbSession.reset(); } socksServer->removeReadBytestream(id, from, to); onFinished(error); + */ } -void OutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) { - finish(error); +void OutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError>) { + //finish(error); } } diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.h b/Swiften/FileTransfer/OutgoingSIFileTransfer.h index 584eb60..79da339 100644 --- a/Swiften/FileTransfer/OutgoingSIFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -25,7 +25,7 @@ namespace Swift { class OutgoingSIFileTransfer : public OutgoingFileTransfer { public: - OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer); + OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, unsigned long long size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer); virtual void start(); virtual void stop(); @@ -43,7 +43,7 @@ namespace Swift { JID from; JID to; std::string name; - int size; + unsigned long long size; std::string description; boost::shared_ptr<ReadBytestream> bytestream; IQRouter* iqRouter; diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp index 338f221..1e96b22 100644 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp @@ -1,14 +1,95 @@ /* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. */ #include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -namespace Swift { +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> + +using namespace Swift; + +RemoteJingleTransportCandidateSelector::RemoteJingleTransportCandidateSelector( + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory) : + connectionFactory(connectionFactory), + timerFactory(timerFactory) { +} RemoteJingleTransportCandidateSelector::~RemoteJingleTransportCandidateSelector() { } +void RemoteJingleTransportCandidateSelector::addCandidates( + const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + foreach(JingleS5BTransportPayload::Candidate c, candidates) { + this->candidates.push(c); + } +} + +void RemoteJingleTransportCandidateSelector::startSelectingCandidate() { + tryNextCandidate(); +} + +void RemoteJingleTransportCandidateSelector::stopSelectingCandidate() { + if (s5bSession) { + sessionReadyConnection.disconnect(); + s5bSession->stop(); + } +} + +void RemoteJingleTransportCandidateSelector::tryNextCandidate() { + if (candidates.empty()) { + SWIFT_LOG(debug) << "No more candidates" << std::endl; + onCandidateSelectFinished( + boost::optional<JingleS5BTransportPayload::Candidate>(), boost::shared_ptr<SOCKS5BytestreamClientSession>()); + } + else { + lastCandidate = candidates.top(); + candidates.pop(); + SWIFT_LOG(debug) << "Trying candidate " << lastCandidate.cid << std::endl; + if (lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType + || lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType + || lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType ) { + boost::shared_ptr<Connection> connection = connectionFactory->createConnection(); + s5bSession = boost::make_shared<SOCKS5BytestreamClientSession>( + connection, lastCandidate.hostPort, socks5DstAddr, timerFactory); + sessionReadyConnection = s5bSession->onSessionReady.connect( + boost::bind(&RemoteJingleTransportCandidateSelector::handleSessionReady, this, _1)); + s5bSession->start(); + } + else { + SWIFT_LOG(debug) << "Can't handle this type of candidate" << std::endl; + tryNextCandidate(); + } + } +} + +void RemoteJingleTransportCandidateSelector::handleSessionReady(bool error) { + sessionReadyConnection.disconnect(); + if (error) { + s5bSession.reset(); + tryNextCandidate(); + } + else { + onCandidateSelectFinished(lastCandidate, s5bSession); + } +} + +void RemoteJingleTransportCandidateSelector::setSOCKS5DstAddr(const std::string& socks5DstAddr) { + this->socks5DstAddr = socks5DstAddr; } diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h index 487747c..66ab4b2 100644 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h @@ -1,34 +1,61 @@ /* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. */ #pragma once -#include <Swiften/Base/boost_bsignals.h> +#include <queue> +#include <vector> + +#include <boost/shared_ptr.hpp> -#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> #include <Swiften/JID/JID.h> -#include <Swiften/Elements/JingleTransportPayload.h> -#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/Network/Connection.h> #include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> + namespace Swift { - class SWIFTEN_API RemoteJingleTransportCandidateSelector { + class ConnectionFactory; + class TimerFactory; + + class RemoteJingleTransportCandidateSelector { public: + RemoteJingleTransportCandidateSelector(ConnectionFactory*, TimerFactory*); virtual ~RemoteJingleTransportCandidateSelector(); - virtual void addRemoteTransportCandidates(JingleTransportPayload::ref) = 0; - virtual void selectCandidate() = 0; - virtual void setMinimumPriority(int) = 0; - virtual void setRequesterTargtet(const JID&, const JID&) {} - virtual SOCKS5BytestreamClientSession::ref getS5BSession() { return SOCKS5BytestreamClientSession::ref(); } + virtual void addCandidates(const std::vector<JingleS5BTransportPayload::Candidate>&); + virtual void setSOCKS5DstAddr(const std::string&); + virtual void startSelectingCandidate(); + virtual void stopSelectingCandidate(); + + boost::signal<void (const boost::optional<JingleS5BTransportPayload::Candidate>&, boost::shared_ptr<SOCKS5BytestreamClientSession>)> onCandidateSelectFinished; + + private: + void tryNextCandidate(); + void handleSessionReady(bool error); - virtual bool isActualCandidate(JingleTransportPayload::ref) = 0; - virtual int getPriority(JingleTransportPayload::ref) = 0; - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0; + private: + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; - boost::signal<void (JingleTransportPayload::ref)> onRemoteTransportCandidateSelectFinished; - }; + std::priority_queue< + JingleS5BTransportPayload::Candidate, + std::vector<JingleS5BTransportPayload::Candidate>, + JingleS5BTransportPayload::CompareCandidate> candidates; + boost::shared_ptr<SOCKS5BytestreamClientSession> s5bSession; + boost::bsignals::connection sessionReadyConnection; + JingleS5BTransportPayload::Candidate lastCandidate; + std::string socks5DstAddr; + }; } diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp deleted file mode 100644 index 36b7cba..0000000 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> - -namespace Swift { - -RemoteJingleTransportCandidateSelectorFactory::~RemoteJingleTransportCandidateSelectorFactory() { -} - -} diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h deleted file mode 100644 index 4980b0c..0000000 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <Swiften/Base/API.h> - -namespace Swift { - class RemoteJingleTransportCandidateSelector; - - class SWIFTEN_API RemoteJingleTransportCandidateSelectorFactory { - public: - virtual ~RemoteJingleTransportCandidateSelectorFactory(); - - virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() = 0; - }; -} diff --git a/Swiften/FileTransfer/SConscript b/Swiften/FileTransfer/SConscript index 4e79992..6c29ea6 100644 --- a/Swiften/FileTransfer/SConscript +++ b/Swiften/FileTransfer/SConscript @@ -1,6 +1,7 @@ Import("swiften_env", "env") sources = [ + "ByteArrayReadBytestream.cpp", "OutgoingFileTransfer.cpp", "OutgoingSIFileTransfer.cpp", "OutgoingJingleFileTransfer.cpp", @@ -8,32 +9,33 @@ sources = [ "IncomingFileTransfer.cpp", "IncomingJingleFileTransfer.cpp", "IncomingFileTransferManager.cpp", + "JingleFileTransfer.cpp", + "FileTransferOptions.cpp", + "FileTransferTransporter.cpp", + "FileTransferTransporterFactory.cpp", + "DefaultFileTransferTransporter.cpp", + "DefaultFileTransferTransporterFactory.cpp", "RemoteJingleTransportCandidateSelector.cpp", - "RemoteJingleTransportCandidateSelectorFactory.cpp", "LocalJingleTransportCandidateGenerator.cpp", - "LocalJingleTransportCandidateGeneratorFactory.cpp", - "DefaultRemoteJingleTransportCandidateSelectorFactory.cpp", - "DefaultLocalJingleTransportCandidateGeneratorFactory.cpp", - "DefaultRemoteJingleTransportCandidateSelector.cpp", - "DefaultLocalJingleTransportCandidateGenerator.cpp", - "JingleTransport.cpp", - "JingleIncomingIBBTransport.cpp", "ReadBytestream.cpp", "WriteBytestream.cpp", "FileReadBytestream.cpp", "FileWriteBytestream.cpp", + "FileTransfer.cpp", + "TransportSession.cpp", "SOCKS5BytestreamClientSession.cpp", + "SOCKS5BytestreamServerInitializeRequest.cpp", + "SOCKS5BytestreamServerManager.cpp", "SOCKS5BytestreamServer.cpp", "SOCKS5BytestreamServerSession.cpp", "SOCKS5BytestreamRegistry.cpp", - "SOCKS5BytestreamProxy.cpp", + "SOCKS5BytestreamProxiesManager.cpp", "SOCKS5BytestreamProxyFinder.cpp", "IBBSendSession.cpp", "IBBReceiveSession.cpp", "FileTransferManager.cpp", "FileTransferManagerImpl.cpp", "IncrementalBytestreamHashCalculator.cpp", - "ConnectivityManager.cpp", ] swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources)) diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp index cd555e5..b371078 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp @@ -4,15 +4,21 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include "SOCKS5BytestreamClientSession.h" #include <boost/bind.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Base/SafeByteArray.h> #include <Swiften/Base/Concat.h> #include <Swiften/Base/Log.h> -#include <Swiften/StringCodecs/SHA1.h> #include <Swiften/StringCodecs/Hexify.h> #include <Swiften/FileTransfer/BytestreamException.h> #include <Swiften/Network/TimerFactory.h> @@ -20,25 +26,39 @@ namespace Swift { -SOCKS5BytestreamClientSession::SOCKS5BytestreamClientSession(boost::shared_ptr<Connection> connection, const HostAddressPort& addressPort, const std::string& destination, TimerFactory* timerFactory) : - connection(connection), addressPort(addressPort), destination(destination), state(Initial), chunkSize(131072) { - connection->onConnectFinished.connect(boost::bind(&SOCKS5BytestreamClientSession::handleConnectFinished, this, _1)); - connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamClientSession::handleDisconnected, this, _1)); +SOCKS5BytestreamClientSession::SOCKS5BytestreamClientSession( + boost::shared_ptr<Connection> connection, + const HostAddressPort& addressPort, + const std::string& destination, + TimerFactory* timerFactory) : + connection(connection), + addressPort(addressPort), + destination(destination), + state(Initial), + chunkSize(131072) { weFailedTimeout = timerFactory->createTimer(2000); - weFailedTimeout->onTick.connect(boost::bind(&SOCKS5BytestreamClientSession::handleWeFailedTimeout, this)); + weFailedTimeout->onTick.connect( + boost::bind(&SOCKS5BytestreamClientSession::handleWeFailedTimeout, this)); +} + +SOCKS5BytestreamClientSession::~SOCKS5BytestreamClientSession() { } void SOCKS5BytestreamClientSession::start() { assert(state == Initial); SWIFT_LOG(debug) << "Trying to connect via TCP to " << addressPort.toString() << "." << std::endl; weFailedTimeout->start(); + connectFinishedConnection = connection->onConnectFinished.connect( + boost::bind(&SOCKS5BytestreamClientSession::handleConnectFinished, this, _1)); connection->connect(addressPort); } void SOCKS5BytestreamClientSession::stop() { - connection->disconnect(); - connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); - connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); + SWIFT_LOG(debug) << std::endl; + if (state == Finished) { + return; + } + closeConnection(); readBytestream.reset(); state = Finished; } @@ -127,7 +147,7 @@ void SOCKS5BytestreamClientSession::authenticate() { SWIFT_LOG(debug) << std::endl; SafeByteArray header = createSafeByteArray("\x05\x01\x00\x03", 4); SafeByteArray message = header; - append(message, createSafeByteArray(destination.size())); + append(message, createSafeByteArray(boost::numeric_cast<char>(destination.size()))); authenticateAddress = createByteArray(destination); append(message, authenticateAddress); append(message, createSafeByteArray("\x00\x00", 2)); // 2 byte for port @@ -151,7 +171,8 @@ void SOCKS5BytestreamClientSession::startSending(boost::shared_ptr<ReadBytestrea if (state == Ready) { state = Writing; readBytestream = readStream; - connection->onDataWritten.connect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); + dataWrittenConnection = connection->onDataWritten.connect( + boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); sendData(); } else { SWIFT_LOG(debug) << "Session isn't ready for transfer yet!" << std::endl; @@ -165,7 +186,7 @@ HostAddressPort SOCKS5BytestreamClientSession::getAddressPort() const { void SOCKS5BytestreamClientSession::sendData() { if (!readBytestream->isFinished()) { try { - boost::shared_ptr<ByteArray> dataToSend = readBytestream->read(chunkSize); + boost::shared_ptr<ByteArray> dataToSend = readBytestream->read(boost::numeric_cast<size_t>(chunkSize)); connection->write(createSafeByteArray(*dataToSend)); onBytesSent(dataToSend->size()); } @@ -179,10 +200,9 @@ void SOCKS5BytestreamClientSession::sendData() { } void SOCKS5BytestreamClientSession::finish(bool error) { + SWIFT_LOG(debug) << std::endl; weFailedTimeout->stop(); - connection->disconnect(); - connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); - connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); + closeConnection(); readBytestream.reset(); if (state == Initial || state == Hello || state == Authenticating) { onSessionReady(true); @@ -198,13 +218,17 @@ void SOCKS5BytestreamClientSession::finish(bool error) { } void SOCKS5BytestreamClientSession::handleConnectFinished(bool error) { + connectFinishedConnection.disconnect(); if (error) { SWIFT_LOG(debug) << "Failed to connect via TCP to " << addressPort.toString() << "." << std::endl; finish(true); } else { SWIFT_LOG(debug) << "Successfully connected via TCP" << addressPort.toString() << "." << std::endl; + disconnectedConnection = connection->onDisconnected.connect( + boost::bind(&SOCKS5BytestreamClientSession::handleDisconnected, this, _1)); + dataReadConnection = connection->onDataRead.connect( + boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); weFailedTimeout->start(); - connection->onDataRead.connect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); process(); } } @@ -233,4 +257,12 @@ void SOCKS5BytestreamClientSession::handleWeFailedTimeout() { finish(true); } +void SOCKS5BytestreamClientSession::closeConnection() { + connectFinishedConnection.disconnect(); + dataWrittenConnection.disconnect(); + dataReadConnection.disconnect(); + disconnectedConnection.disconnect(); + connection->disconnect(); +} + } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h index 0b9790d..287cf3b 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h @@ -38,14 +38,19 @@ public: Ready, Writing, Reading, - Finished, + Finished }; public: typedef boost::shared_ptr<SOCKS5BytestreamClientSession> ref; public: - SOCKS5BytestreamClientSession(boost::shared_ptr<Connection> connection, const HostAddressPort&, const std::string&, TimerFactory*); + SOCKS5BytestreamClientSession( + boost::shared_ptr<Connection> connection, + const HostAddressPort&, + const std::string&, + TimerFactory*); + ~SOCKS5BytestreamClientSession(); void start(); void stop(); @@ -58,8 +63,8 @@ public: boost::signal<void (bool /*error*/)> onSessionReady; boost::signal<void (boost::optional<FileTransferError>)> onFinished; - boost::signal<void (int)> onBytesSent; - boost::signal<void (int)> onBytesReceived; + boost::signal<void (size_t)> onBytesSent; + boost::signal<void (size_t)> onBytesReceived; private: void process(); @@ -73,6 +78,7 @@ private: void finish(bool error); void sendData(); + void closeConnection(); private: boost::shared_ptr<Connection> connection; @@ -89,6 +95,11 @@ private: boost::shared_ptr<ReadBytestream> readBytestream; Timer::ref weFailedTimeout; + + boost::bsignals::connection connectFinishedConnection; + boost::bsignals::connection dataWrittenConnection; + boost::bsignals::connection dataReadConnection; + boost::bsignals::connection disconnectedConnection; }; } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxy.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp index 9599fd1..0b94763 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxy.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ -#include "SOCKS5BytestreamProxy.h" +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <boost/smart_ptr/make_shared.hpp> @@ -14,19 +14,19 @@ namespace Swift { -SOCKS5BytestreamProxy::SOCKS5BytestreamProxy(ConnectionFactory *connFactory, TimerFactory *timeFactory) : connectionFactory(connFactory), timerFactory(timeFactory) { +SOCKS5BytestreamProxiesManager::SOCKS5BytestreamProxiesManager(ConnectionFactory *connFactory, TimerFactory *timeFactory) : connectionFactory(connFactory), timerFactory(timeFactory) { } -void SOCKS5BytestreamProxy::addS5BProxy(S5BProxyRequest::ref proxy) { +void SOCKS5BytestreamProxiesManager::addS5BProxy(S5BProxyRequest::ref proxy) { localS5BProxies.push_back(proxy); } -const std::vector<S5BProxyRequest::ref>& SOCKS5BytestreamProxy::getS5BProxies() const { +const std::vector<S5BProxyRequest::ref>& SOCKS5BytestreamProxiesManager::getS5BProxies() const { return localS5BProxies; } -void SOCKS5BytestreamProxy::connectToProxies(const std::string& sessionID) { +void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& sessionID) { SWIFT_LOG(debug) << "session ID: " << sessionID << std::endl; ProxyJIDClientSessionMap clientSessions; @@ -41,7 +41,7 @@ void SOCKS5BytestreamProxy::connectToProxies(const std::string& sessionID) { proxySessions[sessionID] = clientSessions; } -boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxy::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { +boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { // checking parameters if (proxySessions.find(sessionID) == proxySessions.end()) { return boost::shared_ptr<SOCKS5BytestreamClientSession>(); @@ -64,7 +64,7 @@ boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxy::getProxy return activeSession; } -boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxy::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { +boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { SOCKS5BytestreamClientSession::ref connection = boost::make_shared<SOCKS5BytestreamClientSession>(connectionFactory->createConnection(), addressPort, destAddr, timerFactory); return connection; } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h new file mode 100644 index 0000000..f3fed80 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> +#include <vector> + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/TimerFactory.h> + +namespace Swift { + class SOCKS5BytestreamProxiesDiscoverRequest; + + /** + * - manages list of working S5B proxies + * - creates initial connections (for the candidates you provide) + */ + class SWIFTEN_API SOCKS5BytestreamProxiesManager { + public: + SOCKS5BytestreamProxiesManager(ConnectionFactory*, TimerFactory*); + + boost::shared_ptr<SOCKS5BytestreamProxiesDiscoverRequest> createDiscoverProxiesRequest(); + + void addS5BProxy(S5BProxyRequest::ref); + const std::vector<S5BProxyRequest::ref>& getS5BProxies() const; + + void connectToProxies(const std::string& sessionID); + boost::shared_ptr<SOCKS5BytestreamClientSession> getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID); + + boost::shared_ptr<SOCKS5BytestreamClientSession> createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr); + + private: + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; + + typedef std::map<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> > ProxyJIDClientSessionMap; + std::map<std::string, ProxyJIDClientSessionMap> proxySessions; + + std::vector<S5BProxyRequest::ref> localS5BProxies; + }; + +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxy.h b/Swiften/FileTransfer/SOCKS5BytestreamProxy.h deleted file mode 100644 index 59ff50c..0000000 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxy.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <string> -#include <vector> - -#include <Swiften/Base/API.h> -#include <Swiften/Elements/S5BProxyRequest.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/JID/JID.h> -#include <Swiften/Network/ConnectionFactory.h> -#include <Swiften/Network/TimerFactory.h> - -namespace Swift { - -/** - * - manages list of working S5B proxies - * - creates initial connections (for the candidates you provide) - */ -class SWIFTEN_API SOCKS5BytestreamProxy { -public: - SOCKS5BytestreamProxy(ConnectionFactory*, TimerFactory*); - - void addS5BProxy(S5BProxyRequest::ref); - const std::vector<S5BProxyRequest::ref>& getS5BProxies() const; - - void connectToProxies(const std::string& sessionID); - boost::shared_ptr<SOCKS5BytestreamClientSession> getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID); - - boost::shared_ptr<SOCKS5BytestreamClientSession> createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr); - -private: - ConnectionFactory* connectionFactory; - TimerFactory* timerFactory; - - typedef std::map<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> > ProxyJIDClientSessionMap; - std::map<std::string, ProxyJIDClientSessionMap> proxySessions; - - std::vector<S5BProxyRequest::ref> localS5BProxies; -}; - -} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h index 071e03a..8265157 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h @@ -18,25 +18,25 @@ class JID; class IQRouter; class SOCKS5BytestreamProxyFinder { -public: - SOCKS5BytestreamProxyFinder(const JID& service, IQRouter *iqRouter); - ~SOCKS5BytestreamProxyFinder(); - - void start(); - void stop(); - - boost::signal<void(boost::shared_ptr<S5BProxyRequest>)> onProxyFound; - -private: - void sendBytestreamQuery(const JID&); - - void handleServiceFound(const JID&, boost::shared_ptr<DiscoInfo>); - void handleProxyResponse(boost::shared_ptr<S5BProxyRequest>, ErrorPayload::ref); -private: - JID service; - IQRouter* iqRouter; - boost::shared_ptr<DiscoServiceWalker> serviceWalker; - std::vector<boost::shared_ptr<GenericRequest<S5BProxyRequest> > > requests; -}; + public: + SOCKS5BytestreamProxyFinder(const JID& service, IQRouter *iqRouter); + ~SOCKS5BytestreamProxyFinder(); + + void start(); + void stop(); + + boost::signal<void(boost::shared_ptr<S5BProxyRequest>)> onProxyFound; + + private: + void sendBytestreamQuery(const JID&); + + void handleServiceFound(const JID&, boost::shared_ptr<DiscoInfo>); + void handleProxyResponse(boost::shared_ptr<S5BProxyRequest>, ErrorPayload::ref); + private: + JID service; + IQRouter* iqRouter; + boost::shared_ptr<DiscoServiceWalker> serviceWalker; + std::vector<boost::shared_ptr<GenericRequest<S5BProxyRequest> > > requests; + }; } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp index ffc4298..cf4794c 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,62 +11,28 @@ #include <Swiften/Base/Algorithm.h> #include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> -#include <Swiften/StringCodecs/SHA1.h> -#include <Swiften/StringCodecs/Hexify.h> namespace Swift { SOCKS5BytestreamRegistry::SOCKS5BytestreamRegistry() { } -void SOCKS5BytestreamRegistry::addReadBytestream(const std::string& destination, boost::shared_ptr<ReadBytestream> byteStream) { - readBytestreams[destination] = byteStream; -} - -void SOCKS5BytestreamRegistry::removeReadBytestream(const std::string& destination) { - readBytestreams.erase(destination); -} - -boost::shared_ptr<ReadBytestream> SOCKS5BytestreamRegistry::getReadBytestream(const std::string& destination) const { - ReadBytestreamMap::const_iterator i = readBytestreams.find(destination); - if (i != readBytestreams.end()) { - return i->second; +void SOCKS5BytestreamRegistry::setHasBytestream(const std::string& destination, bool b) { + if (b) { + availableBytestreams.insert(destination); + } + else { + availableBytestreams.erase(destination); } - return boost::shared_ptr<ReadBytestream>(); -} - -void SOCKS5BytestreamRegistry::addWriteBytestream(const std::string& destination, boost::shared_ptr<WriteBytestream> byteStream) { - writeBytestreams[destination] = byteStream; -} - -void SOCKS5BytestreamRegistry::removeWriteBytestream(const std::string& destination) { - writeBytestreams.erase(destination); } -boost::shared_ptr<WriteBytestream> SOCKS5BytestreamRegistry::getWriteBytestream(const std::string& destination) const { - WriteBytestreamMap::const_iterator i = writeBytestreams.find(destination); - if (i != writeBytestreams.end()) { - return i->second; - } - return boost::shared_ptr<WriteBytestream>(); +bool SOCKS5BytestreamRegistry::hasBytestream(const std::string& destination) const { + return availableBytestreams.find(destination) != availableBytestreams.end(); } std::string SOCKS5BytestreamRegistry::generateSessionID() { return idGenerator.generateID(); } -SOCKS5BytestreamServerSession* SOCKS5BytestreamRegistry::getConnectedSession(const std::string& destination) { - if (serverSessions.find(destination) != serverSessions.end()) { - return serverSessions[destination]; - } else { - SWIFT_LOG(debug) << "No active connction for stream ID " << destination << " found!" << std::endl; - return NULL; - } -} - -std::string SOCKS5BytestreamRegistry::getHostname(const std::string& sessionID, const JID& requester, const JID& target) { - return Hexify::hexify(SHA1::getHash(createSafeByteArray(sessionID + requester.toString() + target.toString()))); -} - } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h index 6d89e27..4c05e47 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h @@ -1,65 +1,35 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once -#include <boost/shared_ptr.hpp> - #include <map> #include <string> -#include <vector> #include <set> #include <Swiften/Base/API.h> #include <Swiften/Base/IDGenerator.h> -#include <Swiften/JID/JID.h> -#include <Swiften/Elements/S5BProxyRequest.h> -#include <Swiften/FileTransfer/ReadBytestream.h> -#include <Swiften/FileTransfer/WriteBytestream.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/Network/HostAddressPort.h> namespace Swift { + class SOCKS5BytestreamServerSession; + class SWIFTEN_API SOCKS5BytestreamRegistry { public: SOCKS5BytestreamRegistry(); - boost::shared_ptr<ReadBytestream> getReadBytestream(const std::string& destination) const; - void addReadBytestream(const std::string& destination, boost::shared_ptr<ReadBytestream> byteStream); - void removeReadBytestream(const std::string& destination); - - boost::shared_ptr<WriteBytestream> getWriteBytestream(const std::string& destination) const; - void addWriteBytestream(const std::string& destination, boost::shared_ptr<WriteBytestream> byteStream); - void removeWriteBytestream(const std::string& destination); + void setHasBytestream(const std::string& destination, bool); + bool hasBytestream(const std::string& destination) const; /** * Generate a new session ID to use for new S5B streams. */ std::string generateSessionID(); - /** - * Start an actual transfer. - */ - SOCKS5BytestreamServerSession* getConnectedSession(const std::string& destination); - - public: - static std::string getHostname(const std::string& sessionID, const JID& requester, const JID& target); - private: - friend class SOCKS5BytestreamServerSession; - - typedef std::map<std::string, boost::shared_ptr<ReadBytestream> > ReadBytestreamMap; - ReadBytestreamMap readBytestreams; - - typedef std::map<std::string, boost::shared_ptr<WriteBytestream> > WriteBytestreamMap; - WriteBytestreamMap writeBytestreams; - - std::map<std::string, SOCKS5BytestreamServerSession*> serverSessions; - + std::set<std::string> availableBytestreams; IDGenerator idGenerator; }; } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp index 90fed7a..f491918 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -9,14 +9,19 @@ #include <boost/bind.hpp> #include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> #include <Swiften/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> namespace Swift { -SOCKS5BytestreamServer::SOCKS5BytestreamServer(boost::shared_ptr<ConnectionServer> connectionServer, SOCKS5BytestreamRegistry* registry) : connectionServer(connectionServer), registry(registry) { +SOCKS5BytestreamServer::SOCKS5BytestreamServer( + boost::shared_ptr<ConnectionServer> connectionServer, + SOCKS5BytestreamRegistry* registry) : + connectionServer(connectionServer), + registry(registry) { } void SOCKS5BytestreamServer::start() { @@ -25,22 +30,17 @@ void SOCKS5BytestreamServer::start() { void SOCKS5BytestreamServer::stop() { connectionServer->onNewConnection.disconnect(boost::bind(&SOCKS5BytestreamServer::handleNewConnection, this, _1)); -} - -void SOCKS5BytestreamServer::addReadBytestream(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> byteStream) { - registry->addReadBytestream(getSOCKSDestinationAddress(id, from, to), byteStream); -} - -void SOCKS5BytestreamServer::removeReadBytestream(const std::string& id, const JID& from, const JID& to) { - registry->removeReadBytestream(getSOCKSDestinationAddress(id, from, to)); -} - -std::string SOCKS5BytestreamServer::getSOCKSDestinationAddress(const std::string& id, const JID& from, const JID& to) { - return Hexify::hexify(SHA1::getHash(createByteArray(id + from.toString() + to.toString()))); + foreach (boost::shared_ptr<SOCKS5BytestreamServerSession> session, sessions) { + session->onFinished.disconnect(boost::bind(&SOCKS5BytestreamServer::handleSessionFinished, this, session)); + session->stop(); + } + sessions.clear(); } void SOCKS5BytestreamServer::handleNewConnection(boost::shared_ptr<Connection> connection) { - boost::shared_ptr<SOCKS5BytestreamServerSession> session(new SOCKS5BytestreamServerSession(connection, registry)); + boost::shared_ptr<SOCKS5BytestreamServerSession> session = + boost::make_shared<SOCKS5BytestreamServerSession>(connection, registry); + session->onFinished.connect(boost::bind(&SOCKS5BytestreamServer::handleSessionFinished, this, session)); sessions.push_back(session); session->start(); } @@ -49,5 +49,21 @@ HostAddressPort SOCKS5BytestreamServer::getAddressPort() const { return connectionServer->getAddressPort(); } +std::vector< boost::shared_ptr<SOCKS5BytestreamServerSession> > SOCKS5BytestreamServer::getSessions( + const std::string& streamID) const { + std::vector< boost::shared_ptr<SOCKS5BytestreamServerSession> > result; + foreach (boost::shared_ptr<SOCKS5BytestreamServerSession> session, sessions) { + if (session->getStreamID() == streamID) { + result.push_back(session); + } + } + return result; +} + +void SOCKS5BytestreamServer::handleSessionFinished(boost::shared_ptr<SOCKS5BytestreamServerSession> session) { + sessions.erase(std::remove(sessions.begin(), sessions.end(), session), sessions.end()); + session->onFinished.disconnect(boost::bind(&SOCKS5BytestreamServer::handleSessionFinished, this, session)); +} + } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServer.h b/Swiften/FileTransfer/SOCKS5BytestreamServer.h index 6bb598e..71605c4 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServer.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamServer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -17,26 +17,24 @@ namespace Swift { class SOCKS5BytestreamServerSession; + class CryptoProvider; class SOCKS5BytestreamServer { public: - SOCKS5BytestreamServer(boost::shared_ptr<ConnectionServer> connectionServer, SOCKS5BytestreamRegistry* registry); + SOCKS5BytestreamServer( + boost::shared_ptr<ConnectionServer> connectionServer, + SOCKS5BytestreamRegistry* registry); HostAddressPort getAddressPort() const; void start(); void stop(); - void addReadBytestream(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> byteStream); - void removeReadBytestream(const std::string& id, const JID& from, const JID& to); - - /*protected: - boost::shared_ptr<ReadBytestream> getBytestream(const std::string& dest);*/ + std::vector< boost::shared_ptr<SOCKS5BytestreamServerSession> > getSessions(const std::string& id) const; private: void handleNewConnection(boost::shared_ptr<Connection> connection); - - static std::string getSOCKSDestinationAddress(const std::string& id, const JID& from, const JID& to); + void handleSessionFinished(boost::shared_ptr<SOCKS5BytestreamServerSession>); private: friend class SOCKS5BytestreamServerSession; diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.cpp new file mode 100644 index 0000000..38735de --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h> + +#include <boost/bind.hpp> + +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> + +using namespace Swift; + +SOCKS5BytestreamServerInitializeRequest::SOCKS5BytestreamServerInitializeRequest(SOCKS5BytestreamServerManager* manager) : manager(manager) { +} + +SOCKS5BytestreamServerInitializeRequest::~SOCKS5BytestreamServerInitializeRequest() { +} + +void SOCKS5BytestreamServerInitializeRequest::start() { + if (manager->isInitialized()) { + handleInitialized(true); + } + else { + manager->onInitialized.connect( + boost::bind(&SOCKS5BytestreamServerInitializeRequest::handleInitialized, this, _1)); + manager->initialize(); + } +} + +void SOCKS5BytestreamServerInitializeRequest::stop() { + manager->onInitialized.disconnect( + boost::bind(&SOCKS5BytestreamServerInitializeRequest::handleInitialized, this, _1)); +} + +void SOCKS5BytestreamServerInitializeRequest::handleInitialized(bool success) { + onFinished(success); +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h b/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h new file mode 100644 index 0000000..aa073fc --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class SOCKS5BytestreamServerManager; + + class SWIFTEN_API SOCKS5BytestreamServerInitializeRequest { + public: + SOCKS5BytestreamServerInitializeRequest(SOCKS5BytestreamServerManager* manager); + ~SOCKS5BytestreamServerInitializeRequest(); + + void start(); + void stop(); + + public: + boost::signal<void (bool /* success */)> onFinished; + + private: + void handleInitialized(bool success); + + private: + SOCKS5BytestreamServerManager* manager; + }; +} + diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp new file mode 100644 index 0000000..1d65d27 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> + +#include <Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> +#include <Swiften/Network/ConnectionServer.h> +#include <Swiften/Network/ConnectionServerFactory.h> +#include <Swiften/Network/NetworkEnvironment.h> +#include <Swiften/Network/NATTraverser.h> +#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> +#include <Swiften/Network/NATTraversalForwardPortRequest.h> + +using namespace Swift; + +static const int LISTEN_PORTS_BEGIN = 10000; +static const int LISTEN_PORTS_END = 11000; + +SOCKS5BytestreamServerManager::SOCKS5BytestreamServerManager( + SOCKS5BytestreamRegistry* bytestreamRegistry, + ConnectionServerFactory* connectionServerFactory, + NetworkEnvironment* networkEnvironment, + NATTraverser* natTraverser) : + bytestreamRegistry(bytestreamRegistry), + connectionServerFactory(connectionServerFactory), + networkEnvironment(networkEnvironment), + natTraverser(natTraverser), + state(Start), + server(NULL) { +} + +SOCKS5BytestreamServerManager::~SOCKS5BytestreamServerManager() { + SWIFT_LOG_ASSERT(!connectionServer, warning) << std::endl; + SWIFT_LOG_ASSERT(!getPublicIPRequest, warning) << std::endl; + SWIFT_LOG_ASSERT(!forwardPortRequest, warning) << std::endl; + SWIFT_LOG_ASSERT(state == Start, warning) << std::endl; +} + + +boost::shared_ptr<SOCKS5BytestreamServerInitializeRequest> SOCKS5BytestreamServerManager::createInitializeRequest() { + return boost::make_shared<SOCKS5BytestreamServerInitializeRequest>(this); +} + +void SOCKS5BytestreamServerManager::stop() { + if (getPublicIPRequest) { + getPublicIPRequest->stop(); + getPublicIPRequest.reset(); + } + if (forwardPortRequest) { + forwardPortRequest->stop(); + forwardPortRequest.reset(); + } + if (connectionServer) { + connectionServer->stop(); + connectionServer.reset(); + } + // TODO: Remove port forwards + + state = Start; +} + +std::vector<HostAddressPort> SOCKS5BytestreamServerManager::getHostAddressPorts() const { + std::vector<HostAddressPort> result; + if (connectionServer) { + std::vector<NetworkInterface> networkInterfaces = networkEnvironment->getNetworkInterfaces(); + foreach (const NetworkInterface& networkInterface, networkInterfaces) { + foreach (const HostAddress& address, networkInterface.getAddresses()) { + result.push_back(HostAddressPort(address, connectionServerPort)); + } + } + } + return result; +} + +std::vector<HostAddressPort> SOCKS5BytestreamServerManager::getAssistedHostAddressPorts() const { + std::vector<HostAddressPort> result; + if (publicAddress && portMapping) { + result.push_back(HostAddressPort(*publicAddress, portMapping->getPublicPort())); + } + return result; +} + +bool SOCKS5BytestreamServerManager::isInitialized() const { + return state == Initialized; +} + +void SOCKS5BytestreamServerManager::initialize() { + if (state == Start) { + state = Initializing; + + // Find a port to listen on + assert(!connectionServer); + int port; + for (port = LISTEN_PORTS_BEGIN; port < LISTEN_PORTS_END; ++port) { + SWIFT_LOG(debug) << "Trying to start server on port " << port << std::endl; + connectionServer = connectionServerFactory->createConnectionServer(HostAddress("0.0.0.0"), port); + boost::optional<ConnectionServer::Error> error = connectionServer->tryStart(); + if (!error) { + break; + } + else if (*error != ConnectionServer::Conflict) { + SWIFT_LOG(debug) << "Error starting server" << std::endl; + onInitialized(false); + return; + } + connectionServer.reset(); + } + if (!connectionServer) { + SWIFT_LOG(debug) << "Unable to find an open port" << std::endl; + onInitialized(false); + return; + } + SWIFT_LOG(debug) << "Server started succesfully" << std::endl; + connectionServerPort = port; + + // Start bytestream server. Should actually happen before the connectionserver is started + // but that doesn't really matter here. + assert(!server); + server = new SOCKS5BytestreamServer(connectionServer, bytestreamRegistry); + server->start(); + + // Retrieve public addresses + assert(!getPublicIPRequest); + publicAddress = boost::optional<HostAddress>(); + if ((getPublicIPRequest = natTraverser->createGetPublicIPRequest())) { + getPublicIPRequest->onResult.connect( + boost::bind(&SOCKS5BytestreamServerManager::handleGetPublicIPResult, this, _1)); + getPublicIPRequest->start(); + } + + // Forward ports + assert(!forwardPortRequest); + portMapping = boost::optional<NATPortMapping>(); + if ((forwardPortRequest = natTraverser->createForwardPortRequest(port, port))) { + forwardPortRequest->onResult.connect( + boost::bind(&SOCKS5BytestreamServerManager::handleForwardPortResult, this, _1)); + forwardPortRequest->start(); + } + } +} + +void SOCKS5BytestreamServerManager::handleGetPublicIPResult(boost::optional<HostAddress> address) { + if (address) { + SWIFT_LOG(debug) << "Public IP discovered as " << address.get().toString() << "." << std::endl; + } + else { + SWIFT_LOG(debug) << "No public IP discoverable." << std::endl; + } + + publicAddress = address; + + getPublicIPRequest->stop(); + getPublicIPRequest.reset(); + + checkInitializeFinished(); +} + +void SOCKS5BytestreamServerManager::handleForwardPortResult(boost::optional<NATPortMapping> mapping) { + if (mapping) { + SWIFT_LOG(debug) << "Mapping port was successful." << std::endl; + } + else { + SWIFT_LOG(debug) << "Mapping port has failed." << std::endl; + } + + portMapping = mapping; + + forwardPortRequest->stop(); + forwardPortRequest.reset(); + + checkInitializeFinished(); +} + +void SOCKS5BytestreamServerManager::checkInitializeFinished() { + assert(state == Initializing); + if (!getPublicIPRequest && !forwardPortRequest) { + state = Initialized; + onInitialized(true); + } +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h new file mode 100644 index 0000000..248a9b9 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/NATPortMapping.h> + +namespace Swift { + class NetworkEnvironment; + class NATTraverser; + class NATTraversalGetPublicIPRequest; + class NATTraversalForwardPortRequest; + class SOCKS5BytestreamRegistry; + class ConnectionServerFactory; + class ConnectionServer; + class SOCKS5BytestreamServerInitializeRequest; + class SOCKS5BytestreamServer; + + class SOCKS5BytestreamServerManager { + public: + SOCKS5BytestreamServerManager( + SOCKS5BytestreamRegistry* bytestreamRegistry, + ConnectionServerFactory* connectionServerFactory, + NetworkEnvironment* networkEnvironment, + NATTraverser* natTraverser); + ~SOCKS5BytestreamServerManager(); + + boost::shared_ptr<SOCKS5BytestreamServerInitializeRequest> createInitializeRequest(); + void stop(); + + std::vector<HostAddressPort> getHostAddressPorts() const; + std::vector<HostAddressPort> getAssistedHostAddressPorts() const; + + SOCKS5BytestreamServer* getServer() const { + return server; + } + + private: + bool isInitialized() const; + void initialize(); + void checkInitializeFinished(); + + void handleGetPublicIPResult(boost::optional<HostAddress> address); + void handleForwardPortResult(boost::optional<NATPortMapping> mapping); + + boost::signal<void (bool /* success */)> onInitialized; + + + private: + friend class SOCKS5BytestreamServerInitializeRequest; + SOCKS5BytestreamRegistry* bytestreamRegistry; + ConnectionServerFactory* connectionServerFactory; + NetworkEnvironment* networkEnvironment; + NATTraverser* natTraverser; + enum { Start, Initializing, Initialized } state; + SOCKS5BytestreamServer* server; + boost::shared_ptr<ConnectionServer> connectionServer; + int connectionServerPort; + boost::shared_ptr<NATTraversalGetPublicIPRequest> getPublicIPRequest; + boost::shared_ptr<NATTraversalForwardPortRequest> forwardPortRequest; + boost::optional<HostAddress> publicAddress; + boost::optional<NATPortMapping> portMapping; + }; +} + diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp index 4412d0b..12a0f12 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,7 @@ #include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> #include <boost/bind.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <iostream> #include <Swiften/Base/ByteArray.h> @@ -14,54 +15,61 @@ #include <Swiften/Base/Algorithm.h> #include <Swiften/Base/Concat.h> #include <Swiften/Base/Log.h> +#include <Swiften/Network/HostAddressPort.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> #include <Swiften/FileTransfer/BytestreamException.h> namespace Swift { -SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession(boost::shared_ptr<Connection> connection, SOCKS5BytestreamRegistry* bytestreams) : connection(connection), bytestreams(bytestreams), state(Initial), chunkSize(131072), waitingForData(false) { - connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); +SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession( + boost::shared_ptr<Connection> connection, + SOCKS5BytestreamRegistry* bytestreams) : + connection(connection), + bytestreams(bytestreams), + state(Initial), + chunkSize(131072), + waitingForData(false) { + disconnectedConnection = connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); } SOCKS5BytestreamServerSession::~SOCKS5BytestreamServerSession() { if (state != Finished && state != Initial) { - std::cerr << "Warning: SOCKS5BytestremServerSession unfinished" << std::endl; + std::cerr << "Warning: SOCKS5BytestreamServerSession unfinished" << std::endl; finish(false); } } void SOCKS5BytestreamServerSession::start() { SWIFT_LOG(debug) << std::endl; - connection->onDataRead.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); + dataReadConnection = connection->onDataRead.connect( + boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); state = WaitingForAuthentication; } void SOCKS5BytestreamServerSession::stop() { - connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); - connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); - connection->disconnect(); - if (readBytestream) { - readBytestream->onDataAvailable.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDataAvailable, this)); - } - state = Finished; + finish(false); } -void SOCKS5BytestreamServerSession::startTransfer() { - if (state == ReadyForTransfer) { - if (readBytestream) { - state = WritingData; - connection->onDataWritten.connect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); - sendData(); - } - else if(writeBytestream) { - state = ReadingData; - writeBytestream->write(unprocessedData); - onBytesReceived(unprocessedData.size()); - unprocessedData.clear(); - } - } else { - SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; - } +void SOCKS5BytestreamServerSession::startSending(boost::shared_ptr<ReadBytestream> stream) { + if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; return; } + + readBytestream = stream; + state = WritingData; + dataAvailableConnection = readBytestream->onDataAvailable.connect( + boost::bind(&SOCKS5BytestreamServerSession::handleDataAvailable, this)); + dataWrittenConnection = connection->onDataWritten.connect( + boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); + sendData(); +} + +void SOCKS5BytestreamServerSession::startReceiving(boost::shared_ptr<WriteBytestream> stream) { + if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; return; } + + writeBytestream = stream; + state = ReadingData; + writeBytestream->write(unprocessedData); + onBytesReceived(unprocessedData.size()); + unprocessedData.clear(); } HostAddressPort SOCKS5BytestreamServerSession::getAddressPort() const { @@ -86,9 +94,7 @@ void SOCKS5BytestreamServerSession::handleDataAvailable() { void SOCKS5BytestreamServerSession::handleDisconnected(const boost::optional<Connection::Error>& error) { SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error") << std::endl; - if (error) { - finish(true); - } + finish(error); } void SOCKS5BytestreamServerSession::process() { @@ -127,29 +133,22 @@ void SOCKS5BytestreamServerSession::process() { SWIFT_LOG(debug) << "Junk after authentication mechanism" << std::endl; } unprocessedData.clear(); - std::string streamID = byteArrayToString(requestID); - readBytestream = bytestreams->getReadBytestream(streamID); - writeBytestream = bytestreams->getWriteBytestream(streamID); + streamID = byteArrayToString(requestID); + bool hasBytestream = bytestreams->hasBytestream(streamID); SafeByteArray result = createSafeByteArray("\x05", 1); - result.push_back((readBytestream || writeBytestream) ? 0x0 : 0x4); + result.push_back(hasBytestream ? 0x0 : 0x4); append(result, createByteArray("\x00\x03", 2)); - result.push_back(static_cast<char>(requestID.size())); + result.push_back(boost::numeric_cast<unsigned char>(requestID.size())); append(result, concat(requestID, createByteArray("\x00\x00", 2))); - if (!readBytestream && !writeBytestream) { + if (!hasBytestream) { SWIFT_LOG(debug) << "Readstream or Wrtiestream with ID " << streamID << " not found!" << std::endl; connection->write(result); finish(true); } else { - SWIFT_LOG(debug) << "Found " << (readBytestream ? "Readstream" : "Writestream") << ". Sent OK." << std::endl; + SWIFT_LOG(debug) << "Found stream. Sent OK." << std::endl; connection->write(result); - bytestreams->serverSessions[streamID] = this; state = ReadyForTransfer; - - if (readBytestream) { - readBytestream->onDataAvailable.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDataAvailable, this)); - } - } } } @@ -159,7 +158,7 @@ void SOCKS5BytestreamServerSession::process() { void SOCKS5BytestreamServerSession::sendData() { if (!readBytestream->isFinished()) { try { - SafeByteArray dataToSend = createSafeByteArray(*readBytestream->read(chunkSize)); + SafeByteArray dataToSend = createSafeByteArray(*readBytestream->read(boost::numeric_cast<size_t>(chunkSize))); if (!dataToSend.empty()) { connection->write(dataToSend); onBytesSent(dataToSend.size()); @@ -179,9 +178,15 @@ void SOCKS5BytestreamServerSession::sendData() { } void SOCKS5BytestreamServerSession::finish(bool error) { - connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); - connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); - connection->onDisconnected.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); + SWIFT_LOG(debug) << error << " " << state << std::endl; + if (state == Finished) { + return; + } + + disconnectedConnection.disconnect(); + dataReadConnection.disconnect(); + dataWrittenConnection.disconnect(); + dataAvailableConnection.disconnect(); readBytestream.reset(); state = Finished; if (error) { diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h index 4cbda7c..762db8b 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h @@ -30,7 +30,7 @@ namespace Swift { ReadyForTransfer, ReadingData, WritingData, - Finished, + Finished }; SOCKS5BytestreamServerSession(boost::shared_ptr<Connection> connection, SOCKS5BytestreamRegistry* registry); @@ -43,12 +43,18 @@ namespace Swift { void start(); void stop(); - void startTransfer(); + void startSending(boost::shared_ptr<ReadBytestream>); + void startReceiving(boost::shared_ptr<WriteBytestream>); + HostAddressPort getAddressPort() const; boost::signal<void (boost::optional<FileTransferError>)> onFinished; - boost::signal<void (int)> onBytesSent; - boost::signal<void (int)> onBytesReceived; + boost::signal<void (unsigned long long)> onBytesSent; + boost::signal<void (unsigned long long)> onBytesReceived; + + const std::string& getStreamID() const { + return streamID; + } private: void finish(bool error); @@ -64,8 +70,15 @@ namespace Swift { ByteArray unprocessedData; State state; int chunkSize; + std::string streamID; boost::shared_ptr<ReadBytestream> readBytestream; boost::shared_ptr<WriteBytestream> writeBytestream; bool waitingForData; + + boost::bsignals::connection disconnectedConnection; + boost::bsignals::connection dataReadConnection; + boost::bsignals::connection dataWrittenConnection; + boost::bsignals::connection dataAvailableConnection; + }; } diff --git a/Swiften/FileTransfer/TransportSession.cpp b/Swiften/FileTransfer/TransportSession.cpp new file mode 100644 index 0000000..154cb89 --- /dev/null +++ b/Swiften/FileTransfer/TransportSession.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/TransportSession.h> + +using namespace Swift; + +TransportSession::~TransportSession() { +} diff --git a/Swiften/FileTransfer/TransportSession.h b/Swiften/FileTransfer/TransportSession.h new file mode 100644 index 0000000..e5a90db --- /dev/null +++ b/Swiften/FileTransfer/TransportSession.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/FileTransfer/FileTransferError.h> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class SWIFTEN_API TransportSession { + public: + virtual ~TransportSession(); + + virtual void start() = 0; + virtual void stop() = 0; + + boost::signal<void (size_t)> onBytesSent; + boost::signal<void (boost::optional<FileTransferError>)> onFinished; + }; +} diff --git a/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h b/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h index ae06cd3..26adb05 100644 --- a/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h +++ b/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h @@ -7,28 +7,41 @@ #pragma once #include <string> -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/date_time/posix_time/posix_time.hpp> +#include <Swiften/Base/Override.h> #include <Swiften/FileTransfer/FileTransferManager.h> namespace Swift { + class S5BProxyRequest; + class FileTransferOptions; + class DummyFileTransferManager : public FileTransferManager { public: DummyFileTransferManager() : FileTransferManager() { } - virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID&, const boost::filesystem::path&, const std::string&, boost::shared_ptr<ReadBytestream>) { + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID&, + const boost::filesystem::path&, + const std::string&, + boost::shared_ptr<ReadBytestream>, + const FileTransferOptions&) SWIFTEN_OVERRIDE { return OutgoingFileTransfer::ref(); } - virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID&, const std::string&, const std::string&, const boost::uintmax_t, const boost::posix_time::ptime&, boost::shared_ptr<ReadBytestream>) { + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID&, + const std::string&, + const std::string&, + const boost::uintmax_t, + const boost::posix_time::ptime&, + boost::shared_ptr<ReadBytestream>, + const FileTransferOptions&) SWIFTEN_OVERRIDE { return OutgoingFileTransfer::ref(); } - virtual void startListeningOnPort(int) { - } - virtual void addS5BProxy(boost::shared_ptr<S5BProxyRequest>) { } diff --git a/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp index c62636d..339e245 100644 --- a/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp @@ -13,6 +13,7 @@ #include <Swiften/Base/ByteArray.h> #include <Swiften/FileTransfer/IBBReceiveSession.h> +#include <Swiften/FileTransfer/ByteArrayWriteBytestream.h> #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/DummyStanzaChannel.h> @@ -35,6 +36,7 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { stanzaChannel = new DummyStanzaChannel(); iqRouter = new IQRouter(stanzaChannel); finished = false; + bytestream = boost::make_shared<ByteArrayWriteBytestream>(); } void tearDown() { @@ -61,7 +63,7 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(1, "id-a")); - CPPUNIT_ASSERT(createByteArray("abc") == receivedData); + CPPUNIT_ASSERT(createByteArray("abc") == bytestream->getData()); CPPUNIT_ASSERT(!finished); testling->stop(); @@ -76,7 +78,7 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, createByteArray("def")), "foo@bar.com/baz", "id-b")); CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b")); - CPPUNIT_ASSERT(createByteArray("abcdef") == receivedData); + CPPUNIT_ASSERT(createByteArray("abcdef") == bytestream->getData()); CPPUNIT_ASSERT(!finished); testling->stop(); @@ -118,7 +120,7 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, createByteArray("def")), "foo@bar.com/baz", "id-b")); CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b")); - CPPUNIT_ASSERT(createByteArray("abcdef") == receivedData); + CPPUNIT_ASSERT(createByteArray("abcdef") == bytestream->getData()); CPPUNIT_ASSERT(finished); CPPUNIT_ASSERT(!error); @@ -161,8 +163,7 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { } IBBReceiveSession* createSession(const std::string& from, const std::string& id, size_t size = 0x1000) { - IBBReceiveSession* session = new IBBReceiveSession(id, JID(from), JID(), size, iqRouter); - session->onDataReceived.connect(boost::bind(&IBBReceiveSessionTest::handleDataReceived, this, _1)); + IBBReceiveSession* session = new IBBReceiveSession(id, JID(from), JID(), size, bytestream, iqRouter); session->onFinished.connect(boost::bind(&IBBReceiveSessionTest::handleFinished, this, _1)); return session; } @@ -173,16 +174,12 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { this->error = error; } - void handleDataReceived(const std::vector<unsigned char>& data) { - receivedData.insert(receivedData.end(), data.begin(), data.end()); - } - private: DummyStanzaChannel* stanzaChannel; IQRouter* iqRouter; bool finished; boost::optional<FileTransferError> error; - std::vector<unsigned char> receivedData; + boost::shared_ptr<ByteArrayWriteBytestream> bytestream; }; CPPUNIT_TEST_SUITE_REGISTRATION(IBBReceiveSessionTest); diff --git a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp index 4c6ae72..669ed80 100644 --- a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp @@ -4,12 +4,19 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Override.h> #include <Swiften/Base/Log.h> #include <Swiften/Client/DummyStanzaChannel.h> #include <Swiften/Elements/IBB.h> @@ -17,142 +24,67 @@ #include <Swiften/Elements/JingleS5BTransportPayload.h> #include <Swiften/FileTransfer/ByteArrayWriteBytestream.h> #include <Swiften/FileTransfer/IncomingJingleFileTransfer.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/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <Swiften/Jingle/FakeJingleSession.h> #include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> #include <Swiften/Network/DummyConnectionFactory.h> #include <Swiften/Network/PlatformNATTraversalWorker.h> #include <Swiften/Queries/IQRouter.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> #include <iostream> using namespace Swift; using namespace boost; -class FakeRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector { - void addRemoteTransportCandidates(JingleTransportPayload::ref cand) { - candidate = cand; - } - - void selectCandidate() { - boost::shared_ptr<JingleS5BTransportPayload> payload = make_shared<JingleS5BTransportPayload>(); - payload->setCandidateError(true); - payload->setSessionID(candidate->getSessionID()); - onRemoteTransportCandidateSelectFinished(payload); - } - - void setMinimumPriority(int) { - - } - - bool isActualCandidate(JingleTransportPayload::ref) { - return false; - } - - int getPriority(JingleTransportPayload::ref) { - return 0; - } - - JingleTransport::ref selectTransport(JingleTransportPayload::ref) { - return JingleTransport::ref(); - } - -private: - JingleTransportPayload::ref candidate; -}; - -class FakeRemoteJingleTransportCandidateSelectorFactory : public RemoteJingleTransportCandidateSelectorFactory { -public: - virtual ~FakeRemoteJingleTransportCandidateSelectorFactory() { - - } - - virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() { - return new FakeRemoteJingleTransportCandidateSelector(); - } -}; - -class FakeLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { -public: - virtual void generateLocalTransportCandidates(JingleTransportPayload::ref payload) { - JingleS5BTransportPayload::ref payL = make_shared<JingleS5BTransportPayload>(); - payL->setSessionID(payload->getSessionID()); - onLocalTransportCandidatesGenerated(payL); - } - - void emitonLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { - onLocalTransportCandidatesGenerated(payload); - } - - virtual bool isActualCandidate(JingleTransportPayload::ref) { - return false; - } - - virtual int getPriority(JingleTransportPayload::ref) { - return 0; - } - - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) { - return JingleTransport::ref(); - } -}; - -class FakeLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory { -public: - virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() { - return new FakeLocalJingleTransportCandidateGenerator(); - } -}; - class IncomingJingleFileTransferTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(IncomingJingleFileTransferTest); - CPPUNIT_TEST(test_AcceptOnyIBBSendsSessionAccept); - CPPUNIT_TEST(test_OnlyIBBTransferReceiveWorks); - CPPUNIT_TEST(test_AcceptFailingS5BFallsBackToIBB); + //CPPUNIT_TEST(test_AcceptOnyIBBSendsSessionAccept); + //CPPUNIT_TEST(test_OnlyIBBTransferReceiveWorks); + //CPPUNIT_TEST(test_AcceptFailingS5BFallsBackToIBB); CPPUNIT_TEST_SUITE_END(); public: - shared_ptr<IncomingJingleFileTransfer> createTestling() { - JID ourJID("our@jid.org/full"); - return make_shared<IncomingJingleFileTransfer>(ourJID, shared_ptr<JingleSession>(fakeJingleSession), jingleContentPayload, fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, bytestreamRegistry, bytestreamProxy, timerFactory); - } + // shared_ptr<IncomingJingleFileTransfer> createTestling() { + // JID ourJID("our@jid.org/full"); + // return boost::shared_ptr<IncomingJingleFileTransfer>(new IncomingJingleFileTransfer(ourJID, shared_ptr<JingleSession>(session), jingleContentPayload, fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, bytestreamRegistry, bytestreamProxy, timerFactory, crypto.get())); + // } - IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { - IQ::ref request = IQ::createRequest(IQ::Set, JID("foo@bar.com/baz"), id, ibb); - request->setFrom(from); - return request; - } + // IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { + // IQ::ref request = IQ::createRequest(IQ::Set, JID("foo@bar.com/baz"), id, ibb); + // request->setFrom(from); + // return request; + // } void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); eventLoop = new DummyEventLoop(); - fakeJingleSession = new FakeJingleSession("foo@bar.com/baz", "mysession"); - jingleContentPayload = make_shared<JingleContentPayload>(); - fakeRJTCSF = make_shared<FakeRemoteJingleTransportCandidateSelectorFactory>(); - fakeLJTCF = make_shared<FakeLocalJingleTransportCandidateGeneratorFactory>(); - stanzaChannel = new DummyStanzaChannel(); - iqRouter = new IQRouter(stanzaChannel); - bytestreamRegistry = new SOCKS5BytestreamRegistry(); - timerFactory = new DummyTimerFactory(); - connectionFactory = new DummyConnectionFactory(eventLoop); - bytestreamProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); + session = boost::make_shared<FakeJingleSession>("foo@bar.com/baz", "mysession"); + // jingleContentPayload = make_shared<JingleContentPayload>(); + // fakeRJTCSF = make_shared<FakeRemoteJingleTransportCandidateSelectorFactory>(); + // fakeLJTCF = make_shared<FakeLocalJingleTransportCandidateGeneratorFactory>(); + // stanzaChannel = new DummyStanzaChannel(); + // iqRouter = new IQRouter(stanzaChannel); + // bytestreamRegistry = new SOCKS5BytestreamRegistry(); + // timerFactory = new DummyTimerFactory(); + // connectionFactory = new DummyConnectionFactory(eventLoop); + // bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); } void tearDown() { - delete bytestreamProxy; - delete connectionFactory; - delete timerFactory; - delete bytestreamRegistry; - delete iqRouter; - delete stanzaChannel; + // delete bytestreamProxy; + // delete connectionFactory; + // delete timerFactory; + // delete bytestreamRegistry; + // delete iqRouter; + // delete stanzaChannel; delete eventLoop; } // Tests whether IncomingJingleFileTransfer would accept a IBB only file transfer. +#if 0 void test_AcceptOnyIBBSendsSessionAccept() { //1. create your test incoming file transfer shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>(); @@ -217,7 +149,7 @@ public: CPPUNIT_ASSERT(s5bPayload->hasCandidateError()); // indicate transport replace (Romeo) - fakeJingleSession->onTransportReplaceReceived(getContentID(), addJingleIBBPayload()); + session->onTransportReplaceReceived(getContentID(), addJingleIBBPayload()); FakeJingleSession::AcceptTransportCall acceptTransportCall = getCall<FakeJingleSession::AcceptTransportCall>(2); @@ -259,15 +191,18 @@ private: template <typename T> T getCall(int i) const { size_t index = static_cast<size_t>(i); - CPPUNIT_ASSERT(index < fakeJingleSession->calledCommands.size()); - T* cmd = boost::get<T>(&fakeJingleSession->calledCommands[index]); + CPPUNIT_ASSERT(index < session->calledCommands.size()); + T* cmd = boost::get<T>(&session->calledCommands[index]); CPPUNIT_ASSERT(cmd); return *cmd; } +#endif private: EventLoop* eventLoop; - FakeJingleSession* fakeJingleSession; + boost::shared_ptr<CryptoProvider> crypto; + boost::shared_ptr<FakeJingleSession> session; +#if 0 shared_ptr<JingleContentPayload> jingleContentPayload; shared_ptr<FakeRemoteJingleTransportCandidateSelectorFactory> fakeRJTCSF; shared_ptr<FakeLocalJingleTransportCandidateGeneratorFactory> fakeLJTCF; @@ -275,8 +210,9 @@ private: IQRouter* iqRouter; SOCKS5BytestreamRegistry* bytestreamRegistry; DummyConnectionFactory* connectionFactory; - SOCKS5BytestreamProxy* bytestreamProxy; + SOCKS5BytestreamProxiesManager* bytestreamProxy; DummyTimerFactory* timerFactory; +#endif }; CPPUNIT_TEST_SUITE_REGISTRATION(IncomingJingleFileTransferTest); diff --git a/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp index 0c324bf..16b1225 100644 --- a/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp +++ b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -13,21 +19,18 @@ #include <Swiften/FileTransfer/OutgoingJingleFileTransfer.h> #include <Swiften/Jingle/FakeJingleSession.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/DummyStanzaChannel.h> #include <Swiften/FileTransfer/ByteArrayReadBytestream.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <Swiften/Elements/JingleIBBTransportPayload.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> #include <Swiften/Elements/JingleFileTransferDescription.h> #include <Swiften/Elements/IBB.h> #include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Override.h> #include <Swiften/Base/IDGenerator.h> #include <Swiften/EventLoop/DummyEventLoop.h> #include <Swiften/Network/PlatformNATTraversalWorker.h> @@ -35,11 +38,14 @@ #include <Swiften/Network/DummyConnection.h> #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/DummyConnectionFactory.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> #include <Swiften/Base/Log.h> #include <iostream> +#if 0 using namespace Swift; class OFakeRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector { @@ -87,16 +93,8 @@ public: class OFakeLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { public: - virtual void generateLocalTransportCandidates(JingleTransportPayload::ref /* payload */) { - //JingleTransportPayload::ref payL = make_shared<JingleTransportPayload>(); - //payL->setSessionID(payload->getSessionID()); - JingleS5BTransportPayload::ref payL = boost::make_shared<JingleS5BTransportPayload>(); - - onLocalTransportCandidatesGenerated(payL); - } - - void emitonLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { - onLocalTransportCandidatesGenerated(payload); + void emitonLocalTransportCandidatesGenerated(const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + onLocalTransportCandidatesGenerated(candidates); } virtual bool isActualCandidate(JingleTransportPayload::ref) { @@ -110,6 +108,16 @@ public: virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) { return JingleTransport::ref(); } + + virtual void start() SWIFTEN_OVERRIDE { + //JingleTransportPayload::ref payL = make_shared<JingleTransportPayload>(); + //payL->setSessionID(payload->getSessionID()); + // JingleS5BTransportPayload::ref payL = boost::make_shared<JingleS5BTransportPayload>(); + + onLocalTransportCandidatesGenerated(std::vector<JingleS5BTransportPayload::Candidate>()); + } + + virtual void stop() SWIFTEN_OVERRIDE {} }; class OFakeLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory { @@ -144,7 +152,7 @@ public: fileInfo.setName("test.bin"); fileInfo.setHash("asdjasdas"); fileInfo.setSize(1024 * 1024); - return boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(boost::shared_ptr<JingleSession>(fakeJingleSession), fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, idGen, JID(), to, stream, fileInfo, s5bRegistry, s5bProxy)); + return boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(boost::shared_ptr<JingleSession>(fakeJingleSession), fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, idGen, JID(), to, stream, fileInfo, s5bRegistry, s5bProxy, crypto.get())); } IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { @@ -154,6 +162,7 @@ public: } void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); fakeJingleSession = new FakeJingleSession("foo@bar.com/baz", "mysession"); jingleContentPayload = boost::make_shared<JingleContentPayload>(); fakeRJTCSF = boost::make_shared<OFakeRemoteJingleTransportCandidateSelectorFactory>(); @@ -164,7 +173,7 @@ public: timerFactory = new DummyTimerFactory(); connectionFactory = new DummyConnectionFactory(eventLoop); s5bRegistry = new SOCKS5BytestreamRegistry(); - s5bProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); + s5bProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); data.clear(); for (int n=0; n < 1024 * 1024; ++n) { @@ -275,9 +284,11 @@ private: IDGenerator* idGen; EventLoop *eventLoop; SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; + SOCKS5BytestreamProxiesManager* s5bProxy; DummyTimerFactory* timerFactory; DummyConnectionFactory* connectionFactory; + boost::shared_ptr<CryptoProvider> crypto; }; CPPUNIT_TEST_SUITE_REGISTRATION(OutgoingJingleFileTransferTest); +#endif diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp index 5fe096a..78ea8ed 100644 --- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp @@ -30,10 +30,12 @@ #include <Swiften/Network/DummyConnection.h> #include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; -boost::mt19937 randomGen; +static boost::mt19937 randomGen; class SOCKS5BytestreamClientSessionTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(SOCKS5BytestreamClientSessionTest); @@ -44,15 +46,13 @@ class SOCKS5BytestreamClientSessionTest : public CppUnit::TestFixture { CPPUNIT_TEST(testReadBytestream); CPPUNIT_TEST_SUITE_END(); - const HostAddressPort destinationAddressPort; - const std::string destination; - public: - SOCKS5BytestreamClientSessionTest() : destinationAddressPort(HostAddressPort(HostAddress("127.0.0.1"), 8888)), - destination(SOCKS5BytestreamRegistry::getHostname("foo", JID("requester@example.com/test"), JID("target@example.com/test"))), eventLoop(NULL), timerFactory(NULL) { } + SOCKS5BytestreamClientSessionTest() : destinationAddressPort(HostAddressPort(HostAddress("127.0.0.1"), 8888)) {} void setUp() { - randomGen.seed(time(NULL)); + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + destination = "092a44d859d19c9eed676b551ee80025903351c2"; + randomGen.seed(static_cast<unsigned int>(time(NULL))); eventLoop = new DummyEventLoop(); timerFactory = new DummyTimerFactory(); connection = boost::make_shared<MockeryConnection>(failingPorts, true, eventLoop); @@ -82,7 +82,7 @@ public: serverRespondHelloOK(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00\x03", 4), createByteArray(&helper.unprocessedInput[0], 4)); - CPPUNIT_ASSERT_EQUAL(createByteArray(destination.size()), createByteArray(helper.unprocessedInput[4])); + CPPUNIT_ASSERT_EQUAL(createByteArray(static_cast<char>(destination.size())), createByteArray(static_cast<char>(helper.unprocessedInput[4]))); CPPUNIT_ASSERT_EQUAL(createByteArray(destination), createByteArray(&helper.unprocessedInput[5], destination.size())); CPPUNIT_ASSERT_EQUAL(createByteArray("\x00", 1), createByteArray(&helper.unprocessedInput[5 + destination.size()], 1)); @@ -128,7 +128,7 @@ public: serverRespondHelloOK(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00\x03", 4), createByteArray(&helper.unprocessedInput[0], 4)); - CPPUNIT_ASSERT_EQUAL(createByteArray(destination.size()), createByteArray(helper.unprocessedInput[4])); + CPPUNIT_ASSERT_EQUAL(createByteArray(static_cast<char>(destination.size())), createByteArray(static_cast<char>(helper.unprocessedInput[4]))); CPPUNIT_ASSERT_EQUAL(createByteArray(destination), createByteArray(&helper.unprocessedInput[5], destination.size())); CPPUNIT_ASSERT_EQUAL(createByteArray("\x00", 1), createByteArray(&helper.unprocessedInput[5 + destination.size()], 1)); @@ -205,7 +205,7 @@ private: boost::variate_generator<boost::mt19937&, boost::uniform_int<> > randomByte(randomGen, dist); ByteArray result(len); for (size_t i=0; i < len; ++i ) { - result[i] = randomByte(); + result[i] = static_cast<unsigned char>(randomByte()); } return result; } @@ -221,7 +221,7 @@ private: void serverRespondRequestOK() { boost::shared_ptr<SafeByteArray> dataToSend = createSafeByteArrayRef("\x05\x00\x00\x03", 4); - append(*dataToSend, createSafeByteArray(destination.size())); + append(*dataToSend, createSafeByteArray(static_cast<char>(destination.size()))); append(*dataToSend, createSafeByteArray(destination)); append(*dataToSend, createSafeByteArray("\x00", 1)); connection->onDataRead(dataToSend); @@ -229,7 +229,7 @@ private: void serverRespondRequestFail() { boost::shared_ptr<SafeByteArray> correctData = createSafeByteArrayRef("\x05\x00\x00\x03", 4); - append(*correctData, createSafeByteArray(destination.size())); + append(*correctData, createSafeByteArray(static_cast<char>(destination.size()))); append(*correctData, createSafeByteArray(destination)); append(*correctData, createSafeByteArray("\x00", 1)); @@ -297,10 +297,13 @@ private: }; private: + HostAddressPort destinationAddressPort; + std::string destination; DummyEventLoop* eventLoop; DummyTimerFactory* timerFactory; boost::shared_ptr<MockeryConnection> connection; const std::vector<HostAddressPort> failingPorts; + boost::shared_ptr<CryptoProvider> crypto; }; CPPUNIT_TEST_SUITE_REGISTRATION(SOCKS5BytestreamClientSessionTest); diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp index 6dec37f..7af546f 100644 --- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp @@ -72,11 +72,11 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { void testRequest() { boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams->addReadBytestream("abcdef", stream1); + bytestreams->setHasBytestream("abcdef", true); authenticate(); ByteArray hostname(createByteArray("abcdef")); - receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(static_cast<char>(hostname.size())), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); CPPUNIT_ASSERT(createByteArray("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == createByteArray(&receivedData[0], 13)); } @@ -86,18 +86,18 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { authenticate(); ByteArray hostname(createByteArray("abcdef")); - receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(static_cast<char>(hostname.size())), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); CPPUNIT_ASSERT(createByteArray("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == receivedData); } void testReceiveData() { boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams->addReadBytestream("abcdef", stream1); + bytestreams->setHasBytestream("abcdef", true); authenticate(); request("abcdef"); eventLoop->processEvents(); - testling->startTransfer(); + testling->startSending(stream1); skipHeader("abcdef"); eventLoop->processEvents(); @@ -109,11 +109,11 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); testling->setChunkSize(3); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams->addReadBytestream("abcdef", stream1); + bytestreams->setHasBytestream("abcdef", true); authenticate(); request("abcdef"); eventLoop->processEvents(); - testling->startTransfer(); + testling->startSending(stream1); eventLoop->processEvents(); skipHeader("abcdef"); CPPUNIT_ASSERT(createByteArray("abcdefg") == receivedData); @@ -125,11 +125,11 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { testling->setChunkSize(3); stream1->setDataComplete(false); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams->addReadBytestream("abcdef", stream1); + bytestreams->setHasBytestream("abcdef", true); authenticate(); request("abcdef"); eventLoop->processEvents(); - testling->startTransfer(); + testling->startSending(stream1); eventLoop->processEvents(); skipHeader("abcdef"); CPPUNIT_ASSERT(createByteArray("abcdefg") == receivedData); @@ -144,11 +144,11 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { testling->setChunkSize(3); stream1->setDataComplete(false); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams->addReadBytestream("abcdef", stream1); + bytestreams->setHasBytestream("abcdef", true); authenticate(); request("abcdef"); eventLoop->processEvents(); - testling->startTransfer(); + testling->startSending(stream1); eventLoop->processEvents(); skipHeader("abcdef"); @@ -173,11 +173,11 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { } void request(const std::string& hostname) { - receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(static_cast<char>(hostname.size())), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); } void skipHeader(const std::string& hostname) { - int headerSize = 7 + hostname.size(); + size_t headerSize = 7 + hostname.size(); receivedData = createByteArray(&receivedData[headerSize], receivedData.size() - headerSize); } |