diff options
23 files changed, 317 insertions, 123 deletions
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 @@ -499,18 +499,22 @@ void MainController::performLoginFromCachedCredentials() { client_->disconnect(); } systemTrayController_->setConnecting(); if (rosterController_) { rosterController_->getWindow()->setConnecting(); } 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); } void MainController::handleDisconnected(const boost::optional<ClientError>& error) { if (eagleMode_) { purgeCachedCredentials(); } if (quitRequested_) { resetClient(); 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 @@ -61,27 +61,25 @@ namespace Swift { /** * Use XEP-0198 acks in the stream when available. * Default: true */ bool useAcks; /** * 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; /** * 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; /** * If this and matching Password are non-empty, BOSH connections over * HTTP CONNECT proxies will use these credentials for proxy access. * Default: empty (no authentication needed by the proxy) */ 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 @@ -61,19 +61,19 @@ void CoreClient::connect(const std::string& host) { SWIFT_LOG(debug) << "Connecting to host " << host << std::endl; disconnectRequested_ = false; assert(!connector_); assert(proxyConnectionFactories.empty()); if(networkFactories->getProxyProvider()->getSOCKS5Proxy().isValid()) { 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()) { connectionFactories.push_back(networkFactories->getConnectionFactory()); connector_ = boost::make_shared<ChainedConnector>(host, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); connector_->setTimeoutMilliseconds(60*1000); connector_->start(); } @@ -81,25 +81,26 @@ void CoreClient::connect(const std::string& host) { /* Autodiscovery of which proxy works is largely ok with a TCP session, because this is a one-off. With BOSH * it would be quite painful given that potentially every stanza could be sent on a new connection. */ //sessionStream_ = boost::make_shared<BOSHSessionStream>(boost::make_shared<BOSHConnectionFactory>(options.boshURL, networkFactories->getConnectionFactory(), networkFactories->getXMLParserFactory(), networkFactories->getTLSContextFactory()), getPayloadParserFactories(), getPayloadSerializers(), networkFactories->getTLSContextFactory(), networkFactories->getTimerFactory(), networkFactories->getXMLParserFactory(), networkFactories->getEventLoop(), host, options.boshHTTPConnectProxyURL, options.boshHTTPConnectProxyAuthID, options.boshHTTPConnectProxyAuthPassword); sessionStream_ = boost::shared_ptr<BOSHSessionStream>(new BOSHSessionStream( options.boshURL, 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)); bindSessionToStream(); } } void CoreClient::bindSessionToStream() { 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 @@ -11,60 +11,62 @@ */ #include <Swiften/Network/BOSHConnection.h> #include <boost/bind.hpp> #include <boost/thread.hpp> #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)); } disconnect(); } 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_ = ""; } } void BOSHConnection::restartStream() { write(createSafeByteArray(""), true, false); } @@ -72,19 +74,19 @@ void BOSHConnection::restartStream() { void BOSHConnection::terminateStream() { write(createSafeByteArray(""), false, true); } 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>"); std::stringstream header; content << "<body rid='" << rid << "' sid='" << sid << "'"; if (streamRestart) { content << " xmpp:restart='true' xmlns:xmpp='urn:xmpp:xbosh'"; } @@ -118,25 +120,30 @@ void BOSHConnection::write(const SafeByteArray& data, bool streamRestart, bool t SafeByteArray safeHeader = createHTTPRequest(data, streamRestart, terminate, rid_, sid_, boshURL_).first; onBOSHDataWritten(safeHeader); connection_->write(safeHeader); pending_ = true; 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; std::stringstream header; content << "<body content='text/xml; charset=utf-8'" << " hold='1'" << " to='" << to << "'" << " rid='" << rid << "'" @@ -259,18 +266,19 @@ const std::string& BOSHConnection::getSID() { void BOSHConnection::setRID(unsigned long long rid) { rid_ = rid; } void BOSHConnection::setSID(const std::string& sid) { sid_ = sid; } void BOSHConnection::handleDisconnected(const boost::optional<Connection::Error>& error) { + cancelConnector(); onDisconnected(error); sid_ = ""; connectionReady_ = false; } bool BOSHConnection::isReadyToSend() { /* Without pipelining you need to not send more without first receiving the response */ /* With pipelining you can. Assuming we can't, here */ 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 @@ -10,35 +10,35 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #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> #include <Swiften/Base/Error.h> #include <Swiften/Session/SessionStream.h> namespace boost { class thread; namespace system { class error_code; } } class BOSHConnectionTest; namespace Swift { - class ConnectionFactory; class XMLParserFactory; class TLSContextFactory; class BOSHError : public SessionStream::Error { public: enum Type {BadRequest, HostGone, HostUnknown, ImproperAddressing, InternalServerError, ItemNotFound, OtherRequest, PolicyViolation, RemoteConnectionFailed, RemoteStreamError, SeeOtherURI, SystemShutdown, UndefinedCondition, NoError}; @@ -48,60 +48,60 @@ namespace Swift { private: Type type; }; 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(); virtual void disconnect(); virtual void write(const SafeByteArray& data); 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(); boost::signal<void (bool /* error */)> onConnectFinished; boost::signal<void (bool /* error */)> onDisconnected; boost::signal<void (BOSHError::ref)> onSessionTerminated; boost::signal<void (const std::string& /*sid*/, size_t /*requests*/)> onSessionStarted; boost::signal<void (const SafeByteArray&)> onXMPPDataRead; boost::signal<void (const SafeByteArray&)> onBOSHDataRead; boost::signal<void (const SafeByteArray&)> onBOSHDataWritten; boost::signal<void (const std::string&)> onHTTPError; 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_; bool waitingForStartResponse_; 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 @@ -8,50 +8,55 @@ #include <climits> #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <Swiften/Base/foreach.h> #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) { dataQueue.push_back(data); tryToSendQueuedData(); } void BOSHConnectionPool::handleDataRead(const SafeByteArray& data) { onXMPPDataRead(data); @@ -203,19 +208,20 @@ void BOSHConnectionPool::handleConnectionDisconnected(bool error, BOSHConnection handleSessionTerminated(boost::make_shared<BOSHError>(BOSHError::UndefinedCondition)); } else { /* We might have just freed up a connection slot to send with */ tryToSendQueuedData(); } } 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)); connection->onBOSHDataWritten.connect(boost::bind(&BOSHConnectionPool::handleBOSHDataWritten, this, _1)); connection->onDisconnected.connect(boost::bind(&BOSHConnectionPool::handleConnectionDisconnected, this, _1, connection)); connection->onConnectFinished.connect(boost::bind(&BOSHConnectionPool::handleConnectFinished, this, _1, connection)); connection->onSessionTerminated.connect(boost::bind(&BOSHConnectionPool::handleSessionTerminated, this, _1)); connection->onHTTPError.connect(boost::bind(&BOSHConnectionPool::handleHTTPError, this, _1)); connection->connect(); 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 @@ -9,22 +9,24 @@ #include <vector> #include <Swiften/Base/SafeString.h> #include <Swiften/Network/BOSHConnection.h> 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(); void close(); void restartStream(); boost::signal<void (BOSHError::ref)> onSessionTerminated; boost::signal<void ()> onSessionStarted; boost::signal<void (const SafeByteArray&)> onXMPPDataRead; @@ -46,22 +48,23 @@ namespace Swift { void destroyConnection(BOSHConnection::ref connection); void tryToSendQueuedData(); BOSHConnection::ref getSuitableConnection(); private: URL boshURL; 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 @@ -11,19 +11,19 @@ #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/DomainNameResolver.h> #include <Swiften/Network/DomainNameAddressQuery.h> #include <Swiften/Network/TimerFactory.h> #include <Swiften/Base/Log.h> 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) { timeoutMilliseconds = milliseconds; } void Connector::start() { SWIFT_LOG(debug) << "Starting connector for " << hostname << std::endl; //std::cout << "Connector::start()" << std::endl; @@ -99,19 +99,19 @@ void Connector::tryNextAddress() { serviceQueryResults.pop_front(); } tryNextServiceOrFallback(); } else { SWIFT_LOG(debug) << "Trying next address" << std::endl; HostAddress address = addressQueryResults.front(); addressQueryResults.pop_front(); - int port = 5222; + int port = defaultPort; if (!serviceQueryResults.empty()) { port = serviceQueryResults.front().port; } tryConnect(HostAddressPort(address, port)); } } void Connector::tryConnect(const HostAddressPort& target) { 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 @@ -21,30 +21,30 @@ namespace Swift { class DomainNameAddressQuery; class DomainNameResolver; class ConnectionFactory; class TimerFactory; class Connector : public boost::bsignals::trackable, public boost::enable_shared_from_this<Connector> { 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); void start(); void stop(); 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); void queryAddress(const std::string& hostname); void tryNextServiceOrFallback(); void tryNextAddress(); void tryConnect(const HostAddressPort& target); @@ -52,18 +52,19 @@ namespace Swift { void finish(boost::shared_ptr<Connection>); void handleTimeout(); private: std::string hostname; DomainNameResolver* resolver; ConnectionFactory* connectionFactory; TimerFactory* timerFactory; + int defaultPort; int timeoutMilliseconds; boost::shared_ptr<Timer> timer; boost::shared_ptr<DomainNameServiceQuery> serviceQuery; std::deque<DomainNameServiceQuery::Result> serviceQueryResults; boost::shared_ptr<DomainNameAddressQuery> addressQuery; std::deque<HostAddress> addressQueryResults; bool queriedAllServices; boost::shared_ptr<Connection> currentConnection; }; 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 @@ -1,62 +1,71 @@ /* * Copyright (c) 2010-2011 Thilo Cestonaro * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ /* - * 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. */ #include <Swiften/Network/HTTPConnectProxiedConnection.h> #include <iostream> #include <boost/bind.hpp> #include <boost/thread.hpp> #include <boost/lexical_cast.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Base/Log.h> #include <Swiften/Base/String.h> #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)); } if (connected_) { std::cerr << "Warning: Connection was still established." << std::endl; } } +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() { assert(false); connection_->listen(); } void HTTPConnectProxiedConnection::disconnect() { connected_ = false; @@ -65,21 +74,25 @@ void HTTPConnectProxiedConnection::disconnect() { void HTTPConnectProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { onDisconnected(error); } 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()); if (!authID_.empty() && !authPassword_.empty()) { append(data, createSafeByteArray("Proxy-Authorization: Basic ")); SafeByteArray credentials = authID_; append(credentials, createSafeByteArray(":")); append(credentials, authPassword_); append(data, Base64::encode(credentials)); 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 @@ -1,64 +1,71 @@ /* * Copyright (c) 2010-2011 Thilo Cestonaro * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ /* - * 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. */ #pragma once #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> namespace boost { class thread; namespace system { class error_code; } } namespace Swift { class ConnectionFactory; + class EventLoop; class HTTPConnectProxiedConnection : public Connection, public boost::enable_shared_from_this<HTTPConnectProxiedConnection> { public: typedef boost::shared_ptr<HTTPConnectProxiedConnection> ref; ~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(); virtual void connect(const HostAddressPort& address); virtual void disconnect(); virtual void write(const SafeByteArray& data); 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,24 +1,30 @@ /* + * 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. */ #include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> #include <Swiften/Network/HTTPConnectProxiedConnection.h> 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,27 +1,40 @@ /* + * 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. */ #pragma once #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/HostAddressPort.h> #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 @@ -11,18 +11,19 @@ sourceList = [ "SOCKS5ProxiedConnection.cpp", "SOCKS5ProxiedConnectionFactory.cpp", "BoostConnection.cpp", "BoostConnectionFactory.cpp", "BoostConnectionServer.cpp", "BoostConnectionServerFactory.cpp", "BoostIOServiceThread.cpp", "BOSHConnection.cpp", "BOSHConnectionPool.cpp", + "CachingNameOnlyDomainNameResolver.cpp", "ConnectionFactory.cpp", "ConnectionServer.cpp", "ConnectionServerFactory.cpp", "DummyConnection.cpp", "FakeConnection.cpp", "ChainedConnector.cpp", "Connector.cpp", "Connection.cpp", "TimerFactory.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 @@ -4,78 +4,93 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ #include <Swiften/Network/StaticDomainNameResolver.h> #include <boost/bind.hpp> #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()) { return; } std::vector<DomainNameServiceQuery::Result> results; for(StaticDomainNameResolver::ServicesCollection::const_iterator i = resolver->getServices().begin(); i != resolver->getServices().end(); ++i) { if (i->first == service) { 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) { onResult(results); } 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()) { return; } StaticDomainNameResolver::AddressesMap::const_iterator i = resolver->getAddresses().find(host); if (i != resolver->getAddresses().end()) { eventLoop->postEvent( 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); } } void emitOnResult(std::vector<HostAddress> results, boost::optional<DomainNameResolveError> error) { onResult(results, error); } 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) { addresses[domain].push_back(address); } void StaticDomainNameResolver::addService(const std::string& service, const DomainNameServiceQuery::Result& result) { services.push_back(std::make_pair(service, result)); } @@ -88,17 +103,17 @@ void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, c addService("_xmpp-client._tcp." + domain, ServiceQuery::Result(hostname, address.getPort(), 0, 0)); addAddress(hostname, address.getAddress()); } void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, const std::string& hostname, int port) { addService("_xmpp-client._tcp." + domain, ServiceQuery::Result(hostname, port, 0, 0)); } 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 @@ -11,27 +11,26 @@ #include <Swiften/Network/HostAddress.h> #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Network/DomainNameResolver.h> #include <Swiften/Network/DomainNameServiceQuery.h> #include <Swiften/Network/DomainNameAddressQuery.h> #include <Swiften/EventLoop/EventLoop.h> namespace Swift { - - class StaticDomainNameResolver : public DomainNameResolver { public: typedef std::map<std::string, std::vector<HostAddress> > AddressesMap; typedef std::vector< std::pair<std::string, DomainNameServiceQuery::Result> > ServicesCollection; public: StaticDomainNameResolver(EventLoop* eventLoop); + ~StaticDomainNameResolver(); void addAddress(const std::string& domain, const HostAddress& address); void addService(const std::string& service, const DomainNameServiceQuery::Result& result); void addXMPPClientService(const std::string& domain, const HostAddressPort&); void addXMPPClientService(const std::string& domain, const std::string& host, int port); const AddressesMap& getAddresses() const { return addresses; } @@ -44,17 +43,17 @@ namespace Swift { return isResponsive; } void setIsResponsive(bool b) { isResponsive = b; } 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 @@ -15,25 +15,30 @@ #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/ConnectionFactory.h> #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); CPPUNIT_TEST(testConnectionCount_TwoWrites); CPPUNIT_TEST(testConnectionCount_ThreeWrites); CPPUNIT_TEST(testConnectionCount_ThreeWrites_ManualConnect); CPPUNIT_TEST(testConnectionCount_ThreeWritesTwoReads); CPPUNIT_TEST(testSession); CPPUNIT_TEST(testWrite_Empty); @@ -58,23 +63,28 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { eventLoop = new DummyEventLoop(); connectionFactory = new MockConnectionFactory(eventLoop); boshURL = URL("http", to, 5280, path); sessionTerminated = 0; sessionStarted = 0; initialRID = 2349876; 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; } void testConnectionCount_OneWrite() { PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(0, sessionStarted); readResponse(initial, connectionFactory->connections[0]); @@ -85,22 +95,25 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); CPPUNIT_ASSERT_EQUAL(1, sessionStarted); } void testConnectionCount_TwoWrites() { PoolRef testling = createTestling(); 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()); } void testConnectionCount_ThreeWrites() { PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); eventLoop->processEvents(); readResponse(initial, connectionFactory->connections[0]); testling->restartStream(); @@ -119,35 +132,41 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); CPPUNIT_ASSERT_EQUAL(st(0), boshDataWritten.size()); /* Connection not connected yet, can't send data */ connectionFactory->connections[0]->onConnectFinished(false); eventLoop->processEvents(); 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. */ connectionFactory->connections[1]->onConnectFinished(false); eventLoop->processEvents(); 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(); CPPUNIT_ASSERT(st(2) >= connectionFactory->connections.size()); } void testConnectionCount_ThreeWritesTwoReads() { boost::shared_ptr<MockConnection> c0; boost::shared_ptr<MockConnection> c1; @@ -161,18 +180,19 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { rid++; readResponse(initial, c0); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); CPPUNIT_ASSERT(!c0->pending); rid++; testling->restartStream(); + eventLoop->processEvents(); readResponse("<body/>", connectionFactory->connections[0]); rid++; testling->write(createSafeByteArray("<blah/>")); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); /* 0 was waiting for response, open and send on 1 */ CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* data */ c1 = connectionFactory->connections[1]; std::string fullBody = "<body rid='" + boost::lexical_cast<std::string>(rid) + "' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'><blah/></body>"; /* check empty write */ @@ -193,33 +213,35 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { readResponse("<body xmlns='http://jabber.org/protocol/httpbind'><message><splatploing><blittlebarg/></splatploing></message></body>", c1); eventLoop->processEvents(); CPPUNIT_ASSERT(!c1->pending); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT_EQUAL(st(5), boshDataWritten.size()); /* empty to make room */ CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); rid++; testling->write(createSafeByteArray("<bleh/>")); + eventLoop->processEvents(); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT(c1->pending); CPPUNIT_ASSERT_EQUAL(st(6), boshDataWritten.size()); /* data */ rid++; testling->write(createSafeByteArray("<bluh/>")); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT(c1->pending); CPPUNIT_ASSERT_EQUAL(st(6), boshDataWritten.size()); /* Don't send data, no room */ eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); } 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); PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* header*/ CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); @@ -252,45 +274,53 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); } void testWrite_Empty() { 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]; size_t bodyPosition = response.find("\r\n\r\n"); CPPUNIT_ASSERT_EQUAL(fullBody, response.substr(bodyPosition+4)); } 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; } std::string lastBody() { std::string response = boshDataWritten[boshDataWritten.size() - 1]; size_t bodyPosition = response.find("\r\n\r\n"); return response.substr(bodyPosition+4); } @@ -400,18 +430,20 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { private: URL boshURL; DummyEventLoop* eventLoop; MockConnectionFactory* connectionFactory; std::vector<std::string> xmppDataRead; 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; std::string sid; std::string initial; long initialRID; int sessionStarted; int sessionTerminated; 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 @@ -14,18 +14,20 @@ #include <boost/smart_ptr/make_shared.hpp> #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Network/Connection.h> #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> using namespace Swift; class BOSHConnectionTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(BOSHConnectionTest); CPPUNIT_TEST(testHeader); CPPUNIT_TEST(testReadiness_ok); @@ -37,28 +39,32 @@ class BOSHConnectionTest : public CppUnit::TestFixture { CPPUNIT_TEST(testRead_Fragment); CPPUNIT_TEST(testHTTPRequest); CPPUNIT_TEST(testHTTPRequest_Empty); CPPUNIT_TEST_SUITE_END(); public: void setUp() { eventLoop = new DummyEventLoop(); connectionFactory = new MockConnectionFactory(eventLoop); + resolver = new StaticDomainNameResolver(eventLoop); + timerFactory = new DummyTimerFactory(); connectFinished = false; disconnected = false; disconnectedError = false; dataRead.clear(); } void tearDown() { eventLoop->processEvents(); delete connectionFactory; - delete eventLoop; + delete resolver; + delete timerFactory; + delete eventLoop; } void testHeader() { BOSHConnection::ref testling = createTestling(); testling->connect(); eventLoop->processEvents(); testling->startStream("wonderland.lit", 1); std::string initial("<body wait='60' " "inactivity='30' " @@ -179,19 +185,21 @@ class BOSHConnectionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(fullBody.size(), http.second); std::string response = safeByteArrayToString(http.first); size_t bodyPosition = response.find("\r\n\r\n"); CPPUNIT_ASSERT_EQUAL(fullBody, response.substr(bodyPosition+4)); } 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)); c->onSessionStarted.connect(boost::bind(&BOSHConnectionTest::handleSID, this, _1)); c->setRID(42); return c; } void handleConnectFinished(bool error) { @@ -278,15 +286,17 @@ class BOSHConnectionTest : public CppUnit::TestFixture { private: DummyEventLoop* eventLoop; MockConnectionFactory* connectionFactory; bool connectFinished; bool connectFinishedWithError; bool disconnected; bool disconnectedError; ByteArray dataRead; PlatformXMLParserFactory parserFactory; + StaticDomainNameResolver* resolver; + TimerFactory* timerFactory; std::string sid; }; CPPUNIT_TEST_SUITE_REGISTRATION(BOSHConnectionTest); 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 @@ -12,18 +12,20 @@ #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <boost/shared_ptr.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Network/Connection.h> #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; class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(HTTPConnectProxiedConnectionTest); CPPUNIT_TEST(testConnect_CreatesConnectionToProxy); CPPUNIT_TEST(testConnect_SendsConnectRequest); CPPUNIT_TEST(testConnect_ReceiveConnectResponse); @@ -31,145 +33,150 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { CPPUNIT_TEST(testConnect_ReceiveErrorConnectResponse); CPPUNIT_TEST(testConnect_ReceiveDataAfterConnect); CPPUNIT_TEST(testWrite_AfterConnect); CPPUNIT_TEST(testDisconnect_AfterConnectRequest); CPPUNIT_TEST(testDisconnect_AfterConnect); CPPUNIT_TEST_SUITE_END(); 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(); CPPUNIT_ASSERT(connectFinished); CPPUNIT_ASSERT(!connectFinishedWithError); CPPUNIT_ASSERT(dataRead.empty()); } 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(); CPPUNIT_ASSERT(connectFinished); CPPUNIT_ASSERT(connectFinishedWithError); CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); } 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(); CPPUNIT_ASSERT(connectFinished); CPPUNIT_ASSERT(connectFinishedWithError); CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); } 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(); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("abcdef")); CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), dataRead); } 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(); testling->write(createSafeByteArray("abcdef")); CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), connectionFactory->connections[0]->dataWritten); } 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(); CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); CPPUNIT_ASSERT(disconnected); CPPUNIT_ASSERT(!disconnectedError); } 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(); testling->disconnect(); CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); CPPUNIT_ASSERT(disconnected); CPPUNIT_ASSERT(!disconnectedError); } 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)); return c; } void handleConnectFinished(bool error) { connectFinished = true; connectFinishedWithError = error; @@ -225,22 +232,26 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { return connection; } EventLoop* eventLoop; std::vector< boost::shared_ptr<MockConnection> > connections; std::vector<HostAddressPort> failingPorts; }; 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; bool disconnected; boost::optional<Connection::Error> disconnectedError; ByteArray dataRead; }; CPPUNIT_TEST_SUITE_REGISTRATION(HTTPConnectProxiedConnectionTest); 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 @@ -29,37 +29,38 @@ namespace Swift { BOSHSessionStream::BOSHSessionStream( const URL& boshURL, PayloadParserFactoryCollection* payloadParserFactories, PayloadSerializerCollection* payloadSerializers, ConnectionFactory* connectionFactory, TLSContextFactory* tlsContextFactory, TimerFactory* timerFactory, XMLParserFactory* xmlParserFactory, EventLoop* eventLoop, + DomainNameResolver* resolver, 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<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)); 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)); 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 @@ -32,18 +32,19 @@ namespace Swift { BOSHSessionStream( const URL& boshURL, PayloadParserFactoryCollection* payloadParserFactories, PayloadSerializerCollection* payloadSerializers, ConnectionFactory* connectionFactory, TLSContextFactory* tlsContextFactory, TimerFactory* whitespacePingLayerFactory, XMLParserFactory* xmlParserFactory, EventLoop* eventLoop, + DomainNameResolver* resolver, const std::string& to, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword ); ~BOSHSessionStream(); virtual void close(); virtual bool isOpen(); |