From fd17fe0d239f97cedebe4ceffa234155bd299b68 Mon Sep 17 00:00:00 2001 From: Thilo Cestonaro <thilo@cestona.ro> Date: Thu, 29 Sep 2011 00:03:14 +0200 Subject: BOSH implementation started License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index a8a5c8f..08f31a0 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -24,6 +24,7 @@ #include <Swiften/Client/ClientSessionStanzaChannel.h> #include <Swiften/Network/SOCKS5ProxiedConnectionFactory.h> #include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> +#include <Swiften/Network/BOSHConnectionFactory.h> namespace Swift { @@ -69,7 +70,8 @@ void CoreClient::connect(const std::string& host) { proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getConnectionFactory(), networkFactories->getProxyProvider()->getHTTPConnectProxy())); } std::vector<ConnectionFactory*> connectionFactories(proxyConnectionFactories); - connectionFactories.push_back(networkFactories->getConnectionFactory()); + // connectionFactories.push_back(networkFactories->getConnectionFactory()); + connectionFactories.push_back(new BOSHConnectionFactory(networkFactories->getConnectionFactory())); connector_ = boost::make_shared<ChainedConnector>(host, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); diff --git a/Swiften/Network/BOSHConnection.cpp b/Swiften/Network/BOSHConnection.cpp new file mode 100644 index 0000000..549c652 --- /dev/null +++ b/Swiften/Network/BOSHConnection.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "BOSHConnection.h" +#include <boost/bind.hpp> +#include <boost/thread.hpp> +#include <string> + +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Base/String.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Parser/BOSHParser.h> + +namespace Swift { + + BOSHConnection::BOSHConnection(ConnectionFactory* connectionFactory) + : connectionFactory_(connectionFactory), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)), sid_() + { + reopenAfterAction = true; + } + + BOSHConnection::~BOSHConnection() { + if (newConnection_) { + newConnection_->onDataRead.disconnect(boost::bind(&BOSHConnection::handleDataRead, shared_from_this(), _1)); + newConnection_->onDisconnected.disconnect(boost::bind(&BOSHConnection::handleDisconnected, shared_from_this(), _1)); + } + if (currentConnection_) { + currentConnection_->onDataRead.disconnect(boost::bind(&BOSHConnection::handleDataRead, shared_from_this(), _1)); + currentConnection_->onDisconnected.disconnect(boost::bind(&BOSHConnection::handleDisconnected, shared_from_this(), _1)); + } + } + + void BOSHConnection::connect(const HostAddressPort& server) { + server_ = server; + newConnection_ = connectionFactory_->createConnection(); + newConnection_->onConnectFinished.connect(boost::bind(&BOSHConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + newConnection_->onDataRead.connect(boost::bind(&BOSHConnection::handleDataRead, shared_from_this(), _1)); + newConnection_->onDisconnected.connect(boost::bind(&BOSHConnection::handleDisconnected, shared_from_this(), _1)); + SWIFT_LOG(debug) << "connect to server " << server.getAddress().toString() << ":" << server.getPort() << std::endl; + newConnection_->connect(HostAddressPort(HostAddress("85.10.192.88"), 5280)); + } + + void BOSHConnection::listen() { + assert(false); + } + + void BOSHConnection::disconnect() { + if(newConnection_) + newConnection_->disconnect(); + + if(currentConnection_) + currentConnection_->disconnect(); + } + + void BOSHConnection::write(const SafeByteArray& data) { + SWIFT_LOG(debug) << "write data: " << safeByteArrayToString(data) << std::endl; + } + + void BOSHConnection::handleConnectionConnectFinished(bool error) { + newConnection_->onConnectFinished.disconnect(boost::bind(&BOSHConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + if(error) { + onConnectFinished(true); + return; + } + + if(sid_.size() == 0) { + // Session Creation Request + std::stringstream content; + std::stringstream header; + + content << "<body content='text/xml; charset=utf-8'" + << " from='ephraim@0x10.de'" + << " hold='1'" + << " to='0x10.de'" + << " ver='1.6'" + << " wait='60'" + << " ack='1'" + << " xml:lang='en'" + << " xmlns='http://jabber.org/protocol/httpbind' />\r\n"; + + header << "POST /http-bind HTTP/1.1\r\n" + << "Host: 0x10.de:5280\r\n" + << "Accept-Encoding: deflate\r\n" + << "Content-Type: text/xml; charset=utf-8\r\n" + << "Content-Length: " << content.str().size() << "\r\n\r\n" + << content.str(); + + SWIFT_LOG(debug) << "request: "; + newConnection_->write(createSafeByteArray(header.str())); + } + } + + void BOSHConnection::handleDataRead(const SafeByteArray& data) { + std::string response = safeByteArrayToString(data); + assert(response.find("\r\n\r\n") != std::string::npos); + + SWIFT_LOG(debug) << "response: " << response.substr(response.find("\r\n\r\n") + 4) << std::endl; + + BOSHParser parser; + if(parser.parse(response.substr(response.find("\r\n\r\n") + 4))) { + sid_ = parser.getAttribute("sid"); + onConnectFinished(false); + int bodyStartElementLength = 0; + bool inQuote = false; + for(size_t i= 0; i < response.size(); i++) { + if(response.c_str()[i] == '\'' || response.c_str()[i] == '"') { + inQuote = !inQuote; + } + else if(!inQuote && response.c_str()[i] == '>') { + bodyStartElementLength = i + 1; + break; + } + } + SafeByteArray payload = createSafeByteArray(response.substr(bodyStartElementLength, response.size() - bodyStartElementLength - 7)); + SWIFT_LOG(debug) << "payload: " << safeByteArrayToString(payload) << std::endl; + onDataRead(payload); + } + } + + void BOSHConnection::handleDisconnected(const boost::optional<Error>& error) { + onDisconnected(error); + } + + HostAddressPort BOSHConnection::getLocalAddress() const { + return newConnection_->getLocalAddress(); + } +} diff --git a/Swiften/Network/BOSHConnection.h b/Swiften/Network/BOSHConnection.h new file mode 100644 index 0000000..0da92ba --- /dev/null +++ b/Swiften/Network/BOSHConnection.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Base/String.h> + +namespace boost { + class thread; + namespace system { + class error_code; + } +} + +namespace Swift { + class ConnectionFactory; + + class BOSHConnection : public Connection, public boost::enable_shared_from_this<BOSHConnection> { + public: + typedef boost::shared_ptr<BOSHConnection> ref; + static ref create(ConnectionFactory* connectionFactory) { + return ref(new BOSHConnection(connectionFactory)); + } + virtual ~BOSHConnection(); + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const SafeByteArray& data); + virtual HostAddressPort getLocalAddress() const; + + private: + BOSHConnection(ConnectionFactory* connectionFactory); + + void handleConnectionConnectFinished(bool error); + void handleDataRead(const SafeByteArray& data); + void handleDisconnected(const boost::optional<Error>& error); + + bool reopenAfterAction; + ConnectionFactory* connectionFactory_; + HostAddressPort server_; + boost::shared_ptr<Connection> newConnection_; + boost::shared_ptr<Connection> currentConnection_; + std::string sid_; + }; +} diff --git a/Swiften/Network/BOSHConnectionFactory.cpp b/Swiften/Network/BOSHConnectionFactory.cpp new file mode 100644 index 0000000..4c49cae --- /dev/null +++ b/Swiften/Network/BOSHConnectionFactory.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "BOSHConnectionFactory.h" +#include <Swiften/Network/BOSHConnection.h> + +namespace Swift { + +BOSHConnectionFactory::BOSHConnectionFactory(ConnectionFactory* connectionFactory) { + connectionFactory_ = connectionFactory; + +} + +boost::shared_ptr<Connection> BOSHConnectionFactory::createConnection() { + return BOSHConnection::create(connectionFactory_); +} + +} diff --git a/Swiften/Network/BOSHConnectionFactory.h b/Swiften/Network/BOSHConnectionFactory.h new file mode 100644 index 0000000..7431cf4 --- /dev/null +++ b/Swiften/Network/BOSHConnectionFactory.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddressPort.h> + +namespace Swift { + class BOSHConnectionFactory : public ConnectionFactory { + public: + BOSHConnectionFactory(ConnectionFactory* connectionFactory); + + virtual boost::shared_ptr<Connection> createConnection(); + + private: + ConnectionFactory* connectionFactory_; + }; +} diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index 49df18f..399cec8 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -15,6 +15,8 @@ sourceList = [ "BoostConnectionServer.cpp", "BoostConnectionServerFactory.cpp", "BoostIOServiceThread.cpp", + "BOSHConnection.cpp", + "BOSHConnectionFactory.cpp" "ConnectionFactory.cpp", "ConnectionServer.cpp", "ConnectionServerFactory.cpp", diff --git a/Swiften/Parser/BOSHParser.cpp b/Swiften/Parser/BOSHParser.cpp new file mode 100644 index 0000000..9fb218a --- /dev/null +++ b/Swiften/Parser/BOSHParser.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cassert> + +#include <Swiften/Parser/BOSHParser.h> +#include <Swiften/Parser/XMLParser.h> +#include <Swiften/Parser/PlatformXMLParserFactory.h> + +namespace Swift { + +BOSHParser::BOSHParser() : + xmlParser_(0), + level_(-1), + parseErrorOccurred_(false) +{ + xmlParser_ = PlatformXMLParserFactory().createXMLParser(this); +} + +BOSHParser::~BOSHParser() { + delete xmlParser_; +} + +bool BOSHParser::parse(const std::string& data) { + bool xmlParseResult = xmlParser_->parse(data); + return xmlParseResult && !parseErrorOccurred_; +} + +void BOSHParser::handleStartElement(const std::string& /*element*/, const std::string& /*ns*/, const AttributeMap& attributes) { + if (!parseErrorOccurred_) { + if (level_ == BoshTopLevel) { + boshBodyAttributes_ = attributes; + } + } + ++level_; +} + +void BOSHParser::handleEndElement(const std::string& /*element*/, const std::string& /*ns*/) { + assert(level_ > BoshTopLevel); + --level_; + if (!parseErrorOccurred_) { + + } +} + +void BOSHParser::handleCharacterData(const std::string& /*data*/) { + if (!parseErrorOccurred_) { + + } +} + +} diff --git a/Swiften/Parser/BOSHParser.h b/Swiften/Parser/BOSHParser.h new file mode 100644 index 0000000..69b3d13 --- /dev/null +++ b/Swiften/Parser/BOSHParser.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/noncopyable.hpp> + +#include <Swiften/Parser/XMLParserClient.h> +#include <Swiften/Parser/AttributeMap.h> + +namespace Swift { + class XMLParser; + + class BOSHParser : public XMLParserClient, boost::noncopyable { + public: + BOSHParser(); + ~BOSHParser(); + + bool parse(const std::string&); + + std::string getAttribute(const std::string& attribute, const std::string& ns = "") const { + return boshBodyAttributes_.getAttribute(attribute, ns); + } + private: + virtual void handleStartElement( + const std::string& element, + const std::string& ns, + const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string& ns); + virtual void handleCharacterData(const std::string& data); + + private: + AttributeMap boshBodyAttributes_; + XMLParser* xmlParser_; + enum Level { + BoshTopLevel = -1, + TopLevel = 0, + StreamLevel = 1, + ElementLevel = 2 + }; + int level_; + bool parseErrorOccurred_; + }; +} diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index e4c2778..dd19238 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -11,6 +11,7 @@ sources = [ "AuthChallengeParser.cpp", "AuthSuccessParser.cpp", "AuthResponseParser.cpp", + "BOSHParser.cpp", "CompressParser.cpp", "ElementParser.cpp", "IQParser.cpp", -- cgit v0.10.2-6-g49f6