diff options
author | Kevin Smith <git@kismith.co.uk> | 2012-03-03 11:56:45 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2012-03-04 16:01:01 (GMT) |
commit | 4b6694377e3a0308009bdf90be0a4e0de463b215 (patch) | |
tree | 86b860395d040c38774dfa4400979f9687dff8ae | |
parent | fde71bd59b1412ae475c06f2d4100ce088e86af6 (diff) | |
download | swift-contrib-4b6694377e3a0308009bdf90be0a4e0de463b215.zip swift-contrib-4b6694377e3a0308009bdf90be0a4e0de463b215.tar.bz2 |
Pass along errors about DNS resolution.
-rw-r--r-- | Swiften/Client/CoreClient.cpp | 15 | ||||
-rw-r--r-- | Swiften/Client/CoreClient.h | 2 | ||||
-rw-r--r-- | Swiften/Elements/DeliveryReceipt.h | 2 | ||||
-rw-r--r-- | Swiften/Network/ChainedConnector.cpp | 19 | ||||
-rw-r--r-- | Swiften/Network/ChainedConnector.h | 8 | ||||
-rw-r--r-- | Swiften/Network/Connector.cpp | 8 | ||||
-rw-r--r-- | Swiften/Network/Connector.h | 3 | ||||
-rw-r--r-- | Swiften/Network/UnitTest/ChainedConnectorTest.cpp | 29 | ||||
-rw-r--r-- | Swiften/Network/UnitTest/ConnectorTest.cpp | 34 |
9 files changed, 88 insertions, 32 deletions
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index e2a8e5a..f7e3b21 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -12,18 +12,19 @@ #include <Swiften/Base/IDGenerator.h> #include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> #include <Swiften/Base/Algorithm.h> #include <Swiften/Client/ClientSession.h> #include <Swiften/TLS/CertificateVerificationError.h> #include <Swiften/Network/ChainedConnector.h> #include <Swiften/Network/NetworkFactories.h> #include <Swiften/Network/ProxyProvider.h> +#include <Swiften/Network/DomainNameResolveError.h> #include <Swiften/TLS/PKCS12Certificate.h> #include <Swiften/Session/BasicSessionStream.h> #include <Swiften/Session/BOSHSessionStream.h> #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/ClientSessionStanzaChannel.h> #include <Swiften/Network/SOCKS5ProxiedConnectionFactory.h> #include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> namespace Swift { @@ -57,29 +58,29 @@ void CoreClient::connect(const ClientOptions& o) { } void CoreClient::connect(const std::string& host) { forceReset(); SWIFT_LOG(debug) << "Connecting to host " << host << std::endl; disconnectRequested_ = false; assert(!connector_); assert(proxyConnectionFactories.empty()); - if(networkFactories->getProxyProvider()->getSOCKS5Proxy().isValid()) { + 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->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_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1, _2)); connector_->setTimeoutMilliseconds(60*1000); connector_->start(); } else { /* 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( @@ -123,25 +124,29 @@ void CoreClient::bindSessionToStream() { stanzaChannel_->setSession(session_); session_->onFinished.connect(boost::bind(&CoreClient::handleSessionFinished, this, _1)); session_->onNeedCredentials.connect(boost::bind(&CoreClient::handleNeedCredentials, this)); session_->start(); } /** * Only called for TCP sessions. BOSH is handled inside the BOSHSessionStream. */ -void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connection) { +void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> error) { resetConnector(); if (!connection) { if (options.forgetPassword) { purgePassword(); } - onDisconnected(disconnectRequested_ ? boost::optional<ClientError>() : boost::optional<ClientError>(ClientError::ConnectionError)); + boost::optional<ClientError> clientError; + if (!disconnectRequested_) { + clientError = boost::dynamic_pointer_cast<DomainNameResolveError>(error) ? boost::optional<ClientError>(ClientError::DomainNameResolveError) : boost::optional<ClientError>(ClientError::ConnectionError); + } + onDisconnected(clientError); } else { assert(!connection_); connection_ = connection; assert(!sessionStream_); sessionStream_ = boost::make_shared<BasicSessionStream>(ClientStreamType, connection_, getPayloadParserFactories(), getPayloadSerializers(), networkFactories->getTLSContextFactory(), networkFactories->getTimerFactory(), networkFactories->getXMLParserFactory()); if (certificate_ && !certificate_->isNull()) { sessionStream_->setTLSCertificate(certificate_); @@ -350,19 +355,19 @@ const JID& CoreClient::getJID() const { return jid_; } } void CoreClient::purgePassword() { safeClear(password_); } void CoreClient::resetConnector() { - connector_->onConnectFinished.disconnect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); + connector_->onConnectFinished.disconnect(boost::bind(&CoreClient::handleConnectorFinished, this, _1, _2)); connector_.reset(); foreach(ConnectionFactory* f, proxyConnectionFactories) { delete f; } proxyConnectionFactories.clear(); } void CoreClient::resetSession() { session_->onFinished.disconnect(boost::bind(&CoreClient::handleSessionFinished, this, _1)); diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h index c9a6f30..cafc634 100644 --- a/Swiften/Client/CoreClient.h +++ b/Swiften/Client/CoreClient.h @@ -197,19 +197,19 @@ namespace Swift { return networkFactories; } /** * Called before onConnected signal is emmitted. */ virtual void handleConnected() {}; private: - void handleConnectorFinished(boost::shared_ptr<Connection>); + void handleConnectorFinished(boost::shared_ptr<Connection>, boost::shared_ptr<Error> error); void handleStanzaChannelAvailableChanged(bool available); void handleSessionFinished(boost::shared_ptr<Error>); void handleNeedCredentials(); void handleDataRead(const SafeByteArray&); void handleDataWritten(const SafeByteArray&); void handlePresenceReceived(boost::shared_ptr<Presence>); void handleMessageReceived(boost::shared_ptr<Message>); void handleStanzaAcked(boost::shared_ptr<Stanza>); void purgePassword(); diff --git a/Swiften/Elements/DeliveryReceipt.h b/Swiften/Elements/DeliveryReceipt.h index f42176f..bd634db 100644 --- a/Swiften/Elements/DeliveryReceipt.h +++ b/Swiften/Elements/DeliveryReceipt.h @@ -2,18 +2,20 @@ * Copyright (c) 2011 Tobias Markmann * Licensed under the BSD license. * See http://www.opensource.org/licenses/bsd-license.php for more information. */ #pragma once #include <string> +#include <string> + #include <Swiften/Elements/Payload.h> namespace Swift { class DeliveryReceipt : public Payload { public: typedef boost::shared_ptr<DeliveryReceipt> ref; public: diff --git a/Swiften/Network/ChainedConnector.cpp b/Swiften/Network/ChainedConnector.cpp index 1a38e53..0a1283f 100644 --- a/Swiften/Network/ChainedConnector.cpp +++ b/Swiften/Network/ChainedConnector.cpp @@ -35,48 +35,49 @@ void ChainedConnector::setTimeoutMilliseconds(int milliseconds) { void ChainedConnector::start() { SWIFT_LOG(debug) << "Starting queued connector for " << hostname << std::endl; connectionFactoryQueue = std::deque<ConnectionFactory*>(connectionFactories.begin(), connectionFactories.end()); tryNextConnectionFactory(); } void ChainedConnector::stop() { if (currentConnector) { - currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); currentConnector->stop(); currentConnector.reset(); } - finish(boost::shared_ptr<Connection>()); + finish(boost::shared_ptr<Connection>(), boost::shared_ptr<Error>()); } void ChainedConnector::tryNextConnectionFactory() { assert(!currentConnector); if (connectionFactoryQueue.empty()) { SWIFT_LOG(debug) << "No more connection factories" << std::endl; - finish(boost::shared_ptr<Connection>()); + finish(boost::shared_ptr<Connection>(), lastError); } else { ConnectionFactory* connectionFactory = connectionFactoryQueue.front(); SWIFT_LOG(debug) << "Trying next connection factory: " << typeid(*connectionFactory).name() << std::endl; connectionFactoryQueue.pop_front(); currentConnector = Connector::create(hostname, resolver, connectionFactory, timerFactory); currentConnector->setTimeoutMilliseconds(timeoutMilliseconds); - currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); currentConnector->start(); } } -void ChainedConnector::handleConnectorFinished(boost::shared_ptr<Connection> connection) { +void ChainedConnector::handleConnectorFinished(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> error) { SWIFT_LOG(debug) << "Connector finished" << std::endl; - currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); + lastError = error; currentConnector.reset(); if (connection) { - finish(connection); + finish(connection, error); } else { tryNextConnectionFactory(); } } -void ChainedConnector::finish(boost::shared_ptr<Connection> connection) { - onConnectFinished(connection); +void ChainedConnector::finish(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> error) { + onConnectFinished(connection, error); } diff --git a/Swiften/Network/ChainedConnector.h b/Swiften/Network/ChainedConnector.h index 15b17f3..12ef023 100644 --- a/Swiften/Network/ChainedConnector.h +++ b/Swiften/Network/ChainedConnector.h @@ -6,42 +6,44 @@ #pragma once #include <string> #include <vector> #include <deque> #include <boost/shared_ptr.hpp> #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/Error.h> namespace Swift { class Connection; class Connector; class ConnectionFactory; class TimerFactory; class DomainNameResolver; class ChainedConnector { public: ChainedConnector(const std::string& hostname, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); void setTimeoutMilliseconds(int milliseconds); void start(); void stop(); - boost::signal<void (boost::shared_ptr<Connection>)> onConnectFinished; + boost::signal<void (boost::shared_ptr<Connection>, boost::shared_ptr<Error>)> onConnectFinished; private: - void finish(boost::shared_ptr<Connection> connection); + void finish(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error>); void tryNextConnectionFactory(); - void handleConnectorFinished(boost::shared_ptr<Connection>); + void handleConnectorFinished(boost::shared_ptr<Connection>, boost::shared_ptr<Error>); private: std::string hostname; DomainNameResolver* resolver; std::vector<ConnectionFactory*> connectionFactories; TimerFactory* timerFactory; int timeoutMilliseconds; std::deque<ConnectionFactory*> connectionFactoryQueue; boost::shared_ptr<Connector> currentConnector; + boost::shared_ptr<Error> lastError; }; }; diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp index 378875b..5e7f8d9 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, int defaultPort) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), defaultPort(defaultPort), 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), foundSomeDNS(false) { } 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; @@ -50,18 +50,21 @@ void Connector::queryAddress(const std::string& hostname) { addressQuery = resolver->createAddressQuery(hostname); addressQuery->onResult.connect(boost::bind(&Connector::handleAddressQueryResult, shared_from_this(), _1, _2)); addressQuery->run(); } void Connector::handleServiceQueryResult(const std::vector<DomainNameServiceQuery::Result>& result) { SWIFT_LOG(debug) << result.size() << " SRV result(s)" << std::endl; serviceQueryResults = std::deque<DomainNameServiceQuery::Result>(result.begin(), result.end()); serviceQuery.reset(); + if (!serviceQueryResults.empty()) { + foundSomeDNS = true; + } tryNextServiceOrFallback(); } void Connector::tryNextServiceOrFallback() { if (queriedAllServices) { SWIFT_LOG(debug) << "Queried all services" << std::endl; finish(boost::shared_ptr<Connection>()); } else if (serviceQueryResults.empty()) { @@ -80,18 +83,19 @@ void Connector::handleAddressQueryResult(const std::vector<HostAddress>& address SWIFT_LOG(debug) << addresses.size() << " addresses" << std::endl; addressQuery.reset(); if (error || addresses.empty()) { if (!serviceQueryResults.empty()) { serviceQueryResults.pop_front(); } tryNextServiceOrFallback(); } else { + foundSomeDNS = true; addressQueryResults = std::deque<HostAddress>(addresses.begin(), addresses.end()); tryNextAddress(); } } void Connector::tryNextAddress() { if (addressQueryResults.empty()) { SWIFT_LOG(debug) << "Done trying addresses. Moving on." << std::endl; // Done trying all addresses. Move on to the next host. @@ -154,18 +158,18 @@ void Connector::finish(boost::shared_ptr<Connection> connection) { } if (addressQuery) { addressQuery->onResult.disconnect(boost::bind(&Connector::handleAddressQueryResult, shared_from_this(), _1, _2)); addressQuery.reset(); } if (currentConnection) { currentConnection->onConnectFinished.disconnect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); currentConnection.reset(); } - onConnectFinished(connection); + onConnectFinished(connection, (connection || foundSomeDNS) ? boost::shared_ptr<Error>() : boost::make_shared<DomainNameResolveError>()); } void Connector::handleTimeout() { SWIFT_LOG(debug) << "Timeout" << std::endl; finish(boost::shared_ptr<Connection>()); } }; diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h index 8f2c359..bf0efaf 100644 --- a/Swiften/Network/Connector.h +++ b/Swiften/Network/Connector.h @@ -29,19 +29,19 @@ namespace Swift { 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; + boost::signal<void (boost::shared_ptr<Connection>, boost::shared_ptr<Error>)> onConnectFinished; private: 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(); @@ -61,11 +61,12 @@ namespace Swift { 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; + bool foundSomeDNS; }; }; diff --git a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp index c7d23da..a2fceb9 100644 --- a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp @@ -11,31 +11,34 @@ #include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Network/ChainedConnector.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Network/StaticDomainNameResolver.h> #include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Network/DomainNameResolveError.h> using namespace Swift; class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChainedConnectorTest); CPPUNIT_TEST(testConnect_FirstConnectorSucceeds); CPPUNIT_TEST(testConnect_SecondConnectorSucceeds); CPPUNIT_TEST(testConnect_NoConnectorSucceeds); + CPPUNIT_TEST(testConnect_NoDNS); CPPUNIT_TEST(testStop); CPPUNIT_TEST_SUITE_END(); public: void setUp() { + error.reset(); host = HostAddressPort(HostAddress("1.1.1.1"), 1234); eventLoop = new DummyEventLoop(); resolver = new StaticDomainNameResolver(eventLoop); resolver->addXMPPClientService("foo.com", host); connectionFactory1 = new MockConnectionFactory(eventLoop, 1); connectionFactory2 = new MockConnectionFactory(eventLoop, 2); timerFactory = new DummyTimerFactory(); } @@ -52,43 +55,63 @@ class ChainedConnectorTest : public CppUnit::TestFixture { connectionFactory1->connects = true; connectionFactory2->connects = false; testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT_EQUAL(1, boost::dynamic_pointer_cast<MockConnection>(connections[0])->id); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_SecondConnectorSucceeds() { boost::shared_ptr<ChainedConnector> testling(createConnector()); connectionFactory1->connects = false; connectionFactory2->connects = true; testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT_EQUAL(2, boost::dynamic_pointer_cast<MockConnection>(connections[0])->id); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_NoConnectorSucceeds() { boost::shared_ptr<ChainedConnector> testling(createConnector()); connectionFactory1->connects = false; connectionFactory2->connects = false; testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); + } + + void testConnect_NoDNS() { + /* Reset resolver so there's no record */ + delete resolver; + resolver = new StaticDomainNameResolver(eventLoop); + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = false; + connectionFactory2->connects = false; + + testling->start(); + //testling->stop(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testStop() { boost::shared_ptr<ChainedConnector> testling(createConnector()); connectionFactory1->connects = true; connectionFactory2->connects = false; testling->start(); testling->stop(); @@ -98,23 +121,24 @@ class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!connections[0]); } private: boost::shared_ptr<ChainedConnector> createConnector() { std::vector<ConnectionFactory*> factories; factories.push_back(connectionFactory1); factories.push_back(connectionFactory2); boost::shared_ptr<ChainedConnector> connector = boost::make_shared<ChainedConnector>("foo.com", resolver, factories, timerFactory); - connector->onConnectFinished.connect(boost::bind(&ChainedConnectorTest::handleConnectorFinished, this, _1)); + connector->onConnectFinished.connect(boost::bind(&ChainedConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; } - void handleConnectorFinished(boost::shared_ptr<Connection> connection) { + void handleConnectorFinished(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> resultError) { + error = resultError; boost::shared_ptr<MockConnection> c(boost::dynamic_pointer_cast<MockConnection>(connection)); if (connection) { assert(c); } connections.push_back(c); } struct MockConnection : public Connection { public: @@ -150,12 +174,13 @@ class ChainedConnectorTest : public CppUnit::TestFixture { private: HostAddressPort host; DummyEventLoop* eventLoop; StaticDomainNameResolver* resolver; MockConnectionFactory* connectionFactory1; MockConnectionFactory* connectionFactory2; DummyTimerFactory* timerFactory; std::vector< boost::shared_ptr<MockConnection> > connections; + boost::shared_ptr<Error> error; }; CPPUNIT_TEST_SUITE_REGISTRATION(ChainedConnectorTest); diff --git a/Swiften/Network/UnitTest/ConnectorTest.cpp b/Swiften/Network/UnitTest/ConnectorTest.cpp index 6488e67..67270be 100644 --- a/Swiften/Network/UnitTest/ConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ConnectorTest.cpp @@ -11,18 +11,19 @@ #include <boost/bind.hpp> #include <Swiften/Network/Connector.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Network/StaticDomainNameResolver.h> #include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Network/DomainNameAddressQuery.h> using namespace Swift; class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ConnectorTest); CPPUNIT_TEST(testConnect); CPPUNIT_TEST(testConnect_FirstAddressHostFails); CPPUNIT_TEST(testConnect_NoSRVHost); CPPUNIT_TEST(testConnect_NoHosts); @@ -61,171 +62,183 @@ class ConnectorTest : public CppUnit::TestFixture { resolver->addXMPPClientService("foo.com", host2); resolver->addAddress("foo.com", host3.getAddress()); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host1 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_NoSRVHost() { Connector::ref testling(createConnector()); resolver->addAddress("foo.com", host3.getAddress()); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_FirstAddressHostFails() { Connector::ref testling(createConnector()); HostAddress address1("1.1.1.1"); HostAddress address2("2.2.2.2"); resolver->addXMPPClientService("foo.com", "host-foo.com", 1234); resolver->addAddress("host-foo.com", address1); resolver->addAddress("host-foo.com", address2); connectionFactory->failingPorts.push_back(HostAddressPort(address1, 1234)); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(HostAddressPort(address2, 1234) == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_NoHosts() { Connector::ref testling(createConnector()); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_FirstSRVHostFails() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); connectionFactory->failingPorts.push_back(host1); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(host2 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_AllSRVHostsFailWithoutFallbackHost() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); connectionFactory->failingPorts.push_back(host1); connectionFactory->failingPorts.push_back(host2); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_AllSRVHostsFailWithFallbackHost() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); resolver->addAddress("foo.com", host3.getAddress()); connectionFactory->failingPorts.push_back(host1); connectionFactory->failingPorts.push_back(host2); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_SRVAndFallbackHostsFail() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addAddress("foo.com", host3.getAddress()); connectionFactory->failingPorts.push_back(host1); connectionFactory->failingPorts.push_back(host3); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_TimeoutDuringResolve() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); resolver->setIsResponsive(false); testling->start(); eventLoop->processEvents(); timerFactory->setTime(10); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); CPPUNIT_ASSERT(!connections[0]); } void testConnect_TimeoutDuringConnect() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); resolver->addXMPPClientService("foo.com", host1); connectionFactory->isResponsive = false; testling->start(); eventLoop->processEvents(); timerFactory->setTime(10); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_NoTimeout() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); resolver->addXMPPClientService("foo.com", host1); testling->start(); eventLoop->processEvents(); timerFactory->setTime(10); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testStop_DuringSRVQuery() { - Connector::ref testling(createConnector()); - resolver->addXMPPClientService("foo.com", host1); + Connector::ref testling(createConnector()); + resolver->addXMPPClientService("foo.com", host1); - testling->start(); - testling->stop(); + testling->start(); + testling->stop(); - eventLoop->processEvents(); + eventLoop->processEvents(); - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); - CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testStop_Timeout() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); resolver->addXMPPClientService("foo.com", host1); testling->start(); testling->stop(); @@ -236,28 +249,29 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); } private: Connector::ref createConnector() { Connector::ref connector = Connector::create("foo.com", resolver, connectionFactory, timerFactory); - connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1)); + connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; } - void handleConnectorFinished(boost::shared_ptr<Connection> connection) { + void handleConnectorFinished(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> resultError) { boost::shared_ptr<MockConnection> c(boost::dynamic_pointer_cast<MockConnection>(connection)); if (connection) { assert(c); } connections.push_back(c); + error = resultError; } struct MockConnection : public Connection { public: MockConnection(const std::vector<HostAddressPort>& failingPorts, bool isResponsive, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), isResponsive(isResponsive) {} void listen() { assert(false); } void connect(const HostAddressPort& address) { hostAddressPort = address; @@ -293,12 +307,14 @@ class ConnectorTest : public CppUnit::TestFixture { private: HostAddressPort host1; HostAddressPort host2; HostAddressPort host3; DummyEventLoop* eventLoop; StaticDomainNameResolver* resolver; MockConnectionFactory* connectionFactory; DummyTimerFactory* timerFactory; std::vector< boost::shared_ptr<MockConnection> > connections; + boost::shared_ptr<Error> error; + }; CPPUNIT_TEST_SUITE_REGISTRATION(ConnectorTest); |