summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Smith <git@kismith.co.uk>2012-03-03 11:56:45 (GMT)
committerKevin Smith <git@kismith.co.uk>2012-03-04 16:01:01 (GMT)
commit4b6694377e3a0308009bdf90be0a4e0de463b215 (patch)
tree86b860395d040c38774dfa4400979f9687dff8ae
parentfde71bd59b1412ae475c06f2d4100ce088e86af6 (diff)
downloadswift-contrib-4b6694377e3a0308009bdf90be0a4e0de463b215.zip
swift-contrib-4b6694377e3a0308009bdf90be0a4e0de463b215.tar.bz2
Pass along errors about DNS resolution.
-rw-r--r--Swiften/Client/CoreClient.cpp15
-rw-r--r--Swiften/Client/CoreClient.h2
-rw-r--r--Swiften/Elements/DeliveryReceipt.h2
-rw-r--r--Swiften/Network/ChainedConnector.cpp19
-rw-r--r--Swiften/Network/ChainedConnector.h8
-rw-r--r--Swiften/Network/Connector.cpp8
-rw-r--r--Swiften/Network/Connector.h3
-rw-r--r--Swiften/Network/UnitTest/ChainedConnectorTest.cpp29
-rw-r--r--Swiften/Network/UnitTest/ConnectorTest.cpp34
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);