From 4b6694377e3a0308009bdf90be0a4e0de463b215 Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Sat, 3 Mar 2012 11:56:45 +0000 Subject: Pass along errors about DNS resolution. 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 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -63,7 +64,7 @@ void CoreClient::connect(const std::string& host) { 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()) { @@ -73,7 +74,7 @@ void CoreClient::connect(const std::string& host) { if (options.boshURL.empty()) { connectionFactories.push_back(networkFactories->getConnectionFactory()); connector_ = boost::make_shared(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(); } @@ -129,13 +130,17 @@ void CoreClient::bindSessionToStream() { /** * Only called for TCP sessions. BOSH is handled inside the BOSHSessionStream. */ -void CoreClient::handleConnectorFinished(boost::shared_ptr connection) { +void CoreClient::handleConnectorFinished(boost::shared_ptr connection, boost::shared_ptr error) { resetConnector(); if (!connection) { if (options.forgetPassword) { purgePassword(); } - onDisconnected(disconnectRequested_ ? boost::optional() : boost::optional(ClientError::ConnectionError)); + boost::optional clientError; + if (!disconnectRequested_) { + clientError = boost::dynamic_pointer_cast(error) ? boost::optional(ClientError::DomainNameResolveError) : boost::optional(ClientError::ConnectionError); + } + onDisconnected(clientError); } else { assert(!connection_); @@ -356,7 +361,7 @@ void CoreClient::purgePassword() { } 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; 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 @@ -203,7 +203,7 @@ namespace Swift { virtual void handleConnected() {}; private: - void handleConnectorFinished(boost::shared_ptr); + void handleConnectorFinished(boost::shared_ptr, boost::shared_ptr error); void handleStanzaChannelAvailableChanged(bool available); void handleSessionFinished(boost::shared_ptr); void handleNeedCredentials(); 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 @@ -8,6 +8,8 @@ #include +#include + #include namespace Swift { 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 @@ -41,18 +41,18 @@ void ChainedConnector::start() { 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()); + finish(boost::shared_ptr(), boost::shared_ptr()); } void ChainedConnector::tryNextConnectionFactory() { assert(!currentConnector); if (connectionFactoryQueue.empty()) { SWIFT_LOG(debug) << "No more connection factories" << std::endl; - finish(boost::shared_ptr()); + finish(boost::shared_ptr(), lastError); } else { ConnectionFactory* connectionFactory = connectionFactoryQueue.front(); @@ -60,23 +60,24 @@ void ChainedConnector::tryNextConnectionFactory() { 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) { +void ChainedConnector::handleConnectorFinished(boost::shared_ptr connection, boost::shared_ptr 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) { - onConnectFinished(connection); +void ChainedConnector::finish(boost::shared_ptr connection, boost::shared_ptr 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 @@ -12,6 +12,7 @@ #include #include +#include namespace Swift { class Connection; @@ -28,12 +29,12 @@ namespace Swift { void start(); void stop(); - boost::signal)> onConnectFinished; + boost::signal, boost::shared_ptr)> onConnectFinished; private: - void finish(boost::shared_ptr connection); + void finish(boost::shared_ptr connection, boost::shared_ptr); void tryNextConnectionFactory(); - void handleConnectorFinished(boost::shared_ptr); + void handleConnectorFinished(boost::shared_ptr, boost::shared_ptr); private: std::string hostname; @@ -43,5 +44,6 @@ namespace Swift { int timeoutMilliseconds; std::deque connectionFactoryQueue; boost::shared_ptr currentConnector; + boost::shared_ptr 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 @@ -17,7 +17,7 @@ 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) { @@ -56,6 +56,9 @@ void Connector::handleServiceQueryResult(const std::vector(result.begin(), result.end()); serviceQuery.reset(); + if (!serviceQueryResults.empty()) { + foundSomeDNS = true; + } tryNextServiceOrFallback(); } @@ -86,6 +89,7 @@ void Connector::handleAddressQueryResult(const std::vector& address tryNextServiceOrFallback(); } else { + foundSomeDNS = true; addressQueryResults = std::deque(addresses.begin(), addresses.end()); tryNextAddress(); } @@ -160,7 +164,7 @@ void Connector::finish(boost::shared_ptr connection) { currentConnection->onConnectFinished.disconnect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); currentConnection.reset(); } - onConnectFinished(connection); + onConnectFinished(connection, (connection || foundSomeDNS) ? boost::shared_ptr() : boost::make_shared()); } void Connector::handleTimeout() { 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 @@ -35,7 +35,7 @@ namespace Swift { void start(); void stop(); - boost::signal)> onConnectFinished; + boost::signal, boost::shared_ptr)> onConnectFinished; private: Connector(const std::string& hostname, DomainNameResolver*, ConnectionFactory*, TimerFactory*, int defaultPort); @@ -67,5 +67,6 @@ namespace Swift { std::deque addressQueryResults; bool queriedAllServices; boost::shared_ptr 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 @@ -17,6 +17,7 @@ #include #include #include +#include using namespace Swift; @@ -25,11 +26,13 @@ class ChainedConnectorTest : public CppUnit::TestFixture { 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); @@ -58,6 +61,7 @@ class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT_EQUAL(1, boost::dynamic_pointer_cast(connections[0])->id); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_SecondConnectorSucceeds() { @@ -71,6 +75,7 @@ class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT_EQUAL(2, boost::dynamic_pointer_cast(connections[0])->id); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_NoConnectorSucceeds() { @@ -83,6 +88,24 @@ class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); + } + + void testConnect_NoDNS() { + /* Reset resolver so there's no record */ + delete resolver; + resolver = new StaticDomainNameResolver(eventLoop); + boost::shared_ptr testling(createConnector()); + connectionFactory1->connects = false; + connectionFactory2->connects = false; + + testling->start(); + //testling->stop(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast(error)); } void testStop() { @@ -104,11 +127,12 @@ class ChainedConnectorTest : public CppUnit::TestFixture { factories.push_back(connectionFactory1); factories.push_back(connectionFactory2); boost::shared_ptr connector = boost::make_shared("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) { + void handleConnectorFinished(boost::shared_ptr connection, boost::shared_ptr resultError) { + error = resultError; boost::shared_ptr c(boost::dynamic_pointer_cast(connection)); if (connection) { assert(c); @@ -156,6 +180,7 @@ class ChainedConnectorTest : public CppUnit::TestFixture { MockConnectionFactory* connectionFactory2; DummyTimerFactory* timerFactory; std::vector< boost::shared_ptr > connections; + boost::shared_ptr 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 @@ -17,6 +17,7 @@ #include #include #include +#include using namespace Swift; @@ -67,6 +68,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host1 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_NoSRVHost() { @@ -79,6 +81,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_FirstAddressHostFails() { @@ -97,6 +100,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(HostAddressPort(address2, 1234) == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_NoHosts() { @@ -107,6 +111,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast(error)); } void testConnect_FirstSRVHostFails() { @@ -120,6 +125,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(host2 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_AllSRVHostsFailWithoutFallbackHost() { @@ -134,6 +140,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_AllSRVHostsFailWithFallbackHost() { @@ -150,6 +157,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_SRVAndFallbackHostsFail() { @@ -164,6 +172,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_TimeoutDuringResolve() { @@ -177,6 +186,7 @@ class ConnectorTest : public CppUnit::TestFixture { eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast(error)); CPPUNIT_ASSERT(!connections[0]); } @@ -193,6 +203,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(error)); } void testConnect_NoTimeout() { @@ -207,19 +218,21 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast(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(connections.size())); - CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast(error)); } void testStop_Timeout() { @@ -242,16 +255,17 @@ class ConnectorTest : public CppUnit::TestFixture { 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) { + void handleConnectorFinished(boost::shared_ptr connection, boost::shared_ptr resultError) { boost::shared_ptr c(boost::dynamic_pointer_cast(connection)); if (connection) { assert(c); } connections.push_back(c); + error = resultError; } struct MockConnection : public Connection { @@ -299,6 +313,8 @@ class ConnectorTest : public CppUnit::TestFixture { MockConnectionFactory* connectionFactory; DummyTimerFactory* timerFactory; std::vector< boost::shared_ptr > connections; + boost::shared_ptr error; + }; CPPUNIT_TEST_SUITE_REGISTRATION(ConnectorTest); -- cgit v0.10.2-6-g49f6