summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Smith <git@kismith.co.uk>2011-11-12 16:56:21 (GMT)
committerKevin Smith <git@kismith.co.uk>2011-12-13 08:17:58 (GMT)
commit81c09a0f6a3e87b078340d7f35d0dea4c03f3a6d (patch)
tree4371c5808ee26b2b5ed79ace9ccb439ff2988945 /Swiften/Session
parentfd17fe0d239f97cedebe4ceffa234155bd299b68 (diff)
downloadswift-contrib-81c09a0f6a3e87b078340d7f35d0dea4c03f3a6d.zip
swift-contrib-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.cpp215
-rw-r--r--Swiften/Session/BOSHSessionStream.h99
-rw-r--r--Swiften/Session/BasicSessionStream.cpp4
-rw-r--r--Swiften/Session/BasicSessionStream.h1
-rw-r--r--Swiften/Session/SessionStream.h1
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;