diff options
author | Kevin Smith <git@kismith.co.uk> | 2011-11-12 16:56:21 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2011-12-13 08:17:58 (GMT) |
commit | 81c09a0f6a3e87b078340d7f35d0dea4c03f3a6d (patch) | |
tree | 4371c5808ee26b2b5ed79ace9ccb439ff2988945 /Swiften/Session | |
parent | fd17fe0d239f97cedebe4ceffa234155bd299b68 (diff) | |
download | swift-81c09a0f6a3e87b078340d7f35d0dea4c03f3a6d.zip swift-81c09a0f6a3e87b078340d7f35d0dea4c03f3a6d.tar.bz2 |
BOSH Support for Swiften
This adds support for BOSH to Swiften. It does not expose it to Swift.
Release-Notes: Swiften now allows connects over BOSH, if used appropriately.
Diffstat (limited to 'Swiften/Session')
-rw-r--r-- | Swiften/Session/BOSHSessionStream.cpp | 215 | ||||
-rw-r--r-- | Swiften/Session/BOSHSessionStream.h | 99 | ||||
-rw-r--r-- | Swiften/Session/BasicSessionStream.cpp | 4 | ||||
-rw-r--r-- | Swiften/Session/BasicSessionStream.h | 1 | ||||
-rw-r--r-- | Swiften/Session/SessionStream.h | 1 |
5 files changed, 320 insertions, 0 deletions
diff --git a/Swiften/Session/BOSHSessionStream.cpp b/Swiften/Session/BOSHSessionStream.cpp new file mode 100644 index 0000000..95390f4 --- /dev/null +++ b/Swiften/Session/BOSHSessionStream.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#include <Swiften/Session/BOSHSessionStream.h> + +#include <boost/bind.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/variate_generator.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/StreamType.h> +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/StreamStack/StreamStack.h> +#include <Swiften/StreamStack/ConnectionLayer.h> +#include <Swiften/StreamStack/WhitespacePingLayer.h> +#include <Swiften/StreamStack/CompressionLayer.h> +#include <Swiften/StreamStack/TLSLayer.h> +#include <Swiften/TLS/TLSContextFactory.h> +#include <Swiften/TLS/TLSContext.h> +#include <Swiften/EventLoop/EventLoop.h> + +namespace Swift { + +BOSHSessionStream::BOSHSessionStream( + boost::shared_ptr<BOSHConnectionFactory> connectionFactory, /*FIXME: probably rip out*/ + PayloadParserFactoryCollection* payloadParserFactories, + PayloadSerializerCollection* payloadSerializers, + TLSContextFactory* tlsContextFactory, + TimerFactory* timerFactory, + XMLParserFactory* xmlParserFactory, + EventLoop* eventLoop, + const std::string& to, + const URL& boshHTTPConnectProxyURL, + const SafeString& boshHTTPConnectProxyAuthID, + const SafeString& boshHTTPConnectProxyAuthPassword) : + available(false), + payloadParserFactories(payloadParserFactories), + payloadSerializers(payloadSerializers), + tlsContextFactory(tlsContextFactory), + timerFactory(timerFactory), + xmlParserFactory(xmlParserFactory), + eventLoop(eventLoop), + firstHeader(true) { + + boost::mt19937 random; + boost::uniform_int<> dist(0, LONG_MAX); + random.seed(time(NULL)); + boost::variate_generator<boost::mt19937&, boost::uniform_int<> > randomRID(random, dist); + long initialRID = randomRID(); + + connectionPool = new BOSHConnectionPool(connectionFactory, to, initialRID, boshHTTPConnectProxyURL, boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); + connectionPool->onSessionTerminated.connect(boost::bind(&BOSHSessionStream::handlePoolSessionTerminated, this, _1)); + connectionPool->onSessionStarted.connect(boost::bind(&BOSHSessionStream::handlePoolSessionStarted, this)); + connectionPool->onXMPPDataRead.connect(boost::bind(&BOSHSessionStream::handlePoolXMPPDataRead, this, _1)); + connectionPool->onBOSHDataRead.connect(boost::bind(&BOSHSessionStream::handlePoolBOSHDataRead, this, _1)); + connectionPool->onBOSHDataWritten.connect(boost::bind(&BOSHSessionStream::handlePoolBOSHDataWritten, this, _1)); + + xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, ClientStreamType); + xmppLayer->onStreamStart.connect(boost::bind(&BOSHSessionStream::handleStreamStartReceived, this, _1)); + xmppLayer->onElement.connect(boost::bind(&BOSHSessionStream::handleElementReceived, this, _1)); + xmppLayer->onError.connect(boost::bind(&BOSHSessionStream::handleXMPPError, this)); + xmppLayer->onWriteData.connect(boost::bind(&BOSHSessionStream::handleXMPPLayerDataWritten, this, _1)); + + available = true; +} + +BOSHSessionStream::~BOSHSessionStream() { + close(); + connectionPool->onSessionTerminated.disconnect(boost::bind(&BOSHSessionStream::handlePoolSessionTerminated, this, _1)); + connectionPool->onSessionStarted.disconnect(boost::bind(&BOSHSessionStream::handlePoolSessionStarted, this)); + connectionPool->onXMPPDataRead.disconnect(boost::bind(&BOSHSessionStream::handlePoolXMPPDataRead, this, _1)); + connectionPool->onBOSHDataRead.disconnect(boost::bind(&BOSHSessionStream::handlePoolBOSHDataRead, this, _1)); + connectionPool->onBOSHDataWritten.disconnect(boost::bind(&BOSHSessionStream::handlePoolBOSHDataWritten, this, _1)); + delete connectionPool; + connectionPool = NULL; + xmppLayer->onStreamStart.disconnect(boost::bind(&BOSHSessionStream::handleStreamStartReceived, this, _1)); + xmppLayer->onElement.disconnect(boost::bind(&BOSHSessionStream::handleElementReceived, this, _1)); + xmppLayer->onError.disconnect(boost::bind(&BOSHSessionStream::handleXMPPError, this)); + xmppLayer->onWriteData.disconnect(boost::bind(&BOSHSessionStream::handleXMPPLayerDataWritten, this, _1)); + delete xmppLayer; + xmppLayer = NULL; +} + +void BOSHSessionStream::handlePoolXMPPDataRead(const SafeByteArray& data) { + xmppLayer->handleDataRead(data); +} + +void BOSHSessionStream::writeElement(boost::shared_ptr<Element> element) { + assert(available); + xmppLayer->writeElement(element); +} + +void BOSHSessionStream::writeFooter() { + connectionPool->writeFooter(); +} + +void BOSHSessionStream::writeData(const std::string& data) { + assert(available); + xmppLayer->writeData(data); +} + +void BOSHSessionStream::close() { + connectionPool->close(); +} + +bool BOSHSessionStream::isOpen() { + return available; +} + +bool BOSHSessionStream::supportsTLSEncryption() { + return false; +} + +void BOSHSessionStream::addTLSEncryption() { + assert(available); +} + +bool BOSHSessionStream::isTLSEncrypted() { + return false; +} + +Certificate::ref BOSHSessionStream::getPeerCertificate() const { + return Certificate::ref(); +} + +boost::shared_ptr<CertificateVerificationError> BOSHSessionStream::getPeerCertificateVerificationError() const { + return boost::shared_ptr<CertificateVerificationError>(); +} + +ByteArray BOSHSessionStream::getTLSFinishMessage() const { + return ByteArray(); +} + +bool BOSHSessionStream::supportsZLibCompression() { + return false; +} + +void BOSHSessionStream::addZLibCompression() { + +} + +void BOSHSessionStream::setWhitespacePingEnabled(bool /*enabled*/) { + return; +} + +void BOSHSessionStream::resetXMPPParser() { + xmppLayer->resetParser(); +} + +void BOSHSessionStream::handleStreamStartReceived(const ProtocolHeader& header) { + onStreamStartReceived(header); +} + +void BOSHSessionStream::handleElementReceived(boost::shared_ptr<Element> element) { + onElementReceived(element); +} + +void BOSHSessionStream::handleXMPPError() { + available = false; + onClosed(boost::shared_ptr<Error>(new Error(Error::ParseError))); +} + +void BOSHSessionStream::handlePoolSessionStarted() { + fakeStreamHeaderReceipt(); +} + +void BOSHSessionStream::handlePoolSessionTerminated(BOSHError::ref error) { + eventLoop->postEvent(boost::bind(&BOSHSessionStream::fakeStreamFooterReceipt, this, error), shared_from_this()); +} + +void BOSHSessionStream::writeHeader(const ProtocolHeader& header) { + streamHeader = header; + /*First time we're told to do this, don't (the sending of the initial header is handled on connect) + On subsequent requests we should restart the stream the BOSH way. + */ + if (!firstHeader) { + eventLoop->postEvent(boost::bind(&BOSHSessionStream::fakeStreamHeaderReceipt, this), shared_from_this()); + eventLoop->postEvent(boost::bind(&BOSHConnectionPool::restartStream, connectionPool), shared_from_this()); + } + firstHeader = false; +} + + +void BOSHSessionStream::fakeStreamHeaderReceipt() { + std::stringstream header; + header << "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='"; + header << streamHeader.getTo() << "' id='dummy' version='1.0'>"; + + xmppLayer->handleDataRead(createSafeByteArray(header.str())); +} + +void BOSHSessionStream::fakeStreamFooterReceipt(BOSHError::ref error) { + std::string footer("</stream:stream>"); + xmppLayer->handleDataRead(createSafeByteArray(footer)); + onClosed(error); +} + +void BOSHSessionStream::handleXMPPLayerDataWritten(const SafeByteArray& data) { + eventLoop->postEvent(boost::bind(&BOSHConnectionPool::write, connectionPool, data), shared_from_this()); +} + +void BOSHSessionStream::handlePoolBOSHDataRead(const SafeByteArray& data) { + onDataRead(data); +} + +void BOSHSessionStream::handlePoolBOSHDataWritten(const SafeByteArray& data) { + onDataWritten(data); +} + +}; diff --git a/Swiften/Session/BOSHSessionStream.h b/Swiften/Session/BOSHSessionStream.h new file mode 100644 index 0000000..75c1f2a --- /dev/null +++ b/Swiften/Session/BOSHSessionStream.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011 Kevin Smith + * 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/SafeString.h> +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Network/BOSHConnectionPool.h> +#include <Swiften/Network/BOSHConnectionFactory.h> +#include <Swiften/Session/SessionStream.h> +#include <Swiften/Elements/StreamType.h> +#include <Swiften/EventLoop/EventOwner.h> + +namespace Swift { + class TimerFactory; + class PayloadParserFactoryCollection; + class PayloadSerializerCollection; + class StreamStack; + class XMPPLayer; + class ConnectionLayer; + class CompressionLayer; + class XMLParserFactory; + class TLSContextFactory; + class EventLoop; + + class BOSHSessionStream : public SessionStream, public EventOwner, public boost::enable_shared_from_this<BOSHSessionStream> { + public: + BOSHSessionStream( + boost::shared_ptr<BOSHConnectionFactory> connectionFactory, + PayloadParserFactoryCollection* payloadParserFactories, + PayloadSerializerCollection* payloadSerializers, + TLSContextFactory* tlsContextFactory, + TimerFactory* whitespacePingLayerFactory, + XMLParserFactory* xmlParserFactory, + EventLoop* eventLoop, + const std::string& to, + const URL& boshHTTPConnectProxyURL, + const SafeString& boshHTTPConnectProxyAuthID, + const SafeString& boshHTTPConnectProxyAuthPassword + ); + ~BOSHSessionStream(); + + virtual void close(); + virtual bool isOpen(); + + virtual void writeHeader(const ProtocolHeader& header); + virtual void writeElement(boost::shared_ptr<Element>); + virtual void writeFooter(); + virtual void writeData(const std::string& data); + + virtual bool supportsZLibCompression(); + virtual void addZLibCompression(); + + virtual bool supportsTLSEncryption(); + virtual void addTLSEncryption(); + virtual bool isTLSEncrypted(); + virtual Certificate::ref getPeerCertificate() const; + virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const; + virtual ByteArray getTLSFinishMessage() const; + + virtual void setWhitespacePingEnabled(bool); + + virtual void resetXMPPParser(); + + private: + void handleXMPPError(); + void handleStreamStartReceived(const ProtocolHeader&); + void handleElementReceived(boost::shared_ptr<Element>); + void handlePoolXMPPDataRead(const SafeByteArray& data); + void handleXMPPLayerDataWritten(const SafeByteArray& data); + void handlePoolSessionStarted(); + void handlePoolBOSHDataRead(const SafeByteArray& data); + void handlePoolBOSHDataWritten(const SafeByteArray& data); + void handlePoolSessionTerminated(BOSHError::ref condition); + + private: + void fakeStreamHeaderReceipt(); + void fakeStreamFooterReceipt(BOSHError::ref error); + + private: + BOSHConnectionPool* connectionPool; + bool available; + PayloadParserFactoryCollection* payloadParserFactories; + PayloadSerializerCollection* payloadSerializers; + TLSContextFactory* tlsContextFactory; + TimerFactory* timerFactory; + XMLParserFactory* xmlParserFactory; + XMPPLayer* xmppLayer; + ProtocolHeader streamHeader; + EventLoop* eventLoop; + bool firstHeader; + }; + +} diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp index 07a04b8..70bbeea 100644 --- a/Swiften/Session/BasicSessionStream.cpp +++ b/Swiften/Session/BasicSessionStream.cpp @@ -136,6 +136,10 @@ ByteArray BasicSessionStream::getTLSFinishMessage() const { return tlsLayer->getContext()->getFinishMessage(); } +bool BasicSessionStream::supportsZLibCompression() { + return true; +} + void BasicSessionStream::addZLibCompression() { compressionLayer = new CompressionLayer(); streamStack->addLayer(compressionLayer); diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h index 2ed5ac6..b0c4331 100644 --- a/Swiften/Session/BasicSessionStream.h +++ b/Swiften/Session/BasicSessionStream.h @@ -47,6 +47,7 @@ namespace Swift { virtual void writeFooter(); virtual void writeData(const std::string& data); + virtual bool supportsZLibCompression(); virtual void addZLibCompression(); virtual bool supportsTLSEncryption(); diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h index e6b9469..096f185 100644 --- a/Swiften/Session/SessionStream.h +++ b/Swiften/Session/SessionStream.h @@ -46,6 +46,7 @@ namespace Swift { virtual void writeElement(boost::shared_ptr<Element>) = 0; virtual void writeData(const std::string& data) = 0; + virtual bool supportsZLibCompression() = 0; virtual void addZLibCompression() = 0; virtual bool supportsTLSEncryption() = 0; |