summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2011-05-26 18:46:49 (GMT)
committerRemko Tronçon <git@el-tramo.be>2011-09-25 17:42:32 (GMT)
commit4f62e5ec4b42929fe3c1a68667e63cb1b7a35509 (patch)
tree0d19fac3f578dec00ccf3e58930312951e38de89 /Swiften/FileTransfer/UnitTest
parentde660b763459cdd707876ec244b6866abca07fa2 (diff)
downloadswift-4f62e5ec4b42929fe3c1a68667e63cb1b7a35509.zip
swift-4f62e5ec4b42929fe3c1a68667e63cb1b7a35509.tar.bz2
Google Summer of Code 2011 Project: Adding support for Jingle File Transfers (XEP-0234), Jingle SOCKS5 Bytestreams Transport Method (XEP-0260), Jingle In-Band Bytestreams Transport Method (XEP-0261) and SOCKS5 Bytestreams (XEP-0065).
License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php
Diffstat (limited to 'Swiften/FileTransfer/UnitTest')
-rw-r--r--Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h36
-rw-r--r--Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp282
-rw-r--r--Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp283
-rw-r--r--Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp306
-rw-r--r--Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp16
5 files changed, 917 insertions, 6 deletions
diff --git a/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h b/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h
new file mode 100644
index 0000000..ae06cd3
--- /dev/null
+++ b/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <boost/filesystem.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+#include <Swiften/FileTransfer/FileTransferManager.h>
+
+namespace Swift {
+ class DummyFileTransferManager : public FileTransferManager {
+ public:
+ DummyFileTransferManager() : FileTransferManager() {
+ }
+
+ virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID&, const boost::filesystem::path&, const std::string&, boost::shared_ptr<ReadBytestream>) {
+ 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>) {
+ return OutgoingFileTransfer::ref();
+ }
+
+ virtual void startListeningOnPort(int) {
+ }
+
+ virtual void addS5BProxy(boost::shared_ptr<S5BProxyRequest>) {
+ }
+
+ };
+}
diff --git a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp
new file mode 100644
index 0000000..7407f44
--- /dev/null
+++ b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt 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/Log.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Elements/IBB.h>
+#include <Swiften/Elements/JingleIBBTransportPayload.h>
+#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/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 <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_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);
+ }
+
+ 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() {
+ 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);
+ }
+
+ void tearDown() {
+ delete bytestreamProxy;
+ delete connectionFactory;
+ delete timerFactory;
+ delete bytestreamRegistry;
+ delete iqRouter;
+ delete stanzaChannel;
+ delete eventLoop;
+ }
+
+ // Tests whether IncomingJingleFileTransfer would accept a IBB only file transfer.
+ void test_AcceptOnyIBBSendsSessionAccept() {
+ //1. create your test incoming file transfer
+ shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>();
+ desc->addOffer(StreamInitiationFileInfo());
+ jingleContentPayload->addDescription(desc);
+ JingleIBBTransportPayload::ref tpRef = make_shared<JingleIBBTransportPayload>();
+ tpRef->setSessionID("mysession");
+ jingleContentPayload->addTransport(tpRef);
+
+ shared_ptr<IncomingJingleFileTransfer> fileTransfer = createTestling();
+
+ //2. do 'accept' on a dummy writebytestream (you'll have to look if there already is one)
+ shared_ptr<ByteArrayWriteBytestream> byteStream = make_shared<ByteArrayWriteBytestream>();
+ fileTransfer->accept(byteStream);
+
+ // check whether accept has been called
+ getCall<FakeJingleSession::AcceptCall>(0);
+ }
+
+ void test_OnlyIBBTransferReceiveWorks() {
+ //1. create your test incoming file transfer
+ shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>();
+ desc->addOffer(StreamInitiationFileInfo());
+ jingleContentPayload->addDescription(desc);
+ JingleIBBTransportPayload::ref tpRef = make_shared<JingleIBBTransportPayload>();
+ tpRef->setSessionID("mysession");
+ jingleContentPayload->addTransport(tpRef);
+
+ shared_ptr<IncomingJingleFileTransfer> fileTransfer = createTestling();
+
+ //2. do 'accept' on a dummy writebytestream (you'll have to look if there already is one)
+ shared_ptr<ByteArrayWriteBytestream> byteStream = make_shared<ByteArrayWriteBytestream>();
+ fileTransfer->accept(byteStream);
+
+ // check whether accept has been called
+ getCall<FakeJingleSession::AcceptCall>(0);
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a"));
+ CPPUNIT_ASSERT(createByteArray("abc") == byteStream->getData());
+ }
+
+ void test_AcceptFailingS5BFallsBackToIBB() {
+ //1. create your test incoming file transfer
+ addFileTransferDescription();
+
+ // add SOCKS5BytestreamTransportPayload
+ JingleS5BTransportPayload::ref payLoad = addJingleS5BPayload();
+
+ shared_ptr<IncomingJingleFileTransfer> fileTransfer = createTestling();
+
+ //2. do 'accept' on a dummy writebytestream (you'll have to look if there already is one)
+ shared_ptr<ByteArrayWriteBytestream> byteStream = make_shared<ByteArrayWriteBytestream>();
+ fileTransfer->accept(byteStream);
+
+ // check whether accept has been called
+ FakeJingleSession::AcceptCall acceptCall = getCall<FakeJingleSession::AcceptCall>(0);
+ CPPUNIT_ASSERT_EQUAL(payLoad->getSessionID(), acceptCall.payload->getSessionID());
+
+ // check for candidate error
+ FakeJingleSession::InfoTransportCall infoTransportCall = getCall<FakeJingleSession::InfoTransportCall>(1);
+ JingleS5BTransportPayload::ref s5bPayload = dynamic_pointer_cast<JingleS5BTransportPayload>(infoTransportCall.payload);
+ CPPUNIT_ASSERT(s5bPayload->hasCandidateError());
+
+ // indicate transport replace (Romeo)
+ fakeJingleSession->onTransportReplaceReceived(getContentID(), addJingleIBBPayload());
+
+ FakeJingleSession::AcceptTransportCall acceptTransportCall = getCall<FakeJingleSession::AcceptTransportCall>(2);
+
+ // send a bit of data
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a"));
+ CPPUNIT_ASSERT(createByteArray("abc") == byteStream->getData());
+ }
+
+ void test_S5BTransferReceiveTest() {
+ addFileTransferDescription();
+ JingleS5BTransportPayload::ref payLoad = addJingleS5BPayload();
+ }
+
+private:
+ void addFileTransferDescription() {
+ shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>();
+ desc->addOffer(StreamInitiationFileInfo());
+ jingleContentPayload->addDescription(desc);
+ }
+
+ shared_ptr<JingleS5BTransportPayload> addJingleS5BPayload() {
+ JingleS5BTransportPayload::ref payLoad = make_shared<JingleS5BTransportPayload>();
+ payLoad->setSessionID("mysession");
+ jingleContentPayload->addTransport(payLoad);
+ return payLoad;
+ }
+
+ shared_ptr<JingleIBBTransportPayload> addJingleIBBPayload() {
+ JingleIBBTransportPayload::ref payLoad = make_shared<JingleIBBTransportPayload>();
+ payLoad->setSessionID("mysession");
+ jingleContentPayload->addTransport(payLoad);
+ return payLoad;
+ }
+
+ JingleContentID getContentID() const {
+ return JingleContentID(jingleContentPayload->getName(), jingleContentPayload->getCreator());
+ }
+
+ 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(cmd);
+ return *cmd;
+ }
+
+private:
+ EventLoop* eventLoop;
+ FakeJingleSession* fakeJingleSession;
+ shared_ptr<JingleContentPayload> jingleContentPayload;
+ shared_ptr<FakeRemoteJingleTransportCandidateSelectorFactory> fakeRJTCSF;
+ shared_ptr<FakeLocalJingleTransportCandidateGeneratorFactory> fakeLJTCF;
+ DummyStanzaChannel* stanzaChannel;
+ IQRouter* iqRouter;
+ SOCKS5BytestreamRegistry* bytestreamRegistry;
+ DummyConnectionFactory* connectionFactory;
+ SOCKS5BytestreamProxy* bytestreamProxy;
+ DummyTimerFactory* timerFactory;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(IncomingJingleFileTransferTest);
diff --git a/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp
new file mode 100644
index 0000000..582c3e5
--- /dev/null
+++ b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <boost/bind.hpp>
+#include <boost/optional.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#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/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/IDGenerator.h>
+#include <Swiften/EventLoop/DummyEventLoop.h>
+#include <Swiften/Network/PlatformNATTraversalWorker.h>
+#include <Swiften/Network/DummyTimerFactory.h>
+#include <Swiften/Network/DummyConnection.h>
+#include <Swiften/Network/ConnectionFactory.h>
+#include <Swiften/Network/DummyConnectionFactory.h>
+
+#include <Swiften/Base/Log.h>
+
+#include <iostream>
+
+using namespace Swift;
+
+class OFakeRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector {
+ void addRemoteTransportCandidates(JingleTransportPayload::ref cand) {
+ candidate = cand;
+ }
+
+ void selectCandidate() {
+ JingleS5BTransportPayload::ref payload = boost::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 OFakeRemoteJingleTransportCandidateSelectorFactory : public RemoteJingleTransportCandidateSelectorFactory {
+public:
+ virtual ~OFakeRemoteJingleTransportCandidateSelectorFactory() {
+
+ }
+
+ virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() {
+ return new OFakeRemoteJingleTransportCandidateSelector();
+ }
+};
+
+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);
+ }
+
+ virtual bool isActualCandidate(JingleTransportPayload::ref) {
+ return false;
+ }
+
+ virtual int getPriority(JingleTransportPayload::ref) {
+ return 0;
+ }
+
+ virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) {
+ return JingleTransport::ref();
+ }
+};
+
+class OFakeLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory {
+public:
+ virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() {
+ return new OFakeLocalJingleTransportCandidateGenerator();
+ }
+};
+
+class OutgoingJingleFileTransferTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(OutgoingJingleFileTransferTest);
+ CPPUNIT_TEST(test_SendSessionInitiateOnStart);
+ CPPUNIT_TEST(test_IBBStartsAfterSendingSessionAccept);
+ CPPUNIT_TEST(test_ReceiveSessionTerminateAfterSessionInitiate);
+ CPPUNIT_TEST_SUITE_END();
+
+ class FTStatusHelper {
+ public:
+ bool finishedCalled;
+ FileTransferError::Type error;
+ void handleFileTransferFinished(boost::optional<FileTransferError> error) {
+ finishedCalled = true;
+ if (error.is_initialized()) this->error = error.get().getType();
+ }
+ };
+public:
+
+ boost::shared_ptr<OutgoingJingleFileTransfer> createTestling() {
+ JID to("test@foo.com/bla");
+ StreamInitiationFileInfo fileInfo;
+ fileInfo.setDescription("some file");
+ 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, to, stream, fileInfo, s5bRegistry, s5bProxy));
+ }
+
+ 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() {
+ fakeJingleSession = new FakeJingleSession("foo@bar.com/baz", "mysession");
+ jingleContentPayload = boost::make_shared<JingleContentPayload>();
+ fakeRJTCSF = boost::make_shared<OFakeRemoteJingleTransportCandidateSelectorFactory>();
+ fakeLJTCF = boost::make_shared<OFakeLocalJingleTransportCandidateGeneratorFactory>();
+ stanzaChannel = new DummyStanzaChannel();
+ iqRouter = new IQRouter(stanzaChannel);
+ eventLoop = new DummyEventLoop();
+ timerFactory = new DummyTimerFactory();
+ connectionFactory = new DummyConnectionFactory(eventLoop);
+ s5bRegistry = new SOCKS5BytestreamRegistry();
+ s5bProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory);
+
+ data.clear();
+ for (int n=0; n < 1024 * 1024; ++n) {
+ data.push_back(34);
+ }
+
+ stream = boost::make_shared<ByteArrayReadBytestream>(data);
+
+ idGen = new IDGenerator();
+ }
+
+ void tearDown() {
+ delete idGen;
+ delete s5bRegistry;
+ 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_EQUAL(static_cast<size_t>(1), description->getOffers().size());
+ CPPUNIT_ASSERT(static_cast<size_t>(1048576) == description->getOffers()[0].getSize());
+
+ JingleS5BTransportPayload::ref transport = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(call.payload);
+ CPPUNIT_ASSERT(transport);
+ }
+
+ void test_IBBStartsAfterSendingSessionAccept() {
+ boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling();
+ transfer->start();
+
+ FakeJingleSession::InitiateCall call = getCall<FakeJingleSession::InitiateCall>(0);
+ // FIXME: we initiate with SOCSK5 now and not IBB, needs to be fixed.
+ /*
+ fakeJingleSession->onSessionAcceptReceived(call.id, call.description, call.payload);
+ IQ::ref iqOpenStanza = stanzaChannel->getStanzaAtIndex<IQ>(0);
+ CPPUNIT_ASSERT(iqOpenStanza);
+ */
+ }
+
+ void test_ReceiveSessionTerminateAfterSessionInitiate() {
+ boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling();
+ transfer->start();
+
+ getCall<FakeJingleSession::InitiateCall>(0);
+
+ FTStatusHelper helper;
+ helper.finishedCalled = false;
+ transfer->onFinished.connect(bind(&FTStatusHelper::handleFileTransferFinished, &helper, _1));
+ fakeJingleSession->onSessionTerminateReceived(JinglePayload::Reason(JinglePayload::Reason::Busy));
+ CPPUNIT_ASSERT_EQUAL(true, helper.finishedCalled);
+ CPPUNIT_ASSERT(FileTransferError::PeerError == helper.error);
+ }
+
+
+//TODO: some more testcases
+
+private:
+ void addFileTransferDescription() {
+ boost::shared_ptr<JingleFileTransferDescription> desc = boost::make_shared<JingleFileTransferDescription>();
+ desc->addOffer(StreamInitiationFileInfo());
+ jingleContentPayload->addDescription(desc);
+ }
+
+ boost::shared_ptr<JingleS5BTransportPayload> addJingleS5BPayload() {
+ JingleS5BTransportPayload::ref payLoad = boost::make_shared<JingleS5BTransportPayload>();
+ payLoad->setSessionID("mysession");
+ jingleContentPayload->addTransport(payLoad);
+ return payLoad;
+ }
+
+ boost::shared_ptr<JingleIBBTransportPayload> addJingleIBBPayload() {
+ JingleIBBTransportPayload::ref payLoad = boost::make_shared<JingleIBBTransportPayload>();
+ payLoad->setSessionID("mysession");
+ jingleContentPayload->addTransport(payLoad);
+ return payLoad;
+ }
+
+ JingleContentID getContentID() const {
+ return JingleContentID(jingleContentPayload->getName(), jingleContentPayload->getCreator());
+ }
+
+ 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(cmd);
+ return *cmd;
+ }
+
+private:
+ std::vector<unsigned char> data;
+ boost::shared_ptr<ByteArrayReadBytestream> stream;
+ FakeJingleSession* fakeJingleSession;
+ boost::shared_ptr<JingleContentPayload> jingleContentPayload;
+ boost::shared_ptr<OFakeRemoteJingleTransportCandidateSelectorFactory> fakeRJTCSF;
+ boost::shared_ptr<OFakeLocalJingleTransportCandidateGeneratorFactory> fakeLJTCF;
+ DummyStanzaChannel* stanzaChannel;
+ IQRouter* iqRouter;
+ IDGenerator* idGen;
+ EventLoop *eventLoop;
+ SOCKS5BytestreamRegistry* s5bRegistry;
+ SOCKS5BytestreamProxy* s5bProxy;
+ DummyTimerFactory* timerFactory;
+ DummyConnectionFactory* connectionFactory;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(OutgoingJingleFileTransferTest);
diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp
new file mode 100644
index 0000000..35580bf
--- /dev/null
+++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Base/ByteArray.h>
+#include <QA/Checker/IO.h>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <boost/bind.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Base/Algorithm.h>
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/Base/Concat.h>
+#include <Swiften/Base/Log.h>
+#include <Swiften/Base/StartStopper.h>
+#include <Swiften/EventLoop/DummyEventLoop.h>
+#include <Swiften/FileTransfer/ByteArrayReadBytestream.h>
+#include <Swiften/FileTransfer/ByteArrayWriteBytestream.h>
+#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h>
+#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Network/DummyConnection.h>
+#include <Swiften/Network/DummyTimerFactory.h>
+#include <Swiften/StringCodecs/Hexify.h>
+
+using namespace Swift;
+
+boost::mt19937 randomGen;
+
+class SOCKS5BytestreamClientSessionTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(SOCKS5BytestreamClientSessionTest);
+ CPPUNIT_TEST(testForSessionReady);
+ CPPUNIT_TEST(testErrorHandlingHello);
+ CPPUNIT_TEST(testErrorHandlingRequest);
+ CPPUNIT_TEST(testWriteBytestream);
+ 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) { }
+
+ void setUp() {
+ randomGen.seed(time(NULL));
+ eventLoop = new DummyEventLoop();
+ timerFactory = new DummyTimerFactory();
+ connection = boost::make_shared<MockeryConnection>(failingPorts, true, eventLoop);
+ //connection->onDataSent.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleDataWritten, this, _1));
+ //stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(createByteArray("abcdefg")));
+// connection->onDataRead.connect(boost::bind(&SOCKS5BytestreamClientSessionTest::handleDataRead, this, _1));
+ }
+
+ void tearDown() {
+ //connection.reset();
+ delete timerFactory;
+ delete eventLoop;
+ }
+
+ void testForSessionReady() {
+ TestHelper helper;
+ connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1));
+
+ SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory);
+ clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1));
+
+ clientSession->start();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT(createByteArray("\x05\x01\x00", 3) == helper.unprocessedInput);
+
+ helper.unprocessedInput.clear();
+ 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(destination), createByteArray(&helper.unprocessedInput[5], destination.size()));
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\x00", 1), createByteArray(&helper.unprocessedInput[5 + destination.size()], 1));
+
+ helper.unprocessedInput.clear();
+ serverRespondRequestOK();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled);
+ CPPUNIT_ASSERT_EQUAL(false, helper.sessionReadyError);
+ }
+
+ void testErrorHandlingHello() {
+ TestHelper helper;
+ connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1));
+
+ SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory);
+ clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1));
+
+ clientSession->start();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00", 3), helper.unprocessedInput);
+
+ helper.unprocessedInput.clear();
+ serverRespondHelloAuthFail();
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled);
+ CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyError);
+ CPPUNIT_ASSERT_EQUAL(true, connection->disconnectCalled);
+ }
+
+ void testErrorHandlingRequest() {
+ TestHelper helper;
+ connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1));
+
+ SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory);
+ clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1));
+
+ clientSession->start();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00", 3), helper.unprocessedInput);
+
+ helper.unprocessedInput.clear();
+ 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(destination), createByteArray(&helper.unprocessedInput[5], destination.size()));
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\x00", 1), createByteArray(&helper.unprocessedInput[5 + destination.size()], 1));
+
+ helper.unprocessedInput.clear();
+ serverRespondRequestFail();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled);
+ CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyError);
+ CPPUNIT_ASSERT_EQUAL(true, connection->disconnectCalled);
+ }
+
+ void testWriteBytestream() {
+ TestHelper helper;
+ connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1));
+
+ SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory);
+ clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1));
+
+ clientSession->start();
+ eventLoop->processEvents();
+
+ helper.unprocessedInput.clear();
+ serverRespondHelloOK();
+ eventLoop->processEvents();
+
+ helper.unprocessedInput.clear();
+ serverRespondRequestOK();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled);
+ CPPUNIT_ASSERT_EQUAL(false, helper.sessionReadyError);
+
+ boost::shared_ptr<ByteArrayWriteBytestream> output = boost::make_shared<ByteArrayWriteBytestream>();
+ clientSession->startReceiving(output);
+
+ ByteArray transferData = generateRandomByteArray(1024);
+ connection->onDataRead(createSafeByteArray(transferData.data(), transferData.size()));
+ CPPUNIT_ASSERT_EQUAL(transferData, output->getData());
+ }
+
+ void testReadBytestream() {
+ TestHelper helper;
+ connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1));
+
+ SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory);
+ clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1));
+
+ clientSession->start();
+ eventLoop->processEvents();
+
+ helper.unprocessedInput.clear();
+ serverRespondHelloOK();
+ eventLoop->processEvents();
+
+ helper.unprocessedInput.clear();
+ serverRespondRequestOK();
+ eventLoop->processEvents();
+ CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled);
+ CPPUNIT_ASSERT_EQUAL(false, helper.sessionReadyError);
+
+ helper.unprocessedInput.clear();
+ ByteArray transferData = generateRandomByteArray(1024 * 1024);
+ boost::shared_ptr<ByteArrayReadBytestream> input = boost::make_shared<ByteArrayReadBytestream>(transferData);
+ clientSession->startSending(input);
+ eventLoop->processEvents();
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray(transferData.data(), transferData.size()), helper.unprocessedInput);
+ }
+
+
+
+private:
+ static ByteArray generateRandomByteArray(size_t len) {
+ boost::uniform_int<> dist(0, 255);
+ 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();
+ }
+ return result;
+ }
+
+ // Server responses
+ void serverRespondHelloOK() {
+ connection->onDataRead(createSafeByteArray("\x05\00", 2));
+ }
+
+ void serverRespondHelloAuthFail() {
+ connection->onDataRead(createSafeByteArray("\x05\xFF", 2));
+ }
+
+ void serverRespondRequestOK() {
+ SafeByteArray dataToSend = createSafeByteArray("\x05\x00\x00\x03", 4);
+ append(dataToSend, createSafeByteArray(destination.size()));
+ append(dataToSend, createSafeByteArray(destination));
+ append(dataToSend, createSafeByteArray("\x00", 1));
+ connection->onDataRead(dataToSend);
+ }
+
+ void serverRespondRequestFail() {
+ SafeByteArray correctData = createSafeByteArray("\x05\x00\x00\x03", 4);
+ append(correctData, createSafeByteArray(destination.size()));
+ append(correctData, createSafeByteArray(destination));
+ append(correctData, createSafeByteArray("\x00", 1));
+
+ SafeByteArray dataToSend;
+ //ByteArray failingData = Hexify::unhexify("8417947d1d305c72c11520ea7d2c6e787396705e72c312c6ccc3f66613d7cae1b91b7ab48e8b59a17d559c15fb51");
+ //append(dataToSend, failingData);
+ //SWIFT_LOG(debug) << "hexed: " << Hexify::hexify(failingData) << std::endl;
+ do {
+ ByteArray rndArray = generateRandomByteArray(correctData.size());
+ dataToSend = createSafeByteArray(rndArray.data(), rndArray.size());
+ } while (dataToSend == correctData);
+ connection->onDataRead(dataToSend);
+ }
+
+private:
+ struct TestHelper {
+ TestHelper() : sessionReadyCalled(false), sessionReadyError(false) {}
+ ByteArray unprocessedInput;
+ bool sessionReadyCalled;
+ bool sessionReadyError;
+
+ void handleConnectionDataWritten(const SafeByteArray& data) {
+ append(unprocessedInput, data);
+ //SWIFT_LOG(debug) << "unprocessedInput (" << unprocessedInput.size() << "): " << Hexify::hexify(unprocessedInput) << std::endl;
+ }
+
+ void handleSessionReady(bool error) {
+ sessionReadyCalled = true;
+ sessionReadyError = error;
+ }
+ };
+
+
+private:
+ struct MockeryConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<MockeryConnection> {
+ public:
+ MockeryConnection(const std::vector<HostAddressPort>& failingPorts, bool isResponsive, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), isResponsive(isResponsive), disconnectCalled(false) {}
+
+ void listen() { assert(false); }
+ void connect(const HostAddressPort& address) {
+ hostAddressPort = address;
+ if (isResponsive) {
+ bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end();
+ eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail));
+ }
+ }
+
+ HostAddressPort getLocalAddress() const { return HostAddressPort(); }
+ void disconnect() {
+ disconnectCalled = true;
+ }
+
+ void write(const SafeByteArray& data) {
+ eventLoop->postEvent(boost::ref(onDataWritten), shared_from_this());
+ onDataSent(data);
+ }
+
+ boost::signal<void (const SafeByteArray&)> onDataSent;
+
+ EventLoop* eventLoop;
+ boost::optional<HostAddressPort> hostAddressPort;
+ std::vector<HostAddressPort> failingPorts;
+ bool isResponsive;
+ bool disconnectCalled;
+ };
+
+private:
+ DummyEventLoop* eventLoop;
+ DummyTimerFactory* timerFactory;
+ boost::shared_ptr<MockeryConnection> connection;
+ const std::vector<HostAddressPort> failingPorts;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SOCKS5BytestreamClientSessionTest);
diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
index 06bc98f..cd480f0 100644
--- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
+++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
@@ -34,6 +34,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
void setUp() {
receivedDataChunks = 0;
eventLoop = new DummyEventLoop();
+ bytestreams = new SOCKS5BytestreamRegistry();
connection = boost::shared_ptr<DummyConnection>(new DummyConnection(eventLoop));
connection->onDataSent.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleDataWritten, this, _1));
stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(createByteArray("abcdefg")));
@@ -41,6 +42,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
void tearDown() {
connection.reset();
+ delete bytestreams;
delete eventLoop;
}
@@ -67,7 +69,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
void testRequest() {
boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession());
StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get());
- bytestreams.addBytestream("abcdef", stream1);
+ bytestreams->addReadBytestream("abcdef", stream1);
authenticate();
ByteArray hostname(createByteArray("abcdef"));
@@ -88,10 +90,11 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
void testReceiveData() {
boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession());
StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get());
- bytestreams.addBytestream("abcdef", stream1);
+ bytestreams->addReadBytestream("abcdef", stream1);
authenticate();
request("abcdef");
eventLoop->processEvents();
+ testling->startTransfer();
skipHeader("abcdef");
CPPUNIT_ASSERT(createByteArray("abcdefg") == receivedData);
@@ -102,11 +105,12 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession());
testling->setChunkSize(3);
StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get());
- bytestreams.addBytestream("abcdef", stream1);
+ bytestreams->addReadBytestream("abcdef", stream1);
authenticate();
request("abcdef");
eventLoop->processEvents();
-
+ testling->startTransfer();
+ eventLoop->processEvents();
skipHeader("abcdef");
CPPUNIT_ASSERT(createByteArray("abcdefg") == receivedData);
CPPUNIT_ASSERT_EQUAL(4, receivedDataChunks);
@@ -141,13 +145,13 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
private:
SOCKS5BytestreamServerSession* createSession() {
- SOCKS5BytestreamServerSession* session = new SOCKS5BytestreamServerSession(connection, &bytestreams);
+ SOCKS5BytestreamServerSession* session = new SOCKS5BytestreamServerSession(connection, bytestreams);
return session;
}
private:
DummyEventLoop* eventLoop;
- SOCKS5BytestreamRegistry bytestreams;
+ SOCKS5BytestreamRegistry* bytestreams;
boost::shared_ptr<DummyConnection> connection;
std::vector<unsigned char> receivedData;
int receivedDataChunks;