summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/FileTransfer')
-rw-r--r--Swiften/FileTransfer/IncomingFileTransferManager.cpp4
-rw-r--r--Swiften/FileTransfer/IncomingJingleFileTransfer.cpp14
-rw-r--r--Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp40
-rw-r--r--Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp6
-rw-r--r--Swiften/FileTransfer/UnitTest/DummyFileTransferTransporterFactory.h16
-rw-r--r--Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp11
6 files changed, 64 insertions, 27 deletions
diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.cpp b/Swiften/FileTransfer/IncomingFileTransferManager.cpp
index c1cc757..f5b95ec 100644
--- a/Swiften/FileTransfer/IncomingFileTransferManager.cpp
+++ b/Swiften/FileTransfer/IncomingFileTransferManager.cpp
@@ -1,66 +1,66 @@
/*
- * Copyright (c) 2010-2015 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/FileTransfer/IncomingFileTransferManager.h>
#include <boost/smart_ptr/make_shared.hpp>
#include <Swiften/Base/Log.h>
#include <Swiften/Elements/JingleDescription.h>
#include <Swiften/Elements/JingleFileTransferDescription.h>
#include <Swiften/Elements/JingleIBBTransportPayload.h>
#include <Swiften/Elements/JingleS5BTransportPayload.h>
#include <Swiften/FileTransfer/IncomingJingleFileTransfer.h>
#include <Swiften/Jingle/Jingle.h>
#include <Swiften/Jingle/JingleSessionManager.h>
namespace Swift {
IncomingFileTransferManager::IncomingFileTransferManager(
JingleSessionManager* jingleSessionManager,
FileTransferTransporterFactory* transporterFactory,
TimerFactory* timerFactory,
CryptoProvider* crypto) :
jingleSessionManager(jingleSessionManager),
transporterFactory(transporterFactory),
timerFactory(timerFactory),
crypto(crypto) {
jingleSessionManager->addIncomingSessionHandler(this);
}
IncomingFileTransferManager::~IncomingFileTransferManager() {
jingleSessionManager->removeIncomingSessionHandler(this);
}
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<JingleS5BTransportPayload>()) {
+ if (content->getTransport<JingleS5BTransportPayload>() || content->getTransport<JingleIBBTransportPayload>()) {
JingleFileTransferDescription::ref description = content->getDescription<JingleFileTransferDescription>();
if (description) {
IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(
recipient, session, content, transporterFactory, timerFactory, crypto);
onIncomingFileTransfer(transfer);
}
else {
SWIFT_LOG(warning) << "Received a file-transfer request with no file description.";
session->sendTerminate(JinglePayload::Reason::FailedApplication);
}
}
else {
session->sendTerminate(JinglePayload::Reason::UnsupportedTransports);
}
return true;
}
else {
return false;
}
}
}
diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
index 8cb1cab..db17620 100644
--- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
@@ -1,49 +1,50 @@
/*
* Copyright (c) 2011-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/FileTransfer/IncomingJingleFileTransfer.h>
#include <set>
#include <boost/bind.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <Swiften/Base/Log.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/JingleFileTransferDescription.h>
#include <Swiften/Elements/JingleFileTransferHash.h>
#include <Swiften/Elements/JingleIBBTransportPayload.h>
#include <Swiften/Elements/JingleS5BTransportPayload.h>
+#include <Swiften/FileTransfer/FileTransferOptions.h>
#include <Swiften/FileTransfer/FileTransferTransporter.h>
#include <Swiften/FileTransfer/FileTransferTransporterFactory.h>
#include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h>
#include <Swiften/FileTransfer/TransportSession.h>
#include <Swiften/FileTransfer/WriteBytestream.h>
#include <Swiften/Jingle/JingleSession.h>
#include <Swiften/Network/TimerFactory.h>
#include <Swiften/Queries/GenericRequest.h>
#include <Swiften/StringCodecs/Base64.h>
using namespace Swift;
// TODO: ALlow terminate when already terminated.
IncomingJingleFileTransfer::IncomingJingleFileTransfer(
const JID& toJID,
JingleSession::ref session,
JingleContentPayload::ref content,
FileTransferTransporterFactory* transporterFactory,
TimerFactory* timerFactory,
CryptoProvider* crypto) :
JingleFileTransfer(session, toJID, transporterFactory),
initialContent(content),
crypto(crypto),
state(Initial),
receivedBytes(0),
hashCalculator(NULL) {
description = initialContent->getDescription<JingleFileTransferDescription>();
assert(description);
JingleFileTransferFileInfo fileInfo = description->getFileInfo();
@@ -55,83 +56,86 @@ IncomingJingleFileTransfer::IncomingJingleFileTransfer(
boost::bind(&IncomingJingleFileTransfer::handleWaitOnHashTimerTicked, this));
}
IncomingJingleFileTransfer::~IncomingJingleFileTransfer() {
if (waitOnHashTimer) {
waitOnHashTimer->stop();
}
delete hashCalculator;
hashCalculator = NULL;
}
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;
assert(!hashCalculator);
hashCalculator = new IncrementalBytestreamHashCalculator(
hashes.find("md5") != hashes.end(), hashes.find("sha-1") != hashes.end(), crypto);
writeStreamDataReceivedConnection = stream->onWrite.connect(
boost::bind(&IncomingJingleFileTransfer::handleWriteStreamDataReceived, this, _1));
- if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) {
+ JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>();
+ JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>();
+ if (s5bTransport) {
SWIFT_LOG(debug) << "Got S5B transport as initial payload." << std::endl;
setTransporter(transporterFactory->createResponderTransporter(
getInitiator(), getResponder(), s5bTransport->getSessionID(), options));
transporter->addRemoteCandidates(s5bTransport->getCandidates(), s5bTransport->getDstAddr());
setState(GeneratingInitialLocalCandidates);
transporter->startGeneratingLocalCandidates();
}
- else if (JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>()) {
+ else if (ibbTransport && options.isInBandAllowed()) {
SWIFT_LOG(debug) << "Got IBB transport as initial payload." << std::endl;
setTransporter(transporterFactory->createResponderTransporter(
getInitiator(), getResponder(), ibbTransport->getSessionID(), options));
startTransferring(transporter->createIBBReceiveSession(
ibbTransport->getSessionID(),
description->getFileInfo().getSize(),
stream));
session->sendAccept(getContentID(), initialContent->getDescriptions()[0], ibbTransport);
}
else {
- // Can't happen, because the transfer would have been rejected automatically
- assert(false);
+ // This might happen on incoming transfer which only list transport methods we are not allowed to use due to file-transfer options.
+ session->sendTerminate(JinglePayload::Reason::UnsupportedTransports);
+ setFinishedState(FileTransfer::State::Failed, FileTransferError(FileTransferError::PeerError));
}
}
void IncomingJingleFileTransfer::cancel() {
SWIFT_LOG(debug) << std::endl;
terminate(state == Initial ? JinglePayload::Reason::Decline : JinglePayload::Reason::Cancel);
}
void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(
const std::string& s5bSessionID,
const std::vector<JingleS5BTransportPayload::Candidate>& candidates,
const std::string& dstAddr) {
SWIFT_LOG(debug) << std::endl;
if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; }
fillCandidateMap(localCandidates, candidates);
JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>();
transport->setSessionID(s5bSessionID);
transport->setMode(JingleS5BTransportPayload::TCPMode);
transport->setDstAddr(dstAddr);
foreach(JingleS5BTransportPayload::Candidate candidate, candidates) {
transport->addCandidate(candidate);
}
session->sendAccept(getContentID(), initialContent->getDescriptions()[0], transport);
setState(TryingCandidates);
transporter->startTryingRemoteCandidates();
}
@@ -196,61 +200,61 @@ void IncomingJingleFileTransfer::checkIfAllDataReceived() {
foreach(const JingleFileTransferFileInfo::HashElementMap::value_type& hashElement, hashes) {
hashInfoAvailable |= !hashElement.second.empty();
}
if (!hashInfoAvailable) {
SWIFT_LOG(debug) << "No hash information yet. Waiting a while on hash info." << std::endl;
setState(WaitingForHash);
waitOnHashTimer->start();
}
else {
checkHashAndTerminate();
}
}
else if (receivedBytes > getFileSizeInBytes()) {
SWIFT_LOG(debug) << "We got more than we could handle!" << std::endl;
terminate(JinglePayload::Reason::MediaError);
}
}
void IncomingJingleFileTransfer::handleWriteStreamDataReceived(
const std::vector<unsigned char>& data) {
hashCalculator->feedData(data);
receivedBytes += data.size();
onProcessedBytes(data.size());
checkIfAllDataReceived();
}
void IncomingJingleFileTransfer::handleTransportReplaceReceived(
const JingleContentID& content, JingleTransportPayload::ref transport) {
SWIFT_LOG(debug) << std::endl;
- if (state != WaitingForFallbackOrTerminate) {
+ if (state != WaitingForFallbackOrTerminate) {
SWIFT_LOG(warning) << "Incorrect state" << std::endl;
return;
}
JingleIBBTransportPayload::ref ibbTransport;
if (options.isInBandAllowed() && (ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport))) {
SWIFT_LOG(debug) << "transport replaced with IBB" << std::endl;
startTransferring(transporter->createIBBReceiveSession(
ibbTransport->getSessionID(),
description->getFileInfo().getSize(),
stream));
session->sendTransportAccept(content, ibbTransport);
}
else {
SWIFT_LOG(debug) << "Unknown replace transport" << std::endl;
session->sendTransportReject(content, transport);
}
}
JingleContentID IncomingJingleFileTransfer::getContentID() const {
return JingleContentID(initialContent->getName(), initialContent->getCreator());
}
bool IncomingJingleFileTransfer::verifyData() {
if (hashes.empty()) {
SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl;
return true;
}
if (hashes.find("sha-1") != hashes.end()) {
diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
index a72d5ef..2c43766 100644
--- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp
@@ -66,91 +66,100 @@ OutgoingJingleFileTransfer::OutgoingJingleFileTransfer(
// calculate both, MD5 and SHA-1 since we don't know which one the other side supports
hashCalculator = new IncrementalBytestreamHashCalculator(true, true, crypto);
stream->onRead.connect(
boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1));
waitForRemoteTermination = timerFactory->createTimer(5000);
waitForRemoteTermination->onTick.connect(boost::bind(&OutgoingJingleFileTransfer::handleWaitForRemoteTerminationTimeout, this));
}
OutgoingJingleFileTransfer::~OutgoingJingleFileTransfer() {
if (waitForRemoteTermination) {
waitForRemoteTermination->onTick.disconnect(boost::bind(&OutgoingJingleFileTransfer::handleWaitForRemoteTerminationTimeout, this));
waitForRemoteTermination->stop();
}
stream->onRead.disconnect(
boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1));
delete hashCalculator;
hashCalculator = NULL;
removeTransporter();
}
void OutgoingJingleFileTransfer::start() {
SWIFT_LOG(debug) << std::endl;
if (state != Initial) {
SWIFT_LOG(warning) << "Incorrect state" << std::endl;
return;
}
- setTransporter(transporterFactory->createInitiatorTransporter(getInitiator(), getResponder(), options));
- setInternalState(GeneratingInitialLocalCandidates);
- transporter->startGeneratingLocalCandidates();
+ if (!options.isInBandAllowed() && !options.isDirectAllowed() && !options.isAssistedAllowed() && !options.isProxiedAllowed()) {
+ // Started outgoing file transfer while not supporting transport methods.
+ setFinishedState(FileTransfer::State::Failed, FileTransferError(FileTransferError::UnknownError));
+ }
+ else {
+ setTransporter(transporterFactory->createInitiatorTransporter(getInitiator(), getResponder(), options));
+ setInternalState(GeneratingInitialLocalCandidates);
+ transporter->startGeneratingLocalCandidates();
+ }
}
void OutgoingJingleFileTransfer::cancel() {
terminate(JinglePayload::Reason::Cancel);
}
void OutgoingJingleFileTransfer::terminate(JinglePayload::Reason::Type reason) {
SWIFT_LOG(debug) << reason << std::endl;
if (state != Initial && state != GeneratingInitialLocalCandidates && state != Finished) {
session->sendTerminate(reason);
}
stopAll();
setFinishedState(getExternalFinishedState(reason), getFileTransferError(reason));
}
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(), s5bPayload->getDstAddr());
setInternalState(TryingCandidates);
transporter->startTryingRemoteCandidates();
}
+ else if (JingleIBBTransportPayload::ref ibbPayload = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transportPayload)) {
+ startTransferring(transporter->createIBBSendSession(ibbPayload->getSessionID(), ibbPayload->getBlockSize().get_value_or(DEFAULT_BLOCK_SIZE), stream));
+ }
else {
SWIFT_LOG(debug) << "Unknown transport payload. Falling back." << std::endl;
fallback();
}
}
void OutgoingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) {
SWIFT_LOG(debug) << std::endl;
if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state: " << state << std::endl; return; }
stopAll();
if (state == WaitForTermination) {
waitForRemoteTermination->stop();
}
if (reason && reason->type == JinglePayload::Reason::Cancel) {
setFinishedState(FileTransfer::State::Canceled, FileTransferError(FileTransferError::PeerError));
}
else if (reason && reason->type == JinglePayload::Reason::Decline) {
setFinishedState(FileTransfer::State::Canceled, boost::optional<FileTransferError>());
}
else if (reason && reason->type == JinglePayload::Reason::Success) {
setFinishedState(FileTransfer::State::Finished, boost::optional<FileTransferError>());
}
else {
setFinishedState(FileTransfer::State::Failed, FileTransferError(FileTransferError::PeerError));
}
}
void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleContentID&, JingleTransportPayload::ref transport) {
SWIFT_LOG(debug) << std::endl;
@@ -165,67 +174,78 @@ void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleConte
}
}
void OutgoingJingleFileTransfer::handleTransportRejectReceived(const JingleContentID &, boost::shared_ptr<JingleTransportPayload>) {
SWIFT_LOG(debug) << std::endl;
terminate(JinglePayload::Reason::UnsupportedTransports);
}
void OutgoingJingleFileTransfer::sendSessionInfoHash() {
SWIFT_LOG(debug) << std::endl;
JingleFileTransferHash::ref hashElement = boost::make_shared<JingleFileTransferHash>();
hashElement->getFileInfo().addHash(HashElement("sha-1", hashCalculator->getSHA1Hash()));
hashElement->getFileInfo().addHash(HashElement("md5", hashCalculator->getMD5Hash()));
session->sendInfo(hashElement);
}
void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated(
const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>& candidates, const std::string& dstAddr) {
SWIFT_LOG(debug) << std::endl;
if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state: " << state << std::endl; return; }
fillCandidateMap(localCandidates, candidates);
JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>();
fileInfo.addHash(HashElement("sha-1", ByteArray()));
fileInfo.addHash(HashElement("md5", ByteArray()));
description->setFileInfo(fileInfo);
- JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>();
- transport->setSessionID(s5bSessionID);
- transport->setMode(JingleS5BTransportPayload::TCPMode);
- transport->setDstAddr(dstAddr);
- foreach(JingleS5BTransportPayload::Candidate candidate, candidates) {
- transport->addCandidate(candidate);
- SWIFT_LOG(debug) << "\t" << "S5B candidate: " << candidate.hostPort.toString() << std::endl;
+ JingleTransportPayload::ref transport;
+ if (candidates.empty()) {
+ SWIFT_LOG(debug) << "no S5B candidates generated. Send IBB transport candidate." << std::endl;
+ JingleIBBTransportPayload::ref ibbTransport = boost::make_shared<JingleIBBTransportPayload>();
+ ibbTransport->setBlockSize(DEFAULT_BLOCK_SIZE);
+ ibbTransport->setSessionID(idGenerator->generateID());
+ transport = ibbTransport;
+ }
+ else {
+ JingleS5BTransportPayload::ref s5bTransport = boost::make_shared<JingleS5BTransportPayload>();
+ s5bTransport->setSessionID(s5bSessionID);
+ s5bTransport->setMode(JingleS5BTransportPayload::TCPMode);
+ s5bTransport->setDstAddr(dstAddr);
+ foreach(JingleS5BTransportPayload::Candidate candidate, candidates) {
+ s5bTransport->addCandidate(candidate);
+ SWIFT_LOG(debug) << "\t" << "S5B candidate: " << candidate.hostPort.toString() << std::endl;
+ }
+ transport = s5bTransport;
}
setInternalState(WaitingForAccept);
session->sendInitiate(contentID, description, transport);
}
void OutgoingJingleFileTransfer::fallback() {
if (options.isInBandAllowed()) {
SWIFT_LOG(debug) << "Trying to fallback to IBB transport." << std::endl;
JingleIBBTransportPayload::ref ibbTransport = boost::make_shared<JingleIBBTransportPayload>();
ibbTransport->setBlockSize(DEFAULT_BLOCK_SIZE);
ibbTransport->setSessionID(idGenerator->generateID());
setInternalState(FallbackRequested);
session->sendTransportReplace(contentID, ibbTransport);
}
else {
SWIFT_LOG(debug) << "Fallback to IBB transport not allowed." << std::endl;
terminate(JinglePayload::Reason::ConnectivityError);
}
}
void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) {
SWIFT_LOG(debug) << std::endl;
if (state != Transferring) { SWIFT_LOG(warning) << "Incorrect state: " << state << std::endl; return; }
if (error) {
terminate(JinglePayload::Reason::ConnectivityError);
}
else {
sendSessionInfoHash();
diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp
index 7b97698..3b1be89 100644
--- a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp
+++ b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp
@@ -1,32 +1,32 @@
/*
- * Copyright (c) 2012-2015 Isode Limited.
+ * Copyright (c) 2012-2016 Isode Limited.
* All rights reserved.
* See the COPYING file 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/bind.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <Swiften/Base/Log.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamServerPortForwardingUser.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamServerResourceUser.h>
#include <Swiften/Network/ConnectionServer.h>
#include <Swiften/Network/ConnectionServerFactory.h>
#include <Swiften/Network/NATTraversalForwardPortRequest.h>
#include <Swiften/Network/NATTraversalGetPublicIPRequest.h>
#include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h>
#include <Swiften/Network/NATTraverser.h>
#include <Swiften/Network/NetworkEnvironment.h>
using namespace Swift;
@@ -165,60 +165,64 @@ void SOCKS5BytestreamServerManager::setupPortForwarding() {
// Forward ports
int port = server->getAddressPort().getPort();
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::removePortForwarding() {
// remove port forwards
if (portMapping) {
unforwardPortRequest = natTraverser->createRemovePortForwardingRequest(portMapping.get().getLocalPort(), portMapping.get().getPublicPort());
unforwardPortRequest->onResult.connect(boost::bind(&SOCKS5BytestreamServerManager::handleUnforwardPortResult, this, _1));
unforwardPortRequest->start();
}
}
void SOCKS5BytestreamServerManager::stop() {
if (getPublicIPRequest) {
getPublicIPRequest->stop();
getPublicIPRequest.reset();
}
if (forwardPortRequest) {
forwardPortRequest->stop();
forwardPortRequest.reset();
}
+ if (unforwardPortRequest) {
+ unforwardPortRequest->stop();
+ unforwardPortRequest.reset();
+ }
if (server) {
server->stop();
delete server;
server = NULL;
}
if (connectionServer) {
connectionServer->stop();
connectionServer.reset();
}
state = 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();
}
void SOCKS5BytestreamServerManager::handleForwardPortResult(boost::optional<NATPortMapping> mapping) {
if (mapping) {
SWIFT_LOG(debug) << "Mapping port was successful." << std::endl;
diff --git a/Swiften/FileTransfer/UnitTest/DummyFileTransferTransporterFactory.h b/Swiften/FileTransfer/UnitTest/DummyFileTransferTransporterFactory.h
index 324404d..00a931f 100644
--- a/Swiften/FileTransfer/UnitTest/DummyFileTransferTransporterFactory.h
+++ b/Swiften/FileTransfer/UnitTest/DummyFileTransferTransporterFactory.h
@@ -1,87 +1,94 @@
/*
- * Copyright (c) 2015 Isode Limited.
+ * Copyright (c) 2015-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <string>
#include <Swiften/Base/API.h>
-#include <Swiften/StringCodecs/Hexify.h>
#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/FileTransfer/FileTransferOptions.h>
#include <Swiften/FileTransfer/FileTransferTransporter.h>
#include <Swiften/FileTransfer/FileTransferTransporterFactory.h>
#include <Swiften/FileTransfer/IBBReceiveSession.h>
#include <Swiften/FileTransfer/IBBReceiveTransportSession.h>
-#include <Swiften/FileTransfer/IBBSendTransportSession.h>
#include <Swiften/FileTransfer/IBBSendSession.h>
+#include <Swiften/FileTransfer/IBBSendTransportSession.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h>
#include <Swiften/FileTransfer/TransportSession.h>
#include <Swiften/JID/JID.h>
+#include <Swiften/StringCodecs/Hexify.h>
namespace Swift {
class DummyFileTransferTransporter : public FileTransferTransporter {
public:
enum Role {
Initiator,
Responder
};
public:
DummyFileTransferTransporter(
const JID& initiator,
const JID& responder,
Role role,
SOCKS5BytestreamRegistry* s5bRegistry,
SOCKS5BytestreamServerManager* /* s5bServerManager */,
SOCKS5BytestreamProxiesManager* /* s5bProxy */,
IDGenerator* /* idGenerator */,
ConnectionFactory*,
TimerFactory*,
CryptoProvider* cryptoProvider,
IQRouter* iqRouter,
- const FileTransferOptions&) : initiator_(initiator), responder_(responder), role_(role), s5bRegistry_(s5bRegistry), crypto_(cryptoProvider), iqRouter_(iqRouter) {
+ const FileTransferOptions& ftOptions) : initiator_(initiator), responder_(responder), role_(role), s5bRegistry_(s5bRegistry), crypto_(cryptoProvider), iqRouter_(iqRouter), ftOptions_(ftOptions) {
}
void initialize() {
s5bSessionID_ = s5bRegistry_->generateSessionID();
}
virtual void startGeneratingLocalCandidates() {
std::vector<JingleS5BTransportPayload::Candidate> candidates;
+ if (ftOptions_.isDirectAllowed()) {
+ JingleS5BTransportPayload::Candidate candidate;
+ candidate.cid = "123";
+ candidate.priority = 1235;
+ candidates.push_back(candidate);
+ }
onLocalCandidatesGenerated(s5bSessionID_, candidates, getSOCKS5DstAddr());
}
virtual void stopGeneratingLocalCandidates() {
}
virtual void addRemoteCandidates(const std::vector<JingleS5BTransportPayload::Candidate>&, const std::string&) {
}
virtual void startTryingRemoteCandidates() {
onRemoteCandidateSelectFinished(s5bSessionID_, boost::optional<JingleS5BTransportPayload::Candidate>());
}
virtual void stopTryingRemoteCandidates() {
}
virtual void startActivatingProxy(const JID& /* proxy */) {
}
virtual void stopActivatingProxy() {
}
virtual boost::shared_ptr<TransportSession> createIBBSendSession(const std::string& sessionID, unsigned int blockSize, boost::shared_ptr<ReadBytestream> stream) {
boost::shared_ptr<IBBSendSession> ibbSession = boost::make_shared<IBBSendSession>(
sessionID, initiator_, responder_, stream, iqRouter_);
ibbSession->setBlockSize(blockSize);
return boost::make_shared<IBBSendTransportSession>(ibbSession);
}
virtual boost::shared_ptr<TransportSession> createIBBReceiveSession(const std::string& sessionID, unsigned long long size, boost::shared_ptr<WriteBytestream> stream) {
@@ -112,60 +119,61 @@ public:
private:
std::string getSOCKS5DstAddr() const {
std::string result;
if (role_ == Initiator) {
result = getInitiatorCandidateSOCKS5DstAddr();
}
else {
result = getResponderCandidateSOCKS5DstAddr();
}
return result;
}
std::string getInitiatorCandidateSOCKS5DstAddr() const {
return Hexify::hexify(crypto_->getSHA1Hash(createSafeByteArray(s5bSessionID_ + initiator_.toString() + responder_.toString())));
}
std::string getResponderCandidateSOCKS5DstAddr() const {
return Hexify::hexify(crypto_->getSHA1Hash(createSafeByteArray(s5bSessionID_ + responder_.toString() + initiator_.toString())));
}
private:
JID initiator_;
JID responder_;
Role role_;
SOCKS5BytestreamRegistry* s5bRegistry_;
CryptoProvider* crypto_;
std::string s5bSessionID_;
IQRouter* iqRouter_;
+ FileTransferOptions ftOptions_;
};
class DummyFileTransferTransporterFactory : public FileTransferTransporterFactory {
public:
DummyFileTransferTransporterFactory(
SOCKS5BytestreamRegistry* s5bRegistry,
SOCKS5BytestreamServerManager* s5bServerManager,
SOCKS5BytestreamProxiesManager* s5bProxy,
IDGenerator* idGenerator,
ConnectionFactory* connectionFactory,
TimerFactory* timerFactory,
CryptoProvider* cryptoProvider,
IQRouter* iqRouter) : s5bRegistry_(s5bRegistry), s5bServerManager_(s5bServerManager), s5bProxy_(s5bProxy), idGenerator_(idGenerator), connectionFactory_(connectionFactory), timerFactory_(timerFactory), cryptoProvider_(cryptoProvider), iqRouter_(iqRouter) {
}
virtual ~DummyFileTransferTransporterFactory() {
}
virtual FileTransferTransporter* createInitiatorTransporter(const JID& initiator, const JID& responder, const FileTransferOptions& options) {
DummyFileTransferTransporter* transporter = new DummyFileTransferTransporter(
initiator,
responder,
DummyFileTransferTransporter::Initiator,
s5bRegistry_,
s5bServerManager_,
s5bProxy_,
idGenerator_,
connectionFactory_,
timerFactory_,
diff --git a/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp
index f3fe42e..fee26d5 100644
--- a/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp
+++ b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp
@@ -1,38 +1,38 @@
/*
* Copyright (c) 2011 Tobias Markmann
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
/*
- * Copyright (c) 2013-2015 Isode Limited.
+ * Copyright (c) 2013-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <iostream>
#include <boost/bind.hpp>
#include <boost/optional.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <Swiften/Base/ByteArray.h>
#include <Swiften/Base/IDGenerator.h>
#include <Swiften/Base/Override.h>
#include <Swiften/Client/DummyStanzaChannel.h>
#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/Crypto/PlatformCryptoProvider.h>
#include <Swiften/Elements/IBB.h>
#include <Swiften/Elements/JingleFileTransferDescription.h>
#include <Swiften/Elements/JingleIBBTransportPayload.h>
#include <Swiften/Elements/JingleS5BTransportPayload.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
#include <Swiften/FileTransfer/ByteArrayReadBytestream.h>
#include <Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h>
#include <Swiften/FileTransfer/OutgoingJingleFileTransfer.h>
#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h>
#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h>
@@ -54,76 +54,76 @@ using namespace Swift;
class OutgoingJingleFileTransferTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(OutgoingJingleFileTransferTest);
CPPUNIT_TEST(test_SendSessionInitiateOnStart);
CPPUNIT_TEST(test_FallbackToIBBAfterFailingS5B);
CPPUNIT_TEST(test_ReceiveSessionTerminateAfterSessionInitiate);
CPPUNIT_TEST(test_DeclineEmitsFinishedStateCanceled);
CPPUNIT_TEST_SUITE_END();
class FTStatusHelper {
public:
FTStatusHelper() : finishedCalled(false), error(FileTransferError::UnknownError) {
}
void handleFileTransferFinished(boost::optional<FileTransferError> error) {
finishedCalled = true;
if (error.is_initialized()) this->error = error.get().getType();
}
void handleFileTransferStatusChanged(FileTransfer::State fileTransferSTate) {
state = fileTransferSTate;
}
public:
bool finishedCalled;
FileTransferError::Type error;
boost::optional<FileTransfer::State> state;
};
public:
- boost::shared_ptr<OutgoingJingleFileTransfer> createTestling() {
+ boost::shared_ptr<OutgoingJingleFileTransfer> createTestling(const FileTransferOptions& options = FileTransferOptions().withAssistedAllowed(false).withDirectAllowed(false).withProxiedAllowed(false)) {
JID to("test@foo.com/bla");
JingleFileTransferFileInfo fileInfo;
fileInfo.setDescription("some file");
fileInfo.setName("test.bin");
fileInfo.addHash(HashElement("sha-1", ByteArray()));
fileInfo.setSize(1024 * 1024);
return boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(
to,
boost::shared_ptr<JingleSession>(fakeJingleSession),
stream,
ftTransportFactory,
timerFactory,
idGen,
fileInfo,
- FileTransferOptions().withAssistedAllowed(false).withDirectAllowed(false).withProxiedAllowed(false),
+ options,
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;
}
void setUp() {
crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
fakeJingleSession = new FakeJingleSession("foo@bar.com/baz", "mysession");
jingleContentPayload = boost::make_shared<JingleContentPayload>();
stanzaChannel = new DummyStanzaChannel();
iqRouter = new IQRouter(stanzaChannel);
eventLoop = new DummyEventLoop();
timerFactory = new DummyTimerFactory();
connectionFactory = new DummyConnectionFactory(eventLoop);
serverConnectionFactory = new DummyConnectionServerFactory(eventLoop);
s5bRegistry = new SOCKS5BytestreamRegistry();
networkEnvironment = new PlatformNetworkEnvironment();
natTraverser = new PlatformNATTraversalWorker(eventLoop);
bytestreamServerManager = new SOCKS5BytestreamServerManager(s5bRegistry, serverConnectionFactory, networkEnvironment, natTraverser);
data.clear();
for (int n=0; n < 1024 * 1024; ++n) {
data.push_back(34);
}
stream = boost::make_shared<ByteArrayReadBytestream>(data);
@@ -132,70 +132,71 @@ public:
s5bProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory, resolver, iqRouter, "bar.com");
ftTransportFactory = new DummyFileTransferTransporterFactory(s5bRegistry, bytestreamServerManager, s5bProxy, idGen, connectionFactory, timerFactory, crypto.get(), iqRouter);
}
void tearDown() {
delete ftTransportFactory;
delete s5bProxy;
delete idGen;
delete bytestreamServerManager;
delete natTraverser;
delete networkEnvironment;
delete s5bRegistry;
delete serverConnectionFactory;
delete connectionFactory;
delete timerFactory;
delete eventLoop;
delete iqRouter;
delete stanzaChannel;
}
void test_SendSessionInitiateOnStart() {
boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling();
transfer->start();
FakeJingleSession::InitiateCall call = getCall<FakeJingleSession::InitiateCall>(0);
JingleFileTransferDescription::ref description = boost::dynamic_pointer_cast<JingleFileTransferDescription>(call.description);
CPPUNIT_ASSERT(description);
CPPUNIT_ASSERT(static_cast<size_t>(1048576) == description->getFileInfo().getSize());
- JingleS5BTransportPayload::ref transport = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(call.payload);
+ JingleIBBTransportPayload::ref transport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(call.payload);
CPPUNIT_ASSERT(transport);
}
void test_FallbackToIBBAfterFailingS5B() {
- boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling();
+ boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling(FileTransferOptions().withAssistedAllowed(true).withDirectAllowed(true).withProxiedAllowed(true));
transfer->start();
FakeJingleSession::InitiateCall call = getCall<FakeJingleSession::InitiateCall>(0);
+ CPPUNIT_ASSERT(boost::dynamic_pointer_cast<JingleS5BTransportPayload>(call.payload));
fakeJingleSession->handleSessionAcceptReceived(call.id, call.description, call.payload);
// send candidate failure
JingleS5BTransportPayload::ref candidateFailurePayload = boost::make_shared<JingleS5BTransportPayload>();
candidateFailurePayload->setCandidateError(true);
candidateFailurePayload->setSessionID(call.payload->getSessionID());
fakeJingleSession->handleTransportInfoReceived(call.id, candidateFailurePayload);
// no S5B candidates -> fallback to IBB
// call at position 1 is the candidate our candidate error
FakeJingleSession::ReplaceTransportCall replaceCall = getCall<FakeJingleSession::ReplaceTransportCall>(2);
// accept transport replace
fakeJingleSession->handleTransportAcceptReceived(replaceCall.id, replaceCall.payload);
IQ::ref iqOpenStanza = stanzaChannel->getStanzaAtIndex<IQ>(0);
CPPUNIT_ASSERT(iqOpenStanza);
IBB::ref ibbOpen = iqOpenStanza->getPayload<IBB>();
CPPUNIT_ASSERT(ibbOpen);
CPPUNIT_ASSERT_EQUAL(IBB::Open, ibbOpen->getAction());
}
void test_ReceiveSessionTerminateAfterSessionInitiate() {
boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling();
transfer->start();
getCall<FakeJingleSession::InitiateCall>(0);
FTStatusHelper helper;
helper.finishedCalled = false;