From 093d499945d779cfed92b45e413644834004b0d9 Mon Sep 17 00:00:00 2001 From: Kevin Smith <git@kismith.co.uk> Date: Tue, 17 Jan 2012 07:54:39 +0000 Subject: Allow specifying BOSH and BOSH proxy URLs with names (rather than IPs) diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 046120d..6f93dd3 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -505,6 +505,10 @@ void MainController::performLoginFromCachedCredentials() { ClientOptions clientOptions; clientOptions.forgetPassword = eagleMode_; clientOptions.useTLS = eagleMode_ ? ClientOptions::RequireTLS : ClientOptions::UseTLSWhenAvailable; + /*if (clientJID.getDomain() == "doomsong.co.uk") { + clientOptions.boshURL = URL("https", "channels.doomsong.co.uk", 11443, "http-bind/"); + clientOptions.boshHTTPConnectProxyURL = URL("http", "squidproxy.doomsong.co.uk", 8123, ""); + }*/ client_->connect(clientOptions); } diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h index 06bf947..fbec272 100644 --- a/Swiften/Client/ClientOptions.h +++ b/Swiften/Client/ClientOptions.h @@ -67,7 +67,6 @@ namespace Swift { /** * If non-empty, use BOSH instead of direct TCP, with the given URL. - * The host currently needs to be specified by IP, rather than hostname. * Default: empty (no BOSH) */ URL boshURL; @@ -75,7 +74,6 @@ namespace Swift { /** * If non-empty, BOSH connections will try to connect over this HTTP CONNECT * proxy instead of directly. - * Must be specified by IP, rather than hostname. * Default: empty (no proxy) */ URL boshHTTPConnectProxyURL; diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index 49fb9fa..de12fb7 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -67,7 +67,7 @@ void CoreClient::connect(const std::string& host) { proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getConnectionFactory(), networkFactories->getProxyProvider()->getSOCKS5Proxy())); } if(networkFactories->getProxyProvider()->getHTTPConnectProxy().isValid()) { - proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getConnectionFactory(), networkFactories->getProxyProvider()->getHTTPConnectProxy())); + proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), networkFactories->getEventLoop(), networkFactories->getProxyProvider()->getHTTPConnectProxy().getAddress().toString(), networkFactories->getProxyProvider()->getHTTPConnectProxy().getPort())); } std::vector<ConnectionFactory*> connectionFactories(proxyConnectionFactories); if (options.boshURL.empty()) { @@ -87,13 +87,14 @@ void CoreClient::connect(const std::string& host) { getPayloadParserFactories(), getPayloadSerializers(), networkFactories->getConnectionFactory(), - networkFactories->getTLSContextFactory(), - networkFactories->getTimerFactory(), + networkFactories->getTLSContextFactory(), + networkFactories->getTimerFactory(), networkFactories->getXMLParserFactory(), - networkFactories->getEventLoop(), - host, - options.boshHTTPConnectProxyURL, - options.boshHTTPConnectProxyAuthID, + networkFactories->getEventLoop(), + networkFactories->getDomainNameResolver(), + host, + options.boshHTTPConnectProxyURL, + options.boshHTTPConnectProxyAuthID, options.boshHTTPConnectProxyAuthPassword)); sessionStream_->onDataRead.connect(boost::bind(&CoreClient::handleDataRead, this, _1)); sessionStream_->onDataWritten.connect(boost::bind(&CoreClient::handleDataWritten, this, _1)); diff --git a/Swiften/Network/BOSHConnection.cpp b/Swiften/Network/BOSHConnection.cpp index ea84400..73f8ed6 100644 --- a/Swiften/Network/BOSHConnection.cpp +++ b/Swiften/Network/BOSHConnection.cpp @@ -17,32 +17,29 @@ #include <boost/lexical_cast.hpp> #include <string> -#include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Base/Log.h> #include <Swiften/Base/String.h> #include <Swiften/Base/Concat.h> #include <Swiften/Base/ByteArray.h> #include <Swiften/Network/HostAddressPort.h> -#include <Swiften/Network/TLSConnection.h> #include <Swiften/Parser/BOSHBodyExtractor.h> namespace Swift { -BOSHConnection::BOSHConnection(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory) - : boshURL_(boshURL), - connectionFactory_(connectionFactory), +BOSHConnection::BOSHConnection(const URL& boshURL, Connector::ref connector, XMLParserFactory* parserFactory) + : boshURL_(boshURL), + connector_(connector), parserFactory_(parserFactory), sid_(), waitingForStartResponse_(false), pending_(false), - tlsFactory_(tlsFactory), connectionReady_(false) { } BOSHConnection::~BOSHConnection() { + cancelConnector(); if (connection_) { - connection_->onConnectFinished.disconnect(boost::bind(&BOSHConnection::handleConnectionConnectFinished, shared_from_this(), _1)); connection_->onDataRead.disconnect(boost::bind(&BOSHConnection::handleDataRead, shared_from_this(), _1)); connection_->onDisconnected.disconnect(boost::bind(&BOSHConnection::handleDisconnected, shared_from_this(), _1)); } @@ -50,15 +47,20 @@ BOSHConnection::~BOSHConnection() { } void BOSHConnection::connect() { - Connection::ref rawConnection = connectionFactory_->createConnection(); - connection_ = (boshURL_.getScheme() == "https") ? boost::make_shared<TLSConnection>(rawConnection, tlsFactory_) : rawConnection; - connection_->onConnectFinished.connect(boost::bind(&BOSHConnection::handleConnectionConnectFinished, shared_from_this(), _1)); - connection_->onDataRead.connect(boost::bind(&BOSHConnection::handleDataRead, shared_from_this(), _1)); - connection_->onDisconnected.connect(boost::bind(&BOSHConnection::handleDisconnected, shared_from_this(), _1)); - connection_->connect(HostAddressPort(HostAddress(boshURL_.getHost()), boshURL_.getPort())); + connector_->onConnectFinished.connect(boost::bind(&BOSHConnection::handleConnectFinished, shared_from_this(), _1)); + connector_->start(); +} + +void BOSHConnection::cancelConnector() { + if (connector_) { + connector_->onConnectFinished.disconnect(boost::bind(&BOSHConnection::handleConnectFinished, shared_from_this(), _1)); + connector_->stop(); + connector_.reset(); + } } void BOSHConnection::disconnect() { + cancelConnector(); if(connection_) { connection_->disconnect(); sid_ = ""; @@ -78,7 +80,7 @@ void BOSHConnection::write(const SafeByteArray& data) { write(data, false, false); } -std::pair<SafeByteArray, size_t> BOSHConnection::createHTTPRequest(const SafeByteArray& data, bool streamRestart, bool terminate, long rid, const std::string& sid, const URL& boshURL) { +std::pair<SafeByteArray, size_t> BOSHConnection::createHTTPRequest(const SafeByteArray& data, bool streamRestart, bool terminate, unsigned long long rid, const std::string& sid, const URL& boshURL) { size_t size; std::stringstream content; SafeByteArray contentTail = createSafeByteArray("</body>"); @@ -124,13 +126,18 @@ void BOSHConnection::write(const SafeByteArray& data, bool streamRestart, bool t SWIFT_LOG(debug) << "write data: " << safeByteArrayToString(safeHeader) << std::endl; } -void BOSHConnection::handleConnectionConnectFinished(bool error) { - connection_->onConnectFinished.disconnect(boost::bind(&BOSHConnection::handleConnectionConnectFinished, shared_from_this(), _1)); - connectionReady_ = !error; - onConnectFinished(error); +void BOSHConnection::handleConnectFinished(Connection::ref connection) { + cancelConnector(); + connectionReady_ = connection; + if (connectionReady_) { + connection_ = connection; + connection_->onDataRead.connect(boost::bind(&BOSHConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&BOSHConnection::handleDisconnected, shared_from_this(), _1)); + } + onConnectFinished(!connectionReady_); } -void BOSHConnection::startStream(const std::string& to, unsigned long rid) { +void BOSHConnection::startStream(const std::string& to, unsigned long long rid) { assert(connectionReady_); // Session Creation Request std::stringstream content; @@ -265,6 +272,7 @@ void BOSHConnection::setSID(const std::string& sid) { } void BOSHConnection::handleDisconnected(const boost::optional<Connection::Error>& error) { + cancelConnector(); onDisconnected(error); sid_ = ""; connectionReady_ = false; diff --git a/Swiften/Network/BOSHConnection.h b/Swiften/Network/BOSHConnection.h index 4d53253..d9fa016 100644 --- a/Swiften/Network/BOSHConnection.h +++ b/Swiften/Network/BOSHConnection.h @@ -16,6 +16,7 @@ #include <boost/enable_shared_from_this.hpp> #include <Swiften/Network/Connection.h> +#include <Swiften/Network/Connector.h> #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Base/String.h> #include <Swiften/Base/URL.h> @@ -32,7 +33,6 @@ namespace boost { class BOSHConnectionTest; namespace Swift { - class ConnectionFactory; class XMLParserFactory; class TLSContextFactory; @@ -54,8 +54,8 @@ namespace Swift { class BOSHConnection : public boost::enable_shared_from_this<BOSHConnection> { public: typedef boost::shared_ptr<BOSHConnection> ref; - static ref create(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory) { - return ref(new BOSHConnection(boshURL, connectionFactory, parserFactory, tlsFactory)); + static ref create(const URL& boshURL, Connector::ref connector, XMLParserFactory* parserFactory) { + return ref(new BOSHConnection(boshURL, connector, parserFactory)); } virtual ~BOSHConnection(); virtual void connect(); @@ -65,7 +65,7 @@ namespace Swift { const std::string& getSID(); void setRID(unsigned long long rid); void setSID(const std::string& sid); - void startStream(const std::string& to, unsigned long rid); + void startStream(const std::string& to, unsigned long long rid); void terminateStream(); bool isReadyToSend(); void restartStream(); @@ -83,17 +83,18 @@ namespace Swift { private: friend class ::BOSHConnectionTest; - BOSHConnection(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory); + BOSHConnection(const URL& boshURL, Connector::ref connector, XMLParserFactory* parserFactory); - static std::pair<SafeByteArray, size_t> createHTTPRequest(const SafeByteArray& data, bool streamRestart, bool terminate, long rid, const std::string& sid, const URL& boshURL); - void handleConnectionConnectFinished(bool error); + static std::pair<SafeByteArray, size_t> createHTTPRequest(const SafeByteArray& data, bool streamRestart, bool terminate, unsigned long long rid, const std::string& sid, const URL& boshURL); + void handleConnectFinished(Connection::ref); void handleDataRead(boost::shared_ptr<SafeByteArray> data); void handleDisconnected(const boost::optional<Connection::Error>& error); void write(const SafeByteArray& data, bool streamRestart, bool terminate); /* FIXME: refactor */ BOSHError::Type parseTerminationCondition(const std::string& text); + void cancelConnector(); URL boshURL_; - ConnectionFactory* connectionFactory_; + Connector::ref connector_; XMLParserFactory* parserFactory_; boost::shared_ptr<Connection> connection_; std::string sid_; @@ -101,7 +102,6 @@ namespace Swift { unsigned long long rid_; SafeByteArray buffer_; bool pending_; - TLSContextFactory* tlsFactory_; bool connectionReady_; }; } diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp index a30bf7b..7d43f42 100644 --- a/Swiften/Network/BOSHConnectionPool.cpp +++ b/Swiften/Network/BOSHConnectionPool.cpp @@ -14,38 +14,43 @@ #include <Swiften/Base/SafeString.h> #include <Swiften/Network/TLSConnectionFactory.h> #include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> +#include <Swiften/Network/CachingNameOnlyDomainNameResolver.h> namespace Swift { -BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, const std::string& to, long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword) : +BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* realResolver, ConnectionFactory* connectionFactoryParameter, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword) : boshURL(boshURL), - connectionFactory(connectionFactory), + connectionFactory(connectionFactoryParameter), xmlParserFactory(parserFactory), tlsFactory(tlsFactory), + timerFactory(timerFactory), rid(initialRID), pendingTerminate(false), to(to), requestLimit(2), restartCount(0), pendingRestart(false) { - tlsConnectionFactory = NULL; - if (boshHTTPConnectProxyURL.empty()) { - connectProxyFactory = NULL; - } - else { - ConnectionFactory* rawFactory = connectionFactory; + + if (!boshHTTPConnectProxyURL.empty()) { if (boshHTTPConnectProxyURL.getScheme() == "https") { - tlsConnectionFactory = new TLSConnectionFactory(tlsFactory, rawFactory); - rawFactory = tlsConnectionFactory; + connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory); + myConnectionFactories.push_back(connectionFactory); } - connectProxyFactory = new HTTPConnectProxiedConnectionFactory(rawFactory, HostAddressPort(HostAddress(boshHTTPConnectProxyURL.getHost()), boshHTTPConnectProxyURL.getPort()), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); + connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, eventLoop, boshHTTPConnectProxyURL.getHost(), boshHTTPConnectProxyURL.getPort(), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); } + if (boshURL.getScheme() == "https") { + connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory); + myConnectionFactories.push_back(connectionFactory); + } + resolver = new CachingNameOnlyDomainNameResolver(realResolver, eventLoop); createConnection(); } BOSHConnectionPool::~BOSHConnectionPool() { close(); - delete connectProxyFactory; - delete tlsConnectionFactory; + foreach (ConnectionFactory* factory, myConnectionFactories) { + delete factory; + } + delete resolver; } void BOSHConnectionPool::write(const SafeByteArray& data) { @@ -209,7 +214,8 @@ void BOSHConnectionPool::handleConnectionDisconnected(bool error, BOSHConnection } boost::shared_ptr<BOSHConnection> BOSHConnectionPool::createConnection() { - BOSHConnection::ref connection = BOSHConnection::create(boshURL, connectProxyFactory ? connectProxyFactory : connectionFactory, xmlParserFactory, tlsFactory); + Connector::ref connector = Connector::create(boshURL.getHost(), resolver, connectionFactory, timerFactory, boshURL.getPort()); + BOSHConnection::ref connection = BOSHConnection::create(boshURL, connector, xmlParserFactory); connection->onXMPPDataRead.connect(boost::bind(&BOSHConnectionPool::handleDataRead, this, _1)); connection->onSessionStarted.connect(boost::bind(&BOSHConnectionPool::handleSessionStarted, this, _1, _2)); connection->onBOSHDataRead.connect(boost::bind(&BOSHConnectionPool::handleBOSHDataRead, this, _1)); diff --git a/Swiften/Network/BOSHConnectionPool.h b/Swiften/Network/BOSHConnectionPool.h index cc354b8..8bc0a7c 100644 --- a/Swiften/Network/BOSHConnectionPool.h +++ b/Swiften/Network/BOSHConnectionPool.h @@ -15,10 +15,12 @@ namespace Swift { class HTTPConnectProxiedConnectionFactory; class TLSConnectionFactory; + class CachingNameOnlyDomainNameResolver; + class EventLoop; class BOSHConnectionPool : public boost::bsignals::trackable { public: - BOSHConnectionPool(const URL& boshURL, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, const std::string& to, long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword); + BOSHConnectionPool(const URL& boshURL, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword); ~BOSHConnectionPool(); void write(const SafeByteArray& data); void writeFooter(); @@ -52,16 +54,17 @@ namespace Swift { ConnectionFactory* connectionFactory; XMLParserFactory* xmlParserFactory; TLSContextFactory* tlsFactory; + TimerFactory* timerFactory; std::vector<BOSHConnection::ref> connections; std::string sid; - unsigned long rid; + unsigned long long rid; std::vector<SafeByteArray> dataQueue; bool pendingTerminate; std::string to; size_t requestLimit; int restartCount; bool pendingRestart; - HTTPConnectProxiedConnectionFactory* connectProxyFactory; - TLSConnectionFactory* tlsConnectionFactory; + std::vector<ConnectionFactory*> myConnectionFactories; + CachingNameOnlyDomainNameResolver* resolver; }; } diff --git a/Swiften/Network/CachingNameOnlyDomainNameResolver.cpp b/Swiften/Network/CachingNameOnlyDomainNameResolver.cpp new file mode 100644 index 0000000..a83bebd --- /dev/null +++ b/Swiften/Network/CachingNameOnlyDomainNameResolver.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/CachingNameOnlyDomainNameResolver.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { +CachingNameOnlyDomainNameResolver::CachingNameOnlyDomainNameResolver(DomainNameResolver* realResolver, EventLoop* eventLoop) : realResolver(realResolver) { + staticResolver = boost::make_shared<StaticDomainNameResolver>(eventLoop); +} + +CachingNameOnlyDomainNameResolver::~CachingNameOnlyDomainNameResolver() { + +} + +DomainNameServiceQuery::ref CachingNameOnlyDomainNameResolver::createServiceQuery(const std::string& name) { + return staticResolver->createServiceQuery(name); +} + +DomainNameAddressQuery::ref CachingNameOnlyDomainNameResolver::createAddressQuery(const std::string& name) { + return realResolver->createAddressQuery(name); +} + +void CachingNameOnlyDomainNameResolver::handleAddressQueryResult(const std::string hostname, const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> error) { + //FIXME: Cache +} + +} diff --git a/Swiften/Network/CachingNameOnlyDomainNameResolver.h b/Swiften/Network/CachingNameOnlyDomainNameResolver.h new file mode 100644 index 0000000..d9e78e6 --- /dev/null +++ b/Swiften/Network/CachingNameOnlyDomainNameResolver.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012 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/Network/DomainNameResolver.h> +#include <Swiften/Network/StaticDomainNameResolver.h> + + +namespace Swift { + class EventLoop; + class CachingNameOnlyDomainNameResolver : public DomainNameResolver { + public: + CachingNameOnlyDomainNameResolver(DomainNameResolver* realResolver, EventLoop* eventLoop); + ~CachingNameOnlyDomainNameResolver(); + + virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& name); + virtual DomainNameAddressQuery::ref createAddressQuery(const std::string& name); + + private: + void handleAddressQueryResult(const std::string hostname, const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> error); + + private: + DomainNameResolver* realResolver; + boost::shared_ptr<StaticDomainNameResolver> staticResolver; + }; +} diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp index 8f35aba..378875b 100644 --- a/Swiften/Network/Connector.cpp +++ b/Swiften/Network/Connector.cpp @@ -17,7 +17,7 @@ namespace Swift { -Connector::Connector(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0), queriedAllServices(true) { +Connector::Connector(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, int defaultPort) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), defaultPort(defaultPort), timeoutMilliseconds(0), queriedAllServices(true) { } void Connector::setTimeoutMilliseconds(int milliseconds) { @@ -105,7 +105,7 @@ void Connector::tryNextAddress() { HostAddress address = addressQueryResults.front(); addressQueryResults.pop_front(); - int port = 5222; + int port = defaultPort; if (!serviceQueryResults.empty()) { port = serviceQueryResults.front().port; } diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h index 8336299..8f2c359 100644 --- a/Swiften/Network/Connector.h +++ b/Swiften/Network/Connector.h @@ -27,8 +27,8 @@ namespace Swift { public: typedef boost::shared_ptr<Connector> ref; - static Connector::ref create(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { - return ref(new Connector(hostname, resolver, connectionFactory, timerFactory)); + static Connector::ref create(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, int defaultPort = 5222) { + return ref(new Connector(hostname, resolver, connectionFactory, timerFactory, defaultPort)); } void setTimeoutMilliseconds(int milliseconds); @@ -38,7 +38,7 @@ namespace Swift { boost::signal<void (boost::shared_ptr<Connection>)> onConnectFinished; private: - Connector(const std::string& hostname, DomainNameResolver*, ConnectionFactory*, TimerFactory*); + Connector(const std::string& hostname, DomainNameResolver*, ConnectionFactory*, TimerFactory*, int defaultPort); void handleServiceQueryResult(const std::vector<DomainNameServiceQuery::Result>& result); void handleAddressQueryResult(const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> error); @@ -58,6 +58,7 @@ namespace Swift { DomainNameResolver* resolver; ConnectionFactory* connectionFactory; TimerFactory* timerFactory; + int defaultPort; int timeoutMilliseconds; boost::shared_ptr<Timer> timer; boost::shared_ptr<DomainNameServiceQuery> serviceQuery; diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp index 9ef63f0..512381f 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2011 Kevin Smith + * Copyright (c) 2011-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -24,17 +24,20 @@ #include <Swiften/Base/ByteArray.h> #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/CachingNameOnlyDomainNameResolver.h> #include <Swiften/StringCodecs/Base64.h> using namespace Swift; -HTTPConnectProxiedConnection::HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy, const SafeString& authID, const SafeString& authPassword) : connectionFactory_(connectionFactory), proxy_(proxy), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)), authID_(authID), authPassword_(authPassword) { +HTTPConnectProxiedConnection::HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) : connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)), authID_(authID), authPassword_(authPassword) { + resolver_ = new CachingNameOnlyDomainNameResolver(resolver, eventLoop); connected_ = false; } HTTPConnectProxiedConnection::~HTTPConnectProxiedConnection() { + cancelConnector(); + delete resolver_; if (connection_) { - connection_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); connection_->onDataRead.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); connection_->onDisconnected.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); } @@ -44,13 +47,19 @@ HTTPConnectProxiedConnection::~HTTPConnectProxiedConnection() { } } +void HTTPConnectProxiedConnection::cancelConnector() { + if (connector_) { + connector_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectFinished, shared_from_this(), _1)); + connector_->stop(); + connector_.reset(); + } +} + void HTTPConnectProxiedConnection::connect(const HostAddressPort& server) { server_ = server; - connection_ = connectionFactory_->createConnection(); - connection_->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); - connection_->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); - connection_->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); - connection_->connect(proxy_); + connector_ = Connector::create(proxyHost_, resolver_, connectionFactory_, timerFactory_, proxyPort_); + connector_->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnection::handleConnectFinished, shared_from_this(), _1)); + connector_->start(); } void HTTPConnectProxiedConnection::listen() { @@ -71,9 +80,13 @@ void HTTPConnectProxiedConnection::write(const SafeByteArray& data) { connection_->write(data); } -void HTTPConnectProxiedConnection::handleConnectionConnectFinished(bool error) { - connection_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); - if (!error) { +void HTTPConnectProxiedConnection::handleConnectFinished(Connection::ref connection) { + cancelConnector(); + if (connection) { + connection_ = connection; + connection_->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); + std::stringstream connect; connect << "CONNECT " << server_.getAddress().toString() << ":" << server_.getPort() << " HTTP/1.1\r\n"; SafeByteArray data = createSafeByteArray(connect.str()); diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h index 02d3edd..8318ecc 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.h +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2011 Kevin Smith + * Copyright (c) 2011-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -16,6 +16,7 @@ #include <boost/enable_shared_from_this.hpp> #include <Swiften/Network/Connection.h> +#include <Swiften/Network/Connector.h> #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Base/SafeString.h> @@ -28,6 +29,7 @@ namespace boost { namespace Swift { class ConnectionFactory; + class EventLoop; class HTTPConnectProxiedConnection : public Connection, public boost::enable_shared_from_this<HTTPConnectProxiedConnection> { public: @@ -35,8 +37,8 @@ namespace Swift { ~HTTPConnectProxiedConnection(); - static ref create(ConnectionFactory* connectionFactory, HostAddressPort proxy, const SafeString& authID, const SafeString& authPassword) { - return ref(new HTTPConnectProxiedConnection(connectionFactory, proxy, authID, authPassword)); + static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) { + return ref(new HTTPConnectProxiedConnection(resolver, connectionFactory, timerFactory, eventLoop, proxyHost, proxyPort, authID, authPassword)); } virtual void listen(); @@ -46,19 +48,24 @@ namespace Swift { virtual HostAddressPort getLocalAddress() const; private: - HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy, const SafeString& authID, const SafeString& authPassword); + HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); - void handleConnectionConnectFinished(bool error); + void handleConnectFinished(Connection::ref connection); void handleDataRead(boost::shared_ptr<SafeByteArray> data); void handleDisconnected(const boost::optional<Error>& error); + void cancelConnector(); private: bool connected_; + DomainNameResolver* resolver_; ConnectionFactory* connectionFactory_; - HostAddressPort proxy_; + TimerFactory* timerFactory_; + std::string proxyHost_; + int proxyPort_; HostAddressPort server_; SafeByteArray authID_; SafeByteArray authPassword_; + Connector::ref connector_; boost::shared_ptr<Connection> connection_; }; } diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp index 6ad0228..14d702c 100644 --- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp @@ -1,4 +1,10 @@ /* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +/* * Copyright (c) 2010-2011 Thilo Cestonaro * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. @@ -10,15 +16,15 @@ namespace Swift { -HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy), authID_(""), authPassword_("") { +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), eventLoop_(eventLoop), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(""), authPassword_("") { } -HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy, const SafeString& authID, const SafeString& authPassword) : connectionFactory_(connectionFactory), proxy_(proxy), authID_(authID), authPassword_(authPassword) { +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), eventLoop_(eventLoop), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(authID), authPassword_(authPassword) { } boost::shared_ptr<Connection> HTTPConnectProxiedConnectionFactory::createConnection() { - return HTTPConnectProxiedConnection::create(connectionFactory_, proxy_, authID_, authPassword_); + return HTTPConnectProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, eventLoop_, proxyHost_, proxyPort_, authID_, authPassword_); } } diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h index ef3af66..7d003e8 100644 --- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h @@ -1,4 +1,10 @@ /* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +/* * Copyright (c) 2010-2011 Thilo Cestonaro * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. @@ -11,16 +17,23 @@ #include <Swiften/Base/SafeString.h> namespace Swift { + class DomainNameResolver; + class TimerFactory; + class EventLoop; class HTTPConnectProxiedConnectionFactory : public ConnectionFactory { public: - HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); - HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy, const SafeString& authID, const SafeString& authPassword); + HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort); + HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); virtual boost::shared_ptr<Connection> createConnection(); private: + DomainNameResolver* resolver_; ConnectionFactory* connectionFactory_; - HostAddressPort proxy_; + TimerFactory* timerFactory_; + EventLoop* eventLoop_; + std::string proxyHost_; + int proxyPort_; SafeString authID_; SafeString authPassword_; }; diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index 6975fe6..0d0abbd 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -17,6 +17,7 @@ sourceList = [ "BoostIOServiceThread.cpp", "BOSHConnection.cpp", "BOSHConnectionPool.cpp", + "CachingNameOnlyDomainNameResolver.cpp", "ConnectionFactory.cpp", "ConnectionServer.cpp", "ConnectionServerFactory.cpp", diff --git a/Swiften/Network/StaticDomainNameResolver.cpp b/Swiften/Network/StaticDomainNameResolver.cpp index 76ab411..ee18ee5 100644 --- a/Swiften/Network/StaticDomainNameResolver.cpp +++ b/Swiften/Network/StaticDomainNameResolver.cpp @@ -10,13 +10,14 @@ #include <boost/lexical_cast.hpp> #include <Swiften/Network/DomainNameResolveError.h> +#include <Swiften/EventLoop/EventOwner.h> #include <string> using namespace Swift; namespace { struct ServiceQuery : public DomainNameServiceQuery, public boost::enable_shared_from_this<ServiceQuery> { - ServiceQuery(const std::string& service, Swift::StaticDomainNameResolver* resolver, EventLoop* eventLoop) : eventLoop(eventLoop), service(service), resolver(resolver) {} + ServiceQuery(const std::string& service, Swift::StaticDomainNameResolver* resolver, EventLoop* eventLoop, boost::shared_ptr<EventOwner> owner) : eventLoop(eventLoop), service(service), resolver(resolver), owner(owner) {} virtual void run() { if (!resolver->getIsResponsive()) { @@ -28,7 +29,7 @@ namespace { results.push_back(i->second); } } - eventLoop->postEvent(boost::bind(&ServiceQuery::emitOnResult, shared_from_this(), results)); + eventLoop->postEvent(boost::bind(&ServiceQuery::emitOnResult, shared_from_this(), results), owner); } void emitOnResult(std::vector<DomainNameServiceQuery::Result> results) { @@ -38,10 +39,11 @@ namespace { EventLoop* eventLoop; std::string service; StaticDomainNameResolver* resolver; + boost::shared_ptr<EventOwner> owner; }; struct AddressQuery : public DomainNameAddressQuery, public boost::enable_shared_from_this<AddressQuery> { - AddressQuery(const std::string& host, StaticDomainNameResolver* resolver, EventLoop* eventLoop) : eventLoop(eventLoop), host(host), resolver(resolver) {} + AddressQuery(const std::string& host, StaticDomainNameResolver* resolver, EventLoop* eventLoop, boost::shared_ptr<EventOwner> owner) : eventLoop(eventLoop), host(host), resolver(resolver), owner(owner) {} virtual void run() { if (!resolver->getIsResponsive()) { @@ -53,7 +55,7 @@ namespace { boost::bind(&AddressQuery::emitOnResult, shared_from_this(), i->second, boost::optional<DomainNameResolveError>())); } else { - eventLoop->postEvent(boost::bind(&AddressQuery::emitOnResult, shared_from_this(), std::vector<HostAddress>(), boost::optional<DomainNameResolveError>(DomainNameResolveError()))); + eventLoop->postEvent(boost::bind(&AddressQuery::emitOnResult, shared_from_this(), std::vector<HostAddress>(), boost::optional<DomainNameResolveError>(DomainNameResolveError())), owner); } } @@ -64,12 +66,25 @@ namespace { EventLoop* eventLoop; std::string host; StaticDomainNameResolver* resolver; + boost::shared_ptr<EventOwner> owner; }; } +class StaticDomainNameResolverEventOwner : public EventOwner { + public: + ~StaticDomainNameResolverEventOwner() { + + } +}; + + namespace Swift { -StaticDomainNameResolver::StaticDomainNameResolver(EventLoop* eventLoop) : eventLoop(eventLoop), isResponsive(true) { +StaticDomainNameResolver::StaticDomainNameResolver(EventLoop* eventLoop) : eventLoop(eventLoop), isResponsive(true), owner(new StaticDomainNameResolverEventOwner()) { +} + +StaticDomainNameResolver::~StaticDomainNameResolver() { + eventLoop->removeEventsFromOwner(owner); } void StaticDomainNameResolver::addAddress(const std::string& domain, const HostAddress& address) { @@ -94,11 +109,11 @@ void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, c } boost::shared_ptr<DomainNameServiceQuery> StaticDomainNameResolver::createServiceQuery(const std::string& name) { - return boost::shared_ptr<DomainNameServiceQuery>(new ServiceQuery(name, this, eventLoop)); + return boost::shared_ptr<DomainNameServiceQuery>(new ServiceQuery(name, this, eventLoop, owner)); } boost::shared_ptr<DomainNameAddressQuery> StaticDomainNameResolver::createAddressQuery(const std::string& name) { - return boost::shared_ptr<DomainNameAddressQuery>(new AddressQuery(name, this, eventLoop)); + return boost::shared_ptr<DomainNameAddressQuery>(new AddressQuery(name, this, eventLoop, owner)); } } diff --git a/Swiften/Network/StaticDomainNameResolver.h b/Swiften/Network/StaticDomainNameResolver.h index a72db7c..29d1629 100644 --- a/Swiften/Network/StaticDomainNameResolver.h +++ b/Swiften/Network/StaticDomainNameResolver.h @@ -17,8 +17,6 @@ #include <Swiften/EventLoop/EventLoop.h> namespace Swift { - - class StaticDomainNameResolver : public DomainNameResolver { public: typedef std::map<std::string, std::vector<HostAddress> > AddressesMap; @@ -26,6 +24,7 @@ namespace Swift { public: StaticDomainNameResolver(EventLoop* eventLoop); + ~StaticDomainNameResolver(); void addAddress(const std::string& domain, const HostAddress& address); void addService(const std::string& service, const DomainNameServiceQuery::Result& result); @@ -50,11 +49,11 @@ namespace Swift { virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& name); virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name); - private: EventLoop* eventLoop; bool isResponsive; AddressesMap addresses; ServicesCollection services; + boost::shared_ptr<EventOwner> owner; }; } diff --git a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp index 1bfee10..82762c5 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp @@ -21,13 +21,18 @@ #include <Swiften/Network/BOSHConnection.h> #include <Swiften/Network/BOSHConnectionPool.h> #include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> #include <Swiften/Parser/PlatformXMLParserFactory.h> + + using namespace Swift; typedef boost::shared_ptr<BOSHConnectionPool> PoolRef; + class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(BOSHConnectionPoolTest); CPPUNIT_TEST(testConnectionCount_OneWrite); @@ -64,11 +69,16 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { xmppDataRead.clear(); boshDataRead.clear(); boshDataWritten.clear(); + resolver = new StaticDomainNameResolver(eventLoop); + resolver->addAddress(to, HostAddress("127.0.0.1")); + timerFactory = new DummyTimerFactory(); } void tearDown() { eventLoop->processEvents(); delete connectionFactory; + delete resolver; + delete timerFactory; delete eventLoop; } @@ -91,10 +101,13 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); eventLoop->processEvents(); readResponse(initial, connectionFactory->connections[0]); + eventLoop->processEvents(); testling->write(createSafeByteArray("<blah/>")); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); testling->write(createSafeByteArray("<bleh/>")); eventLoop->processEvents(); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); } @@ -125,15 +138,20 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* Connection finished, stream header sent */ readResponse(initial, connectionFactory->connections[0]); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* Don't respond to initial data with a holding call */ testling->restartStream(); + eventLoop->processEvents(); readResponse("<body/>", connectionFactory->connections[0]); + eventLoop->processEvents(); testling->restartStream(); + eventLoop->processEvents(); testling->write(createSafeByteArray("<blah/>")); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); /* New connection isn't up yet. */ @@ -142,6 +160,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* New connection ready. */ testling->write(createSafeByteArray("<bleh/>")); + eventLoop->processEvents(); testling->write(createSafeByteArray("<bluh/>")); CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* New data can't be sent, no free connections. */ eventLoop->processEvents(); @@ -167,6 +186,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { rid++; testling->restartStream(); + eventLoop->processEvents(); readResponse("<body/>", connectionFactory->connections[0]); rid++; @@ -199,6 +219,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { rid++; testling->write(createSafeByteArray("<bleh/>")); + eventLoop->processEvents(); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT(c1->pending); CPPUNIT_ASSERT_EQUAL(st(6), boshDataWritten.size()); /* data */ @@ -214,6 +235,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { void testSession() { to = "prosody.doomsong.co.uk"; + resolver->addAddress("prosody.doomsong.co.uk", HostAddress("127.0.0.1")); path = "http-bind/"; boshURL = URL("http", to, 5280, path); @@ -258,15 +280,18 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { boost::shared_ptr<MockConnection> c0; PoolRef testling = createTestling(); - c0 = connectionFactory->connections[0]; CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); - eventLoop->processEvents(); + c0 = connectionFactory->connections[0]; readResponse(initial, c0); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* Shouldn't have sent anything extra */ + eventLoop->processEvents(); testling->restartStream(); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), boshDataWritten.size()); readResponse("<body></body>", c0); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); std::string fullBody = "<body rid='" + boost::lexical_cast<std::string>(initialRID + 2) + "' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'></body>"; std::string response = boshDataWritten[2]; @@ -279,12 +304,17 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { private: PoolRef createTestling() { - PoolRef pool = boost::make_shared<BOSHConnectionPool>(boshURL, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), to, initialRID, URL(), "", ""); + BOSHConnectionPool* a = new BOSHConnectionPool(boshURL, resolver, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), timerFactory, eventLoop, to, initialRID, URL(), SafeString(""), SafeString("")); + PoolRef pool(a); + //FIXME: Remko - why does the above work, but the below fail? + //PoolRef pool = boost::make_shared<BOSHConnectionPool>(boshURL, resolver, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), timerFactory, eventLoop, to, initialRID, URL(), SafeString(""), SafeString("")); pool->onXMPPDataRead.connect(boost::bind(&BOSHConnectionPoolTest::handleXMPPDataRead, this, _1)); pool->onBOSHDataRead.connect(boost::bind(&BOSHConnectionPoolTest::handleBOSHDataRead, this, _1)); pool->onBOSHDataWritten.connect(boost::bind(&BOSHConnectionPoolTest::handleBOSHDataWritten, this, _1)); pool->onSessionStarted.connect(boost::bind(&BOSHConnectionPoolTest::handleSessionStarted, this)); pool->onSessionTerminated.connect(boost::bind(&BOSHConnectionPoolTest::handleSessionTerminated, this)); + eventLoop->processEvents(); + eventLoop->processEvents(); return pool; } @@ -406,6 +436,8 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { std::vector<std::string> boshDataRead; std::vector<std::string> boshDataWritten; PlatformXMLParserFactory parserFactory; + StaticDomainNameResolver* resolver; + TimerFactory* timerFactory; std::string to; std::string path; std::string port; diff --git a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp index 8062bea..e0dc0bf 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp @@ -20,6 +20,8 @@ #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/BOSHConnection.h> #include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> #include <Swiften/Parser/PlatformXMLParserFactory.h> @@ -43,6 +45,8 @@ class BOSHConnectionTest : public CppUnit::TestFixture { void setUp() { eventLoop = new DummyEventLoop(); connectionFactory = new MockConnectionFactory(eventLoop); + resolver = new StaticDomainNameResolver(eventLoop); + timerFactory = new DummyTimerFactory(); connectFinished = false; disconnected = false; disconnectedError = false; @@ -52,7 +56,9 @@ class BOSHConnectionTest : public CppUnit::TestFixture { void tearDown() { eventLoop->processEvents(); delete connectionFactory; - delete eventLoop; + delete resolver; + delete timerFactory; + delete eventLoop; } void testHeader() { @@ -185,7 +191,9 @@ class BOSHConnectionTest : public CppUnit::TestFixture { private: BOSHConnection::ref createTestling() { - BOSHConnection::ref c = BOSHConnection::create(URL("http", "wonderland.lit", 5280, "http-bind"), connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL)); + resolver->addAddress("wonderland.lit", HostAddress("127.0.0.1")); + Connector::ref connector = Connector::create("wonderland.lit", resolver, connectionFactory, timerFactory, 5280); + BOSHConnection::ref c = BOSHConnection::create(URL("http", "wonderland.lit", 5280, "http-bind"), connector, &parserFactory); c->onConnectFinished.connect(boost::bind(&BOSHConnectionTest::handleConnectFinished, this, _1)); c->onDisconnected.connect(boost::bind(&BOSHConnectionTest::handleDisconnected, this, _1)); c->onXMPPDataRead.connect(boost::bind(&BOSHConnectionTest::handleDataRead, this, _1)); @@ -284,6 +292,8 @@ class BOSHConnectionTest : public CppUnit::TestFixture { bool disconnectedError; ByteArray dataRead; PlatformXMLParserFactory parserFactory; + StaticDomainNameResolver* resolver; + TimerFactory* timerFactory; std::string sid; }; diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp index c0252d4..347a145 100644 --- a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp +++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp @@ -18,6 +18,8 @@ #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/HTTPConnectProxiedConnection.h> #include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> using namespace Swift; @@ -37,44 +39,55 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { public: void setUp() { - proxyHost = HostAddressPort(HostAddress("1.1.1.1"), 1234); + proxyHost = "doo.bah"; + proxyPort = 1234; + proxyHostAddress = HostAddressPort(HostAddress("1.1.1.1"), proxyPort); host = HostAddressPort(HostAddress("2.2.2.2"), 2345); eventLoop = new DummyEventLoop(); + resolver = new StaticDomainNameResolver(eventLoop); + resolver->addAddress(proxyHost, proxyHostAddress.getAddress()); + timerFactory = new DummyTimerFactory(); connectionFactory = new MockConnectionFactory(eventLoop); connectFinished = false; disconnected = false; } void tearDown() { + delete timerFactory; delete connectionFactory; + delete resolver; delete eventLoop; } + void connect(HTTPConnectProxiedConnection::ref connection, const HostAddressPort& to) { + connection->connect(to); + eventLoop->processEvents(); + eventLoop->processEvents(); + eventLoop->processEvents(); + } + void testConnect_CreatesConnectionToProxy() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(host); - eventLoop->processEvents(); + connect(testling, host); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connectionFactory->connections.size())); CPPUNIT_ASSERT(connectionFactory->connections[0]->hostAddressPort); - CPPUNIT_ASSERT(proxyHost == *connectionFactory->connections[0]->hostAddressPort); + CPPUNIT_ASSERT(proxyHostAddress == *connectionFactory->connections[0]->hostAddressPort); CPPUNIT_ASSERT(!connectFinished); } void testConnect_SendsConnectRequest() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); CPPUNIT_ASSERT_EQUAL(createByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\n\r\n"), connectionFactory->connections[0]->dataWritten); } void testConnect_ReceiveConnectResponse() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); eventLoop->processEvents(); @@ -86,8 +99,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { void testConnect_ReceiveMalformedConnectResponse() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("FLOOP")); eventLoop->processEvents(); @@ -99,8 +111,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { void testConnect_ReceiveErrorConnectResponse() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 401 Unauthorized\r\n\r\n")); eventLoop->processEvents(); @@ -112,8 +123,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { void testConnect_ReceiveDataAfterConnect() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); eventLoop->processEvents(); @@ -124,8 +134,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { void testWrite_AfterConnect() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); eventLoop->processEvents(); connectionFactory->connections[0]->dataWritten.clear(); @@ -137,8 +146,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { void testDisconnect_AfterConnectRequest() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); testling->disconnect(); @@ -149,8 +157,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { void testDisconnect_AfterConnect() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); eventLoop->processEvents(); @@ -163,7 +170,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { private: HTTPConnectProxiedConnection::ref createTestling() { - boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(connectionFactory, proxyHost, "", ""); + boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(resolver, connectionFactory, timerFactory, eventLoop, proxyHost, proxyPort, "", ""); c->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleConnectFinished, this, _1)); c->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDisconnected, this, _1)); c->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDataRead, this, _1)); @@ -231,10 +238,14 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { }; private: - HostAddressPort proxyHost; + std::string proxyHost; + HostAddressPort proxyHostAddress; + int proxyPort; HostAddressPort host; DummyEventLoop* eventLoop; + StaticDomainNameResolver* resolver; MockConnectionFactory* connectionFactory; + TimerFactory* timerFactory; std::vector< boost::shared_ptr<MockConnection> > connections; bool connectFinished; bool connectFinishedWithError; diff --git a/Swiften/Session/BOSHSessionStream.cpp b/Swiften/Session/BOSHSessionStream.cpp index f53b8e1..d706d43 100644 --- a/Swiften/Session/BOSHSessionStream.cpp +++ b/Swiften/Session/BOSHSessionStream.cpp @@ -35,6 +35,7 @@ BOSHSessionStream::BOSHSessionStream( TimerFactory* timerFactory, XMLParserFactory* xmlParserFactory, EventLoop* eventLoop, + DomainNameResolver* resolver, const std::string& to, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, @@ -49,11 +50,11 @@ BOSHSessionStream::BOSHSessionStream( firstHeader(true) { boost::mt19937 random; - boost::uniform_int<long long> dist(0, (1LL<<53) - 1); + boost::uniform_int<unsigned long long> dist(0, (1LL<<53) - 1); random.seed(time(NULL)); - long long initialRID = boost::variate_generator<boost::mt19937&, boost::uniform_int<long long> >(random, dist)(); + unsigned long long initialRID = boost::variate_generator<boost::mt19937&, boost::uniform_int<unsigned long long> >(random, dist)(); - connectionPool = new BOSHConnectionPool(boshURL, connectionFactory, xmlParserFactory, tlsContextFactory, to, initialRID, boshHTTPConnectProxyURL, boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); + connectionPool = new BOSHConnectionPool(boshURL, resolver, connectionFactory, xmlParserFactory, tlsContextFactory, timerFactory, eventLoop, 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)); diff --git a/Swiften/Session/BOSHSessionStream.h b/Swiften/Session/BOSHSessionStream.h index c3f6220..497d391 100644 --- a/Swiften/Session/BOSHSessionStream.h +++ b/Swiften/Session/BOSHSessionStream.h @@ -38,6 +38,7 @@ namespace Swift { TimerFactory* whitespacePingLayerFactory, XMLParserFactory* xmlParserFactory, EventLoop* eventLoop, + DomainNameResolver* resolver, const std::string& to, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, -- cgit v0.10.2-6-g49f6