1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/*
* Copyright (c) 2011 Tobias Markmann
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
#include <Swiften/FileTransfer/FileTransferManagerImpl.h>
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#include <Swiften/Base/foreach.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/OutgoingFileTransferManager.h>
#include <Swiften/FileTransfer/IncomingFileTransferManager.h>
#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h>
#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h>
#include <Swiften/Presence/PresenceOracle.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/Network/ConnectionFactory.h>
#include <Swiften/Network/ConnectionServerFactory.h>
#include <Swiften/Network/HostAddress.h>
#include <Swiften/Network/NATTraverser.h>
#include <Swiften/Base/BoostFilesystemVersion.h>
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) {
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);
incomingFTManager->onIncomingFileTransfer.connect(onIncomingFileTransfer);
}
FileTransferManagerImpl::~FileTransferManagerImpl() {
if (s5bProxyFinder) {
s5bProxyFinder->stop();
delete s5bProxyFinder;
}
if (bytestreamServer) {
bytestreamServer->stop();
delete bytestreamServer;
}
delete incomingFTManager;
delete outgoingFTManager;
delete remoteCandidateSelectorFactory;
delete localCandidateGeneratorFactory;
delete connectivityManager;
}
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::addS5BProxy(S5BProxyRequest::ref proxy) {
bytestreamProxy->addS5BProxy(proxy);
}
boost::optional<JID> FileTransferManagerImpl::highestPriorityJIDSupportingFileTransfer(const JID& bareJID) {
JID fullReceipientJID;
int priority = INT_MIN;
//getAllPresence(bareJID) gives you all presences for the bare JID (i.e. all resources) Remko Tronçon @ 11:11
std::vector<Presence::ref> presences = presenceOracle->getAllPresence(bareJID);
//iterate over them
foreach(Presence::ref pres, presences) {
if (pres->getPriority() > priority) {
// look up caps from the jid
DiscoInfo::ref info = capsProvider->getCaps(pres->getFrom());
if (info && info->hasFeature(DiscoInfo::JingleFeature) && info->hasFeature(DiscoInfo::JingleFTFeature) && (info->hasFeature(DiscoInfo::JingleTransportsIBBFeature) || info->hasFeature(DiscoInfo::JingleTransportsS5BFeature))) {
priority = pres->getPriority();
fullReceipientJID = pres->getFrom();
}
}
}
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) {
#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();
#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);
}
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) {
StreamInitiationFileInfo fileInfo;
fileInfo.setDate(lastModified);
fileInfo.setSize(sizeInBytes);
fileInfo.setName(filename);
fileInfo.setDescription(description);
JID receipient = to;
if(receipient.isBare()) {
boost::optional<JID> fullJID = highestPriorityJIDSupportingFileTransfer(receipient);
if (fullJID.is_initialized()) {
receipient = fullJID.get();
} else {
return OutgoingFileTransfer::ref();
}
}
return outgoingFTManager->createOutgoingFileTransfer(ownJID, receipient, bytestream, fileInfo);
}
}
|