summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/MainController.cpp4
-rw-r--r--Swiften/Client/ClientOptions.h2
-rw-r--r--Swiften/Client/CoreClient.cpp15
-rw-r--r--Swiften/Network/BOSHConnection.cpp46
-rw-r--r--Swiften/Network/BOSHConnection.h18
-rw-r--r--Swiften/Network/BOSHConnectionPool.cpp34
-rw-r--r--Swiften/Network/BOSHConnectionPool.h11
-rw-r--r--Swiften/Network/CachingNameOnlyDomainNameResolver.cpp32
-rw-r--r--Swiften/Network/CachingNameOnlyDomainNameResolver.h32
-rw-r--r--Swiften/Network/Connector.cpp4
-rw-r--r--Swiften/Network/Connector.h7
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.cpp35
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.h19
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp12
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnectionFactory.h19
-rw-r--r--Swiften/Network/SConscript1
-rw-r--r--Swiften/Network/StaticDomainNameResolver.cpp29
-rw-r--r--Swiften/Network/StaticDomainNameResolver.h5
-rw-r--r--Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp38
-rw-r--r--Swiften/Network/UnitTest/BOSHConnectionTest.cpp14
-rw-r--r--Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp55
-rw-r--r--Swiften/Session/BOSHSessionStream.cpp7
-rw-r--r--Swiften/Session/BOSHSessionStream.h1
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
@@ -473,70 +473,74 @@ void MainController::performLoginFromCachedCredentials() {
certificateTrustChecker_ = new CertificateStorageTrustChecker(certificateStorage_);
client_ = boost::make_shared<Swift::Client>(clientJID, createSafeByteArray(password_.c_str()), networkFactories_, storages_);
clientInitialized_ = true;
client_->setCertificateTrustChecker(certificateTrustChecker_);
client_->onDataRead.connect(boost::bind(&XMLConsoleController::handleDataRead, xmlConsoleController_, _1));
client_->onDataWritten.connect(boost::bind(&XMLConsoleController::handleDataWritten, xmlConsoleController_, _1));
client_->onDisconnected.connect(boost::bind(&MainController::handleDisconnected, this, _1));
client_->onConnected.connect(boost::bind(&MainController::handleConnected, this));
client_->setSoftwareVersion(CLIENT_NAME, buildVersion);
client_->getVCardManager()->onVCardChanged.connect(boost::bind(&MainController::handleVCardReceived, this, _1, _2));
presenceNotifier_ = new PresenceNotifier(client_->getStanzaChannel(), notifier_, client_->getMUCRegistry(), client_->getAvatarManager(), client_->getNickResolver(), client_->getPresenceOracle(), networkFactories_->getTimerFactory());
presenceNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1));
eventNotifier_ = new EventNotifier(eventController_, notifier_, client_->getAvatarManager(), client_->getNickResolver());
eventNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1));
if (!certificateFile_.empty()) {
client_->setCertificate(certificateFile_);
}
boost::shared_ptr<Presence> presence(new Presence());
presence->setShow(static_cast<StatusShow::Type>(profileSettings_->getIntSetting("lastShow", StatusShow::Online)));
presence->setStatus(profileSettings_->getStringSetting("lastStatus"));
statusTracker_->setRequestedPresence(presence);
} else {
/* In case we're in the middle of another login, make sure they don't overlap */
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();
loginWindow_->quit();
}
else if (error) {
std::string message;
std::string certificateErrorMessage;
switch(error->getType()) {
case ClientError::UnknownError: message = QT_TRANSLATE_NOOP("", "Unknown Error"); break;
case ClientError::DomainNameResolveError: message = QT_TRANSLATE_NOOP("", "Unable to find server"); break;
case ClientError::ConnectionError: message = QT_TRANSLATE_NOOP("", "Error connecting to server"); break;
case ClientError::ConnectionReadError: message = QT_TRANSLATE_NOOP("", "Error while receiving server data"); break;
case ClientError::ConnectionWriteError: message = QT_TRANSLATE_NOOP("", "Error while sending data to the server"); break;
case ClientError::XMLError: message = QT_TRANSLATE_NOOP("", "Error parsing server data"); break;
case ClientError::AuthenticationFailedError: message = QT_TRANSLATE_NOOP("", "Login/password invalid"); break;
case ClientError::CompressionFailedError: message = QT_TRANSLATE_NOOP("", "Error while compressing stream"); break;
case ClientError::ServerVerificationFailedError: message = QT_TRANSLATE_NOOP("", "Server verification failed"); break;
case ClientError::NoSupportedAuthMechanismsError: message = QT_TRANSLATE_NOOP("", "Authentication mechanisms not supported"); break;
case ClientError::UnexpectedElementError: message = QT_TRANSLATE_NOOP("", "Unexpected response"); break;
case ClientError::ResourceBindError: message = QT_TRANSLATE_NOOP("", "Error binding resource"); break;
case ClientError::SessionStartError: message = QT_TRANSLATE_NOOP("", "Error starting session"); break;
case ClientError::StreamError: message = QT_TRANSLATE_NOOP("", "Stream error"); break;
case ClientError::TLSError: message = QT_TRANSLATE_NOOP("", "Encryption error"); break;
case ClientError::ClientCertificateLoadError: message = QT_TRANSLATE_NOOP("", "Error loading certificate (Invalid password?)"); break;
case ClientError::ClientCertificateError: message = QT_TRANSLATE_NOOP("", "Certificate not authorized"); break;
case ClientError::UnknownCertificateError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Unknown certificate"); break;
case ClientError::CertificateExpiredError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has expired"); break;
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
@@ -35,57 +35,55 @@ namespace Swift {
UseTLS useTLS;
/**
* Sets whether plaintext authentication is
* allowed over non-TLS-encrypted connections.
*
* Default: false
*/
bool allowPLAINWithoutTLS;
/**
* Use XEP-196 stream resumption when available.
*
* Default: false
*/
bool useStreamResumption;
/**
* Forget the password once it's used.
* This makes the Client useless after the first login attempt.
*
* FIXME: This is a temporary workaround.
*
* Default: false
*/
bool forgetPassword;
/**
* 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)
*/
SafeString boshHTTPConnectProxyAuthID;
SafeString boshHTTPConnectProxyAuthPassword;
};
}
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
@@ -35,97 +35,98 @@ CoreClient::CoreClient(const JID& jid, const SafeByteArray& password, NetworkFac
stanzaChannel_->onStanzaAcked.connect(boost::bind(&CoreClient::handleStanzaAcked, this, _1));
stanzaChannel_->onAvailableChanged.connect(boost::bind(&CoreClient::handleStanzaChannelAvailableChanged, this, _1));
iqRouter_ = new IQRouter(stanzaChannel_);
iqRouter_->setJID(jid);
}
CoreClient::~CoreClient() {
forceReset();
delete iqRouter_;
stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&CoreClient::handleStanzaChannelAvailableChanged, this, _1));
stanzaChannel_->onMessageReceived.disconnect(boost::bind(&CoreClient::handleMessageReceived, this, _1));
stanzaChannel_->onPresenceReceived.disconnect(boost::bind(&CoreClient::handlePresenceReceived, this, _1));
stanzaChannel_->onStanzaAcked.disconnect(boost::bind(&CoreClient::handleStanzaAcked, this, _1));
delete stanzaChannel_;
}
void CoreClient::connect(const ClientOptions& o) {
SWIFT_LOG(debug) << "Connecting" << std::endl;
options = o;
connect(jid_.getDomain());
}
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()) {
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();
}
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(
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() {
session_ = ClientSession::create(jid_, sessionStream_);
session_->setCertificateTrustChecker(certificateTrustChecker);
session_->setUseStreamCompression(options.useStreamCompression);
session_->setAllowPLAINOverNonTLS(options.allowPLAINWithoutTLS);
switch(options.useTLS) {
case ClientOptions::UseTLSWhenAvailable:
session_->setUseTLS(ClientSession::UseTLSWhenAvailable);
break;
case ClientOptions::NeverUseTLS:
session_->setUseTLS(ClientSession::NeverUseTLS);
break;
case ClientOptions::RequireTLS:
session_->setUseTLS(ClientSession::RequireTLS);
break;
}
session_->setUseAcks(options.useAcks);
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) {
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
@@ -1,168 +1,175 @@
/*
* Copyright (c) 2011 Thilo Cestonaro
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
/*
* Copyright (c) 2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#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);
}
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'";
}
if (terminate) {
content << " type='terminate'";
}
content << " xmlns='http://jabber.org/protocol/httpbind'>";
SafeByteArray safeContent = createSafeByteArray(content.str());
safeContent.insert(safeContent.end(), data.begin(), data.end());
safeContent.insert(safeContent.end(), contentTail.begin(), contentTail.end());
size = safeContent.size();
header << "POST /" << boshURL.getPath() << " HTTP/1.1\r\n"
<< "Host: " << boshURL.getHost() << ":" << boshURL.getPort() << "\r\n"
/*<< "Accept-Encoding: deflate\r\n"*/
<< "Content-Type: text/xml; charset=utf-8\r\n"
<< "Content-Length: " << size << "\r\n\r\n";
SafeByteArray safeHeader = createSafeByteArray(header.str());
safeHeader.insert(safeHeader.end(), safeContent.begin(), safeContent.end());
return std::pair<SafeByteArray, size_t>(safeHeader, size);
}
void BOSHConnection::write(const SafeByteArray& data, bool streamRestart, bool terminate) {
assert(connectionReady_);
assert(!sid_.empty());
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 << "'"
<< " ver='1.6'"
<< " wait='60'" /* FIXME: we probably want this configurable*/
/*<< " ack='0'" FIXME: support acks */
<< " xml:lang='en'"
<< " xmlns:xmpp='urn:xmpp:bosh'"
<< " xmpp:version='1.0'"
<< " xmlns='http://jabber.org/protocol/httpbind' />";
std::string contentString = content.str();
header << "POST /" << boshURL_.getPath() << " HTTP/1.1\r\n"
<< "Host: " << boshURL_.getHost() << ":" << boshURL_.getPort() << "\r\n"
/*<< "Accept-Encoding: deflate\r\n"*/
<< "Content-Type: text/xml; charset=utf-8\r\n"
<< "Content-Length: " << contentString.size() << "\r\n\r\n"
<< contentString;
waitingForStartResponse_ = true;
SafeByteArray safeHeader = createSafeByteArray(header.str());
onBOSHDataWritten(safeHeader);
connection_->write(safeHeader);
SWIFT_LOG(debug) << "write stream header: " << safeByteArrayToString(safeHeader) << std::endl;
}
void BOSHConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) {
onBOSHDataRead(*data);
@@ -233,48 +240,49 @@ BOSHError::Type BOSHConnection::parseTerminationCondition(const std::string& tex
}
else if (text == "policy-violation") {
condition = BOSHError::PolicyViolation;
}
else if (text == "remote-connection-failed") {
condition = BOSHError::RemoteConnectionFailed;
}
else if (text == "remote-stream-error") {
condition = BOSHError::RemoteStreamError;
}
else if (text == "see-other-uri") {
condition = BOSHError::SeeOtherURI;
}
else if (text == "system-shutdown") {
condition = BOSHError::SystemShutdown;
}
else if (text == "") {
condition = BOSHError::NoError;
}
return condition;
}
const std::string& BOSHConnection::getSID() {
return sid_;
}
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 */
return connectionReady_ && !pending_ && !waitingForStartResponse_ && !sid_.empty();
}
}
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
@@ -1,107 +1,107 @@
/*
* Copyright (c) 2011 Thilo Cestonaro
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
/*
* Copyright (c) 2011 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/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};
BOSHError(Type type) : SessionStream::Error(SessionStream::Error::ConnectionReadError), type(type) {}
Type getType() {return type;}
typedef boost::shared_ptr<BOSHError> ref;
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
@@ -1,83 +1,88 @@
/*
* Copyright (c) 2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swiften/Network/BOSHConnectionPool.h>
#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);
tryToSendQueuedData(); /* Will rebalance the connections */
}
void BOSHConnectionPool::restartStream() {
BOSHConnection::ref connection = getSuitableConnection();
if (connection) {
pendingRestart = false;
rid++;
connection->setRID(rid);
connection->restartStream();
restartCount++;
}
else {
pendingRestart = true;
}
}
void BOSHConnectionPool::writeFooter() {
pendingTerminate = true;
tryToSendQueuedData();
}
void BOSHConnectionPool::close() {
/* TODO: Send a terminate here. */
std::vector<BOSHConnection::ref> connectionCopies = connections;
foreach (BOSHConnection::ref connection, connectionCopies) {
@@ -177,71 +182,72 @@ void BOSHConnectionPool::tryToSendQueuedData() {
suitableConnection->write(createSafeByteArray(""));
}
else {
/* My thought process I went through when writing this, to aid anyone else confused why this can happen...
*
* What to do here? I think this isn't possible.
If you didn't have two connections, suitable would have made one.
If you have two connections and neither is suitable, pending would be true.
If you have a non-pending connection, it's suitable.
If I decide to do something here, remove assert above.
Ah! Yes, because there's a period between creating the connection and it being connected. */
}
}
}
}
}
void BOSHConnectionPool::handleHTTPError(const std::string& /*errorCode*/) {
handleSessionTerminated(boost::make_shared<BOSHError>(BOSHError::UndefinedCondition));
}
void BOSHConnectionPool::handleConnectionDisconnected(bool error, BOSHConnection::ref connection) {
destroyConnection(connection);
if (false && error) {
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();
connections.push_back(connection);
return connection;
}
void BOSHConnectionPool::destroyConnection(boost::shared_ptr<BOSHConnection> connection) {
connections.erase(std::remove(connections.begin(), connections.end(), connection), connections.end());
connection->onXMPPDataRead.disconnect(boost::bind(&BOSHConnectionPool::handleDataRead, this, _1));
connection->onSessionStarted.disconnect(boost::bind(&BOSHConnectionPool::handleSessionStarted, this, _1, _2));
connection->onBOSHDataRead.disconnect(boost::bind(&BOSHConnectionPool::handleBOSHDataRead, this, _1));
connection->onBOSHDataWritten.disconnect(boost::bind(&BOSHConnectionPool::handleBOSHDataWritten, this, _1));
connection->onDisconnected.disconnect(boost::bind(&BOSHConnectionPool::handleConnectionDisconnected, this, _1, connection));
connection->onConnectFinished.disconnect(boost::bind(&BOSHConnectionPool::handleConnectFinished, this, _1, connection));
connection->onSessionTerminated.disconnect(boost::bind(&BOSHConnectionPool::handleSessionTerminated, this, _1));
connection->onHTTPError.disconnect(boost::bind(&BOSHConnectionPool::handleHTTPError, this, _1));
}
void BOSHConnectionPool::handleSessionTerminated(BOSHError::ref error) {
onSessionTerminated(error);
}
void BOSHConnectionPool::handleBOSHDataRead(const SafeByteArray& data) {
onBOSHDataRead(data);
}
void BOSHConnectionPool::handleBOSHDataWritten(const SafeByteArray& data) {
onBOSHDataWritten(data);
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
@@ -1,67 +1,70 @@
/*
* Copyright (c) 2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#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;
boost::signal<void (const SafeByteArray&)> onBOSHDataRead;
boost::signal<void (const SafeByteArray&)> onBOSHDataWritten;
private:
void handleDataRead(const SafeByteArray& data);
void handleSessionStarted(const std::string& sid, size_t requests);
void handleBOSHDataRead(const SafeByteArray& data);
void handleBOSHDataWritten(const SafeByteArray& data);
void handleSessionTerminated(BOSHError::ref condition);
void handleConnectFinished(bool, BOSHConnection::ref connection);
void handleConnectionDisconnected(bool error, BOSHConnection::ref connection);
void handleHTTPError(const std::string& errorCode);
private:
BOSHConnection::ref createConnection();
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
@@ -1,55 +1,55 @@
/*
* Copyright (c) 2010 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swiften/Network/Connector.h>
#include <boost/bind.hpp>
#include <iostream>
#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;
assert(!currentConnection);
assert(!serviceQuery);
assert(!timer);
queriedAllServices = false;
serviceQuery = resolver->createServiceQuery("_xmpp-client._tcp." + hostname);
serviceQuery->onResult.connect(boost::bind(&Connector::handleServiceQueryResult, shared_from_this(), _1));
if (timeoutMilliseconds > 0) {
timer = timerFactory->createTimer(timeoutMilliseconds);
timer->onTick.connect(boost::bind(&Connector::handleTimeout, shared_from_this()));
timer->start();
}
serviceQuery->run();
}
void Connector::stop() {
finish(boost::shared_ptr<Connection>());
}
void Connector::queryAddress(const std::string& hostname) {
assert(!addressQuery);
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) {
@@ -73,71 +73,71 @@ void Connector::tryNextServiceOrFallback() {
else {
SWIFT_LOG(debug) << "Querying next address" << std::endl;
queryAddress(serviceQueryResults.front().hostname);
}
}
void Connector::handleAddressQueryResult(const std::vector<HostAddress>& addresses, boost::optional<DomainNameResolveError> error) {
SWIFT_LOG(debug) << addresses.size() << " addresses" << std::endl;
addressQuery.reset();
if (error || addresses.empty()) {
if (!serviceQueryResults.empty()) {
serviceQueryResults.pop_front();
}
tryNextServiceOrFallback();
}
else {
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.
if (!serviceQueryResults.empty()) {
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) {
assert(!currentConnection);
SWIFT_LOG(debug) << "Trying to connect to " << target.getAddress().toString() << ":" << target.getPort() << std::endl;
currentConnection = connectionFactory->createConnection();
currentConnection->onConnectFinished.connect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1));
currentConnection->connect(target);
}
void Connector::handleConnectionConnectFinished(bool error) {
SWIFT_LOG(debug) << "ConnectFinished: " << (error ? "error" : "success") << std::endl;
currentConnection->onConnectFinished.disconnect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1));
if (error) {
currentConnection.reset();
if (!addressQueryResults.empty()) {
tryNextAddress();
}
else {
if (!serviceQueryResults.empty()) {
serviceQueryResults.pop_front();
}
tryNextServiceOrFallback();
}
}
else {
finish(currentConnection);
}
}
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
@@ -1,70 +1,71 @@
/*
* Copyright (c) 2010 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <deque>
#include <Swiften/Base/boost_bsignals.h>
#include <boost/shared_ptr.hpp>
#include <Swiften/Network/DomainNameServiceQuery.h>
#include <Swiften/Network/Connection.h>
#include <Swiften/Network/Timer.h>
#include <Swiften/Network/HostAddressPort.h>
#include <string>
#include <Swiften/Network/DomainNameResolveError.h>
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);
void handleConnectionConnectFinished(bool error);
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,111 +1,124 @@
/*
* 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;
connection_->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));
append(data, createSafeByteArray("\r\n"));
}
append(data, createSafeByteArray("\r\n"));
SWIFT_LOG(debug) << "HTTP Proxy send headers: " << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl;
connection_->write(data);
}
else {
onConnectFinished(true);
}
}
void HTTPConnectProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) {
if (!connected_) {
SWIFT_LOG(debug) << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl;
std::vector<std::string> tmp = String::split(byteArrayToString(ByteArray(data->begin(), data->end())), ' ');
if(tmp.size() > 1) {
int status = boost::lexical_cast<int> (tmp[1].c_str());
SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl;
if (status / 100 == 2) { // all 2XX states are OK
connected_ = true;
onConnectFinished(false);
return;
}
SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl;
}
disconnect();
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
@@ -1,54 +1,55 @@
Import("swiften_env")
myenv = swiften_env.Clone()
myenv.MergeFlags(myenv["LIBIDN_FLAGS"])
if myenv.get("HAVE_CARES", False) :
myenv.MergeFlags(myenv.get("CARES_FLAGS", {}))
sourceList = [
"HTTPConnectProxiedConnection.cpp",
"HTTPConnectProxiedConnectionFactory.cpp",
"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",
"DummyTimerFactory.cpp",
"BoostTimerFactory.cpp",
"DomainNameResolver.cpp",
"DomainNameAddressQuery.cpp",
"DomainNameServiceQuery.cpp",
"PlatformDomainNameResolver.cpp",
"PlatformDomainNameServiceQuery.cpp",
"PlatformDomainNameAddressQuery.cpp",
"StaticDomainNameResolver.cpp",
"HostAddress.cpp",
"HostAddressPort.cpp",
"NetworkFactories.cpp",
"BoostNetworkFactories.cpp",
"NetworkEnvironment.cpp",
"Timer.cpp",
"TLSConnection.cpp",
"TLSConnectionFactory.cpp",
"BoostTimer.cpp",
"ProxyProvider.cpp",
"NullProxyProvider.cpp",
"NATTraverser.cpp",
"NullNATTraverser.cpp",
"NATTraversalGetPublicIPRequest.cpp",
"NATTraversalForwardPortRequest.cpp",
"NATTraversalRemovePortForwardingRequest.cpp",
"NATTraversalInterface.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
@@ -1,104 +1,119 @@
/*
* Copyright (c) 2010 Remko Tronçon
* Licensed under the GNU General Public License v3.
* 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));
}
void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, const HostAddressPort& address) {
static int hostid = 0;
std::string hostname(std::string("host-") + boost::lexical_cast<std::string>(hostid));
hostid++;
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
@@ -1,60 +1,59 @@
/*
* Copyright (c) 2010 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <vector>
#include <map>
#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;
}
const ServicesCollection& getServices() const {
return services;
}
bool getIsResponsive() const {
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
@@ -1,322 +1,352 @@
/*
* Copyright (c) 2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <QA/Checker/IO.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/optional.hpp>
#include <boost/bind.hpp>
#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/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);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
to = "wonderland.lit";
path = "http-bind";
port = "5280";
sid = "MyShinySID";
initial = "<body wait='60' "
"inactivity='30' "
"polling='5' "
"requests='2' "
"hold='1' "
"maxpause='120' "
"sid='" + sid + "' "
"ver='1.6' "
"from='wonderland.lit' "
"xmlns='http://jabber.org/protocol/httpbind'/>";
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]);
CPPUNIT_ASSERT_EQUAL(1, sessionStarted);
CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size());
testling->write(createSafeByteArray("<blah/>"));
eventLoop->processEvents();
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();
readResponse("<body/>", connectionFactory->connections[0]);
testling->restartStream();
readResponse("<body/>", connectionFactory->connections[0]);
testling->write(createSafeByteArray("<blah/>"));
testling->write(createSafeByteArray("<bleh/>"));
testling->write(createSafeByteArray("<bluh/>"));
eventLoop->processEvents();
CPPUNIT_ASSERT(st(2) >= connectionFactory->connections.size());
}
void testConnectionCount_ThreeWrites_ManualConnect() {
connectionFactory->autoFinishConnect = false;
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;
long rid = initialRID;
PoolRef testling = createTestling();
CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size());
c0 = connectionFactory->connections[0];
eventLoop->processEvents();
CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* header*/
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 */
CPPUNIT_ASSERT_EQUAL(fullBody, lastBody());
CPPUNIT_ASSERT(c0->pending);
CPPUNIT_ASSERT(c1->pending);
rid++;
readResponse("<body xmlns='http://jabber.org/protocol/httpbind'><message><splatploing/></message></body>", c0); /* Doesn't include necessary attributes - as the support is improved this'll start to fail */
eventLoop->processEvents();
CPPUNIT_ASSERT(!c0->pending);
CPPUNIT_ASSERT(c1->pending);
CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* don't send empty in [0], still have [1] waiting */
CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size());
rid++;
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());
std::string response = "<body authid='743da605-4c2e-4de1-afac-ac040dd4a940' xmpp:version='1.0' xmlns:stream='http://etherx.jabber.org/streams' xmlns:xmpp='urn:xmpp:xbosh' inactivity='60' wait='60' polling='5' secure='true' hold='1' from='prosody.doomsong.co.uk' ver='1.6' sid='743da605-4c2e-4de1-afac-ac040dd4a940' requests='2' xmlns='http://jabber.org/protocol/httpbind'><stream:features><auth xmlns='http://jabber.org/features/iq-auth'/><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>SCRAM-SHA-1</mechanism><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features></body>";
readResponse(response, connectionFactory->connections[0]);
eventLoop->processEvents();
CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size());
CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size());
std::string send = "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"SCRAM-SHA-1\">biwsbj1hZG1pbixyPWZhOWE5ZDhiLWZmMDctNGE4Yy04N2E3LTg4YWRiNDQxZGUwYg==</auth>";
testling->write(createSafeByteArray(send));
eventLoop->processEvents();
CPPUNIT_ASSERT_EQUAL(st(2), boshDataWritten.size());
CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size());
response = "<body xmlns='http://jabber.org/protocol/httpbind' sid='743da605-4c2e-4de1-afac-ac040dd4a940' xmlns:stream = 'http://etherx.jabber.org/streams'><challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1mYTlhOWQ4Yi1mZjA3LTRhOGMtODdhNy04OGFkYjQ0MWRlMGJhZmZlMWNhMy1mMDJkLTQ5NzEtYjkyNS0yM2NlNWQ2MDQyMjYscz1OVGd5WkdWaFptTXRaVE15WXkwMFpXUmhMV0ZqTURRdFpqYzRNbUppWmpGa1pqWXgsaT00MDk2</challenge></body>";
readResponse(response, connectionFactory->connections[0]);
eventLoop->processEvents();
CPPUNIT_ASSERT_EQUAL(st(2), boshDataWritten.size());
CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size());
send = "<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">Yz1iaXdzLHI9ZmE5YTlkOGItZmYwNy00YThjLTg3YTctODhhZGI0NDFkZTBiYWZmZTFjYTMtZjAyZC00OTcxLWI5MjUtMjNjZTVkNjA0MjI2LHA9aU11NWt3dDN2VWplU2RqL01Jb3VIRldkZjBnPQ==</response>";
testling->write(createSafeByteArray(send));
eventLoop->processEvents();
CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size());
CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size());
response = "<body xmlns='http://jabber.org/protocol/httpbind' sid='743da605-4c2e-4de1-afac-ac040dd4a940' xmlns:stream = 'http://etherx.jabber.org/streams'><success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1YNmNBY3BBOWxHNjNOOXF2bVQ5S0FacERrVm89</success></body>";
readResponse(response, connectionFactory->connections[0]);
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);
}
size_t st(int val) {
return static_cast<size_t>(val);
}
void handleXMPPDataRead(const SafeByteArray& d) {
xmppDataRead.push_back(safeByteArrayToString(d));
}
void handleBOSHDataRead(const SafeByteArray& d) {
boshDataRead.push_back(safeByteArrayToString(d));
}
void handleBOSHDataWritten(const SafeByteArray& d) {
boshDataWritten.push_back(safeByteArrayToString(d));
}
void handleSessionStarted() {
sessionStarted++;
}
void handleSessionTerminated() {
sessionTerminated++;
}
struct MockConnection : public Connection {
@@ -374,48 +404,50 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture {
void readResponse(const std::string& response, boost::shared_ptr<MockConnection> connection) {
connection->pending = false;
boost::shared_ptr<SafeByteArray> data1 = boost::make_shared<SafeByteArray>(createSafeByteArray(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/xml; charset=utf-8\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"Content-Length: "));
connection->onDataRead(data1);
boost::shared_ptr<SafeByteArray> data2 = boost::make_shared<SafeByteArray>(createSafeByteArray(boost::lexical_cast<std::string>(response.size())));
connection->onDataRead(data2);
boost::shared_ptr<SafeByteArray> data3 = boost::make_shared<SafeByteArray>(createSafeByteArray("\r\n\r\n"));
connection->onDataRead(data3);
boost::shared_ptr<SafeByteArray> data4 = boost::make_shared<SafeByteArray>(createSafeByteArray(response));
connection->onDataRead(data4);
}
std::string fullRequestFor(const std::string& data) {
std::string body = data;
std::string result = "POST /" + path + " HTTP/1.1\r\n"
+ "Host: " + to + ":" + port + "\r\n"
+ "Content-Type: text/xml; charset=utf-8\r\n"
+ "Content-Length: " + boost::lexical_cast<std::string>(body.size()) + "\r\n\r\n"
+ body;
return result;
}
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;
};
CPPUNIT_TEST_SUITE_REGISTRATION(BOSHConnectionPoolTest);
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
@@ -1,90 +1,96 @@
/*
* Copyright (c) 2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <QA/Checker/IO.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/optional.hpp>
#include <boost/bind.hpp>
#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);
CPPUNIT_TEST(testReadiness_pending);
CPPUNIT_TEST(testReadiness_disconnect);
CPPUNIT_TEST(testReadiness_noSID);
CPPUNIT_TEST(testWrite_Receive);
CPPUNIT_TEST(testWrite_ReceiveTwice);
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' "
"polling='5' "
"requests='2' "
"hold='1' "
"maxpause='120' "
"sid='MyShinySID' "
"ver='1.6' "
"from='wonderland.lit' "
"xmlns='http://jabber.org/protocol/httpbind'/>");
readResponse(initial, connectionFactory->connections[0]);
CPPUNIT_ASSERT_EQUAL(std::string("MyShinySID"), sid);
CPPUNIT_ASSERT(testling->isReadyToSend());
}
void testReadiness_ok() {
BOSHConnection::ref testling = createTestling();
testling->connect();
eventLoop->processEvents();
testling->setSID("blahhhhh");
CPPUNIT_ASSERT(testling->isReadyToSend());
}
void testReadiness_pending() {
BOSHConnection::ref testling = createTestling();
testling->connect();
eventLoop->processEvents();
testling->setSID("mySID");
@@ -153,71 +159,73 @@ class BOSHConnectionTest : public CppUnit::TestFixture {
boost::shared_ptr<SafeByteArray> data2 = boost::make_shared<SafeByteArray>(createSafeByteArray(
"\r\n<body xmlns='http://jabber.org/protocol/httpbind'>"
"<bl"));
boost::shared_ptr<SafeByteArray> data3 = boost::make_shared<SafeByteArray>(createSafeByteArray(
"ah/>"
"</body>"));
connection->onDataRead(data1);
connection->onDataRead(data2);
CPPUNIT_ASSERT(dataRead.empty());
connection->onDataRead(data3);
CPPUNIT_ASSERT_EQUAL(std::string("<blah/>"), byteArrayToString(dataRead));
}
void testHTTPRequest() {
std::string data = "<blah/>";
std::string sid = "wigglebloom";
std::string fullBody = "<body xmlns='http://jabber.org/protocol/httpbind' sid='" + sid + "' rid='20'>" + data + "</body>";
std::pair<SafeByteArray, size_t> http = BOSHConnection::createHTTPRequest(createSafeByteArray(data), false, false, 20, sid, URL());
CPPUNIT_ASSERT_EQUAL(fullBody.size(), http.second);
}
void testHTTPRequest_Empty() {
std::string data = "";
std::string sid = "wigglebloomsickle";
std::string fullBody = "<body rid='42' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'>" + data + "</body>";
std::pair<SafeByteArray, size_t> http = BOSHConnection::createHTTPRequest(createSafeByteArray(data), false, false, 42, sid, URL());
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) {
connectFinished = true;
connectFinishedWithError = error;
}
void handleDisconnected(bool e) {
disconnected = true;
disconnectedError = e;
}
void handleDataRead(const SafeByteArray& d) {
append(dataRead, d);
}
void handleSID(const std::string& s) {
sid = s;
}
struct MockConnection : public Connection {
public:
MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) {
}
void listen() { assert(false); }
void connect(const HostAddressPort& address) {
hostAddressPort = address;
@@ -252,41 +260,43 @@ class BOSHConnectionTest : public CppUnit::TestFixture {
connections.push_back(connection);
return connection;
}
EventLoop* eventLoop;
std::vector< boost::shared_ptr<MockConnection> > connections;
std::vector<HostAddressPort> failingPorts;
};
void readResponse(const std::string& response, boost::shared_ptr<MockConnection> connection) {
boost::shared_ptr<SafeByteArray> data1 = boost::make_shared<SafeByteArray>(createSafeByteArray(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/xml; charset=utf-8\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Access-Control-Allow-Headers: Content-Type\r\n"
"Content-Length: "));
connection->onDataRead(data1);
boost::shared_ptr<SafeByteArray> data2 = boost::make_shared<SafeByteArray>(createSafeByteArray(boost::lexical_cast<std::string>(response.size())));
connection->onDataRead(data2);
boost::shared_ptr<SafeByteArray> data3 = boost::make_shared<SafeByteArray>(createSafeByteArray("\r\n\r\n"));
connection->onDataRead(data3);
boost::shared_ptr<SafeByteArray> data4 = boost::make_shared<SafeByteArray>(createSafeByteArray(response));
connection->onDataRead(data4);
}
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
@@ -1,246 +1,257 @@
/*
* Copyright (c) 2010 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <QA/Checker/IO.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/optional.hpp>
#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);
CPPUNIT_TEST(testConnect_ReceiveMalformedConnectResponse);
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;
}
void handleDisconnected(const boost::optional<Connection::Error>& e) {
disconnected = true;
disconnectedError = e;
}
void handleDataRead(boost::shared_ptr<SafeByteArray> d) {
append(dataRead, *d);
}
struct MockConnection : public Connection {
public:
MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) {
}
void listen() { assert(false); }
void connect(const HostAddressPort& address) {
hostAddressPort = address;
bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end();
eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail));
}
HostAddressPort getLocalAddress() const { return HostAddressPort(); }
void disconnect() {
disconnected = true;
onDisconnected(boost::optional<Connection::Error>());
}
void write(const SafeByteArray& d) {
append(dataWritten, d);
}
EventLoop* eventLoop;
boost::optional<HostAddressPort> hostAddressPort;
std::vector<HostAddressPort> failingPorts;
ByteArray dataWritten;
bool disconnected;
};
struct MockConnectionFactory : public ConnectionFactory {
MockConnectionFactory(EventLoop* eventLoop) : eventLoop(eventLoop) {
}
boost::shared_ptr<Connection> createConnection() {
boost::shared_ptr<MockConnection> connection = boost::make_shared<MockConnection>(failingPorts, eventLoop);
connections.push_back(connection);
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
@@ -3,89 +3,90 @@
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swiften/Session/BOSHSessionStream.h>
#include <boost/bind.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/StreamType.h>
#include <Swiften/StreamStack/XMPPLayer.h>
#include <Swiften/StreamStack/StreamStack.h>
#include <Swiften/StreamStack/ConnectionLayer.h>
#include <Swiften/StreamStack/WhitespacePingLayer.h>
#include <Swiften/StreamStack/CompressionLayer.h>
#include <Swiften/StreamStack/TLSLayer.h>
#include <Swiften/TLS/TLSContextFactory.h>
#include <Swiften/TLS/TLSContext.h>
#include <Swiften/EventLoop/EventLoop.h>
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));
xmppLayer->onError.connect(boost::bind(&BOSHSessionStream::handleXMPPError, this));
xmppLayer->onWriteData.connect(boost::bind(&BOSHSessionStream::handleXMPPLayerDataWritten, this, _1));
available = true;
}
BOSHSessionStream::~BOSHSessionStream() {
close();
connectionPool->onSessionTerminated.disconnect(boost::bind(&BOSHSessionStream::handlePoolSessionTerminated, this, _1));
connectionPool->onSessionStarted.disconnect(boost::bind(&BOSHSessionStream::handlePoolSessionStarted, this));
connectionPool->onXMPPDataRead.disconnect(boost::bind(&BOSHSessionStream::handlePoolXMPPDataRead, this, _1));
connectionPool->onBOSHDataRead.disconnect(boost::bind(&BOSHSessionStream::handlePoolBOSHDataRead, this, _1));
connectionPool->onBOSHDataWritten.disconnect(boost::bind(&BOSHSessionStream::handlePoolBOSHDataWritten, this, _1));
delete connectionPool;
connectionPool = NULL;
xmppLayer->onStreamStart.disconnect(boost::bind(&BOSHSessionStream::handleStreamStartReceived, this, _1));
xmppLayer->onElement.disconnect(boost::bind(&BOSHSessionStream::handleElementReceived, this, _1));
xmppLayer->onError.disconnect(boost::bind(&BOSHSessionStream::handleXMPPError, this));
xmppLayer->onWriteData.disconnect(boost::bind(&BOSHSessionStream::handleXMPPLayerDataWritten, this, _1));
delete xmppLayer;
xmppLayer = NULL;
}
void BOSHSessionStream::handlePoolXMPPDataRead(const SafeByteArray& data) {
xmppLayer->handleDataRead(data);
}
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
@@ -6,70 +6,71 @@
#pragma once
#include <boost/shared_ptr.hpp>
#include <Swiften/Base/SafeString.h>
#include <Swiften/Base/SafeByteArray.h>
#include <Swiften/Network/BOSHConnectionPool.h>
#include <Swiften/Session/SessionStream.h>
#include <Swiften/Elements/StreamType.h>
#include <Swiften/EventLoop/EventOwner.h>
namespace Swift {
class TimerFactory;
class PayloadParserFactoryCollection;
class PayloadSerializerCollection;
class StreamStack;
class XMPPLayer;
class ConnectionLayer;
class CompressionLayer;
class XMLParserFactory;
class TLSContextFactory;
class EventLoop;
class BOSHSessionStream : public SessionStream, public EventOwner, public boost::enable_shared_from_this<BOSHSessionStream> {
public:
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();
virtual void writeHeader(const ProtocolHeader& header);
virtual void writeElement(boost::shared_ptr<Element>);
virtual void writeFooter();
virtual void writeData(const std::string& data);
virtual bool supportsZLibCompression();
virtual void addZLibCompression();
virtual bool supportsTLSEncryption();
virtual void addTLSEncryption();
virtual bool isTLSEncrypted();
virtual Certificate::ref getPeerCertificate() const;
virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
virtual ByteArray getTLSFinishMessage() const;
virtual void setWhitespacePingEnabled(bool);
virtual void resetXMPPParser();
private:
void handleXMPPError();
void handleStreamStartReceived(const ProtocolHeader&);
void handleElementReceived(boost::shared_ptr<Element>);
void handlePoolXMPPDataRead(const SafeByteArray& data);
void handleXMPPLayerDataWritten(const SafeByteArray& data);