diff options
author | Remko Tronçon <git@el-tramo.be> | 2012-06-02 16:40:22 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2012-06-17 07:34:57 (GMT) |
commit | f171bc207c2a7371ac6924ff467049dd0258aa00 (patch) | |
tree | eda5b5feb94dea264ea26b839b6f9ef5e32c915f /Swiften | |
parent | 5a1bdf2f6a4842176be5938f8db5cb9d151aceb5 (diff) | |
download | swift-f171bc207c2a7371ac6924ff467049dd0258aa00.zip swift-f171bc207c2a7371ac6924ff467049dd0258aa00.tar.bz2 |
Allow different connection methods for Client.
Diffstat (limited to 'Swiften')
27 files changed, 546 insertions, 360 deletions
diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h index fbec272..e5fcda9 100644 --- a/Swiften/Client/ClientOptions.h +++ b/Swiften/Client/ClientOptions.h @@ -17,7 +17,27 @@ namespace Swift { RequireTLS }; - ClientOptions() : useStreamCompression(true), useTLS(UseTLSWhenAvailable), allowPLAINWithoutTLS(false), useStreamResumption(false), forgetPassword(false), useAcks(true), boshHTTPConnectProxyAuthID(""), boshHTTPConnectProxyAuthPassword("") { + enum ProxyType { + NoProxy, + SystemConfiguredProxy, + SOCKS5Proxy, + HTTPConnectProxy + }; + + ClientOptions() : + useStreamCompression(true), + useTLS(UseTLSWhenAvailable), + allowPLAINWithoutTLS(false), + useStreamResumption(false), + forgetPassword(false), + useAcks(true), + manualHostname(""), + manualPort(-1), + proxyType(SystemConfiguredProxy), + manualProxyHostname(""), + manualProxyPort(-1), + boshHTTPConnectProxyAuthID(""), + boshHTTPConnectProxyAuthPassword("") { } /** @@ -66,6 +86,35 @@ namespace Swift { bool useAcks; /** + * The hostname to connect to. + * Leave this empty for standard XMPP connection, based on the JID domain. + */ + std::string manualHostname; + + /** + * The port to connect to. + * Leave this to -1 to use the port discovered by SRV lookups, and 5222 as a + * fallback. + */ + int manualPort; + + /** + * The type of proxy to use for connecting to the XMPP + * server. + */ + ProxyType proxyType; + + /** + * Override the system-configured proxy hostname. + */ + std::string manualProxyHostname; + + /** + * Override the system-configured proxy port. + */ + int manualProxyPort; + + /** * If non-empty, use BOSH instead of direct TCP, with the given URL. * Default: empty (no BOSH) */ diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index 36e27eb..64c0bab 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -54,27 +54,55 @@ CoreClient::~CoreClient() { 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_); + + options = o; + + + // Determine connection types to use 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->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), networkFactories->getEventLoop(), networkFactories->getProxyProvider()->getHTTPConnectProxy().getAddress().toString(), networkFactories->getProxyProvider()->getHTTPConnectProxy().getPort())); + bool useDirectConnection = true; + HostAddressPort systemSOCKS5Proxy = networkFactories->getProxyProvider()->getSOCKS5Proxy(); + HostAddressPort systemHTTPConnectProxy = networkFactories->getProxyProvider()->getHTTPConnectProxy(); + switch (o.proxyType) { + case ClientOptions::NoProxy: + break; + case ClientOptions::SystemConfiguredProxy: + if (systemSOCKS5Proxy.isValid()) { + proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), systemSOCKS5Proxy.getAddress().toString(), systemHTTPConnectProxy.getPort())); + } + if (systemHTTPConnectProxy.isValid()) { + proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), systemHTTPConnectProxy.getAddress().toString(), systemHTTPConnectProxy.getPort())); + } + break; + case ClientOptions::SOCKS5Proxy: { + std::string proxyHostname = o.manualProxyHostname.empty() ? systemSOCKS5Proxy.getAddress().toString() : o.manualProxyHostname; + int proxyPort = o.manualProxyPort == -1 ? systemSOCKS5Proxy.getPort() : o.manualProxyPort; + proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), proxyHostname, proxyPort)); + useDirectConnection = false; + break; + } + case ClientOptions::HTTPConnectProxy: { + std::string proxyHostname = o.manualProxyHostname.empty() ? systemSOCKS5Proxy.getAddress().toString() : o.manualProxyHostname; + int proxyPort = o.manualProxyPort == -1 ? systemSOCKS5Proxy.getPort() : o.manualProxyPort; + proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), proxyHostname, proxyPort)); + useDirectConnection = false; + break; + } } std::vector<ConnectionFactory*> connectionFactories(proxyConnectionFactories); - if (options.boshURL.empty()) { + if (useDirectConnection) { connectionFactories.push_back(networkFactories->getConnectionFactory()); - connector_ = boost::make_shared<ChainedConnector>(host, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); + } + + // Create connector + std::string host = o.manualHostname.empty() ? jid_.getDomain() : o.manualHostname; + int port = o.manualPort; + assert(!connector_); + if (options.boshURL.empty()) { + connector_ = boost::make_shared<ChainedConnector>(host, port, o.manualHostname.empty(), networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1, _2)); connector_->setTimeoutMilliseconds(60*1000); connector_->start(); diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h index 985bf7f..4bb04e2 100644 --- a/Swiften/Client/CoreClient.h +++ b/Swiften/Client/CoreClient.h @@ -74,8 +74,6 @@ namespace Swift { */ void disconnect(); - void connect(const std::string& host); - /** * Sends a message. */ diff --git a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp index c957481..636a52a 100644 --- a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp +++ b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp @@ -79,7 +79,9 @@ int main(int argc, char* argv[]) { std::cout << "Connecting to JID " << jid << " with timeout " << timeout << "ms on host: "; ; if (!connectHost.empty()) { std::cout << connectHost << std::endl; - client->connect(connectHost); + ClientOptions options; + options.manualHostname = connectHost; + client->connect(options); } else { std::cout << " Default" << std::endl; client->connect(); diff --git a/Swiften/Examples/SendMessage/SendMessage.cpp b/Swiften/Examples/SendMessage/SendMessage.cpp index f4dbf53..07e289e 100644 --- a/Swiften/Examples/SendMessage/SendMessage.cpp +++ b/Swiften/Examples/SendMessage/SendMessage.cpp @@ -69,7 +69,9 @@ int main(int argc, char* argv[]) { client->onConnected.connect(&handleConnected); errorConnection = client->onDisconnected.connect(&handleDisconnected); if (!connectHost.empty()) { - client->connect(connectHost); + ClientOptions options; + options.manualHostname = connectHost; + client->connect(options); } else { client->connect(); } diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp index bb24aa5..0adeb45 100644 --- a/Swiften/Network/BOSHConnectionPool.cpp +++ b/Swiften/Network/BOSHConnectionPool.cpp @@ -35,7 +35,7 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory); myConnectionFactories.push_back(connectionFactory); } - connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, eventLoop, boshHTTPConnectProxyURL.getHost(), boshHTTPConnectProxyURL.getPort(), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); + connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, boshHTTPConnectProxyURL.getHost(), boshHTTPConnectProxyURL.getPort(), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); } if (boshURL.getScheme() == "https") { connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory); @@ -211,7 +211,7 @@ void BOSHConnectionPool::handleConnectionDisconnected(bool error, BOSHConnection } boost::shared_ptr<BOSHConnection> BOSHConnectionPool::createConnection() { - Connector::ref connector = Connector::create(boshURL.getHost(), resolver, connectionFactory, timerFactory, boshURL.getPort()); + Connector::ref connector = Connector::create(boshURL.getHost(), boshURL.getPort(), false, resolver, connectionFactory, timerFactory); 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)); diff --git a/Swiften/Network/ChainedConnector.cpp b/Swiften/Network/ChainedConnector.cpp index 0a1283f..8c7c04b 100644 --- a/Swiften/Network/ChainedConnector.cpp +++ b/Swiften/Network/ChainedConnector.cpp @@ -18,10 +18,14 @@ using namespace Swift; ChainedConnector::ChainedConnector( const std::string& hostname, + int port, + bool doServiceLookups, DomainNameResolver* resolver, const std::vector<ConnectionFactory*>& connectionFactories, TimerFactory* timerFactory) : hostname(hostname), + port(port), + doServiceLookups(doServiceLookups), resolver(resolver), connectionFactories(connectionFactories), timerFactory(timerFactory), @@ -58,7 +62,7 @@ void ChainedConnector::tryNextConnectionFactory() { ConnectionFactory* connectionFactory = connectionFactoryQueue.front(); SWIFT_LOG(debug) << "Trying next connection factory: " << typeid(*connectionFactory).name() << std::endl; connectionFactoryQueue.pop_front(); - currentConnector = Connector::create(hostname, resolver, connectionFactory, timerFactory); + currentConnector = Connector::create(hostname, port, doServiceLookups, resolver, connectionFactory, timerFactory); currentConnector->setTimeoutMilliseconds(timeoutMilliseconds); currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); currentConnector->start(); diff --git a/Swiften/Network/ChainedConnector.h b/Swiften/Network/ChainedConnector.h index 12ef023..60aea05 100644 --- a/Swiften/Network/ChainedConnector.h +++ b/Swiften/Network/ChainedConnector.h @@ -23,7 +23,7 @@ namespace Swift { class ChainedConnector { public: - ChainedConnector(const std::string& hostname, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); + ChainedConnector(const std::string& hostname, int port, bool doServiceLookups, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); void setTimeoutMilliseconds(int milliseconds); void start(); @@ -38,6 +38,8 @@ namespace Swift { private: std::string hostname; + int port; + bool doServiceLookups; DomainNameResolver* resolver; std::vector<ConnectionFactory*> connectionFactories; TimerFactory* timerFactory; diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp index 5e7f8d9..02ebb02 100644 --- a/Swiften/Network/Connector.cpp +++ b/Swiften/Network/Connector.cpp @@ -17,7 +17,7 @@ namespace Swift { -Connector::Connector(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, int defaultPort) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), defaultPort(defaultPort), timeoutMilliseconds(0), queriedAllServices(true), foundSomeDNS(false) { +Connector::Connector(const std::string& hostname, int port, bool doServiceLookups, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), port(port), doServiceLookups(doServiceLookups), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0), queriedAllServices(true), foundSomeDNS(false) { } void Connector::setTimeoutMilliseconds(int milliseconds) { @@ -31,14 +31,19 @@ void Connector::start() { 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(); + if (doServiceLookups) { + 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(); + } + else { + queryAddress(hostname); + } } void Connector::stop() { @@ -109,12 +114,12 @@ void Connector::tryNextAddress() { HostAddress address = addressQueryResults.front(); addressQueryResults.pop_front(); - int port = defaultPort; + int connectPort = (port == -1 ? 5222 : port); if (!serviceQueryResults.empty()) { - port = serviceQueryResults.front().port; + connectPort = serviceQueryResults.front().port; } - tryConnect(HostAddressPort(address, port)); + tryConnect(HostAddressPort(address, connectPort)); } } diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h index bf0efaf..e3fd51f 100644 --- a/Swiften/Network/Connector.h +++ b/Swiften/Network/Connector.h @@ -27,8 +27,8 @@ namespace Swift { public: typedef boost::shared_ptr<Connector> ref; - 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)); + static Connector::ref create(const std::string& hostname, int port, bool doServiceLookups, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { + return ref(new Connector(hostname, port, doServiceLookups, resolver, connectionFactory, timerFactory)); } void setTimeoutMilliseconds(int milliseconds); @@ -38,7 +38,7 @@ namespace Swift { boost::signal<void (boost::shared_ptr<Connection>, boost::shared_ptr<Error>)> onConnectFinished; private: - Connector(const std::string& hostname, DomainNameResolver*, ConnectionFactory*, TimerFactory*, int defaultPort); + Connector(const std::string& hostname, int port, bool doServiceLookups, DomainNameResolver*, ConnectionFactory*, TimerFactory*); void handleServiceQueryResult(const std::vector<DomainNameServiceQuery::Result>& result); void handleAddressQueryResult(const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> error); @@ -55,10 +55,11 @@ namespace Swift { private: std::string hostname; + int port; + bool doServiceLookups; DomainNameResolver* resolver; ConnectionFactory* connectionFactory; TimerFactory* timerFactory; - int defaultPort; int timeoutMilliseconds; boost::shared_ptr<Timer> timer; boost::shared_ptr<DomainNameServiceQuery> serviceQuery; diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp index 512381f..7bd7e41 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -15,7 +15,6 @@ #include <iostream> #include <boost/bind.hpp> -#include <boost/thread.hpp> #include <boost/lexical_cast.hpp> #include <Swiften/Base/Algorithm.h> @@ -24,111 +23,52 @@ #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(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( + DomainNameResolver* resolver, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + const std::string& proxyHost, + int proxyPort, + const SafeString& authID, + const SafeString& authPassword) : + ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort), + authID_(authID), + authPassword_(authPassword) { } -HTTPConnectProxiedConnection::~HTTPConnectProxiedConnection() { - cancelConnector(); - delete resolver_; - if (connection_) { - 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; - 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::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")); - } +void HTTPConnectProxiedConnection::initializeProxy() { + std::stringstream connect; + connect << "CONNECT " << getServer().getAddress().toString() << ":" << getServer().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")); - SWIFT_LOG(debug) << "HTTP Proxy send headers: " << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl; - connection_->write(data); - } - else { - onConnectFinished(true); } + append(data, createSafeByteArray("\r\n")); + SWIFT_LOG(debug) << "HTTP Proxy send headers: " << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl; + write(data); } -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; +void HTTPConnectProxiedConnection::handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data) { + 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 + setProxyInitializeFinished(true); + return; } - disconnect(); - onConnectFinished(true); - } - else { - onDataRead(data); + SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl; } -} - -HostAddressPort HTTPConnectProxiedConnection::getLocalAddress() const { - return connection_->getLocalAddress(); + setProxyInitializeFinished(false); } diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h index 8318ecc..e6c8629 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.h +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -13,59 +13,30 @@ #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; - } -} +#include <Swiften/Network/ProxiedConnection.h> namespace Swift { + class DomainNameResolver; class ConnectionFactory; class EventLoop; + class TimerFactory; - class HTTPConnectProxiedConnection : public Connection, public boost::enable_shared_from_this<HTTPConnectProxiedConnection> { + class HTTPConnectProxiedConnection : public ProxiedConnection { public: typedef boost::shared_ptr<HTTPConnectProxiedConnection> ref; - ~HTTPConnectProxiedConnection(); - - 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)); + static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) { + return ref(new HTTPConnectProxiedConnection(resolver, connectionFactory, timerFactory, 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(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); + HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); - void handleConnectFinished(Connection::ref connection); - void handleDataRead(boost::shared_ptr<SafeByteArray> data); - void handleDisconnected(const boost::optional<Error>& error); - void cancelConnector(); + virtual void initializeProxy(); + virtual void handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data); private: - bool connected_; - DomainNameResolver* resolver_; - ConnectionFactory* connectionFactory_; - 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 14d702c..cf4cef5 100644 --- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp @@ -16,15 +16,15 @@ namespace Swift { -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(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(""), 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) { +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(authID), authPassword_(authPassword) { } boost::shared_ptr<Connection> HTTPConnectProxiedConnectionFactory::createConnection() { - return HTTPConnectProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, eventLoop_, proxyHost_, proxyPort_, authID_, authPassword_); + return HTTPConnectProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, proxyHost_, proxyPort_, authID_, authPassword_); } } diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h index 7d003e8..3efcecd 100644 --- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h @@ -22,8 +22,8 @@ namespace Swift { class EventLoop; class HTTPConnectProxiedConnectionFactory : public ConnectionFactory { public: - 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); + HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); + HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); virtual boost::shared_ptr<Connection> createConnection(); @@ -31,7 +31,6 @@ namespace Swift { DomainNameResolver* resolver_; ConnectionFactory* connectionFactory_; TimerFactory* timerFactory_; - EventLoop* eventLoop_; std::string proxyHost_; int proxyPort_; SafeString authID_; diff --git a/Swiften/Network/HostNameOrAddress.cpp b/Swiften/Network/HostNameOrAddress.cpp new file mode 100644 index 0000000..bc2737d --- /dev/null +++ b/Swiften/Network/HostNameOrAddress.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/HostNameOrAddress.h> + +using namespace Swift; + +namespace { + struct ToStringVisitor : public boost::static_visitor<std::string> { + std::string operator()(const HostAddress& address) const { + return address.toString(); + } + + std::string operator()(const std::string & str) const { + return str; + } + }; +} + +namespace Swift { + +std::string toString(const HostNameOrAddress& address) { + return boost::apply_visitor(ToStringVisitor(), address); +} + +} diff --git a/Swiften/Network/HostNameOrAddress.h b/Swiften/Network/HostNameOrAddress.h new file mode 100644 index 0000000..f804d15 --- /dev/null +++ b/Swiften/Network/HostNameOrAddress.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ +#pragma once + +#include <string> +#include <Swiften/Network/HostAddress.h> +#include <boost/variant.hpp> + +namespace Swift { + typedef boost::variant<std::string, HostAddress> HostNameOrAddress; + + std::string toString(const HostNameOrAddress& address); +} diff --git a/Swiften/Network/ProxiedConnection.cpp b/Swiften/Network/ProxiedConnection.cpp new file mode 100644 index 0000000..8bf12d3 --- /dev/null +++ b/Swiften/Network/ProxiedConnection.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#include <Swiften/Network/ProxiedConnection.h> + +#include <iostream> +#include <boost/bind.hpp> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/ConnectionFactory.h> + +using namespace Swift; + +ProxiedConnection::ProxiedConnection( + DomainNameResolver* resolver, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + const std::string& proxyHost, + int proxyPort) : + resolver_(resolver), + connectionFactory_(connectionFactory), + timerFactory_(timerFactory), + proxyHost_(proxyHost), + proxyPort_(proxyPort), + server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) { + connected_ = false; +} + +ProxiedConnection::~ProxiedConnection() { + cancelConnector(); + if (connection_) { + connection_->onDataRead.disconnect(boost::bind(&ProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.disconnect(boost::bind(&ProxiedConnection::handleDisconnected, shared_from_this(), _1)); + } + if (connected_) { + std::cerr << "Warning: Connection was still established." << std::endl; + } +} + +void ProxiedConnection::cancelConnector() { + if (connector_) { + connector_->onConnectFinished.disconnect(boost::bind(&ProxiedConnection::handleConnectFinished, shared_from_this(), _1)); + connector_->stop(); + connector_.reset(); + } +} + +void ProxiedConnection::connect(const HostAddressPort& server) { + server_ = server; + + connector_ = Connector::create(proxyHost_, proxyPort_, false, resolver_, connectionFactory_, timerFactory_); + connector_->onConnectFinished.connect(boost::bind(&ProxiedConnection::handleConnectFinished, shared_from_this(), _1)); + connector_->start(); +} + +void ProxiedConnection::listen() { + assert(false); + connection_->listen(); +} + +void ProxiedConnection::disconnect() { + connected_ = false; + connection_->disconnect(); +} + +void ProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { + onDisconnected(error); +} + +void ProxiedConnection::write(const SafeByteArray& data) { + connection_->write(data); +} + +void ProxiedConnection::handleConnectFinished(Connection::ref connection) { + cancelConnector(); + if (connection) { + connection_ = connection; + connection_->onDataRead.connect(boost::bind(&ProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&ProxiedConnection::handleDisconnected, shared_from_this(), _1)); + + initializeProxy(); + } + else { + onConnectFinished(true); + } +} + +void ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { + if (!connected_) { + handleProxyInitializeData(data); + } + else { + onDataRead(data); + } +} + +HostAddressPort ProxiedConnection::getLocalAddress() const { + return connection_->getLocalAddress(); +} + +void ProxiedConnection::setProxyInitializeFinished(bool success) { + connected_ = success; + if (!success) { + disconnect(); + } + onConnectFinished(!success); +} diff --git a/Swiften/Network/ProxiedConnection.h b/Swiften/Network/ProxiedConnection.h new file mode 100644 index 0000000..aa8df38 --- /dev/null +++ b/Swiften/Network/ProxiedConnection.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * 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 ProxiedConnection : public Connection, public boost::enable_shared_from_this<ProxiedConnection> { + public: + ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); + ~ProxiedConnection(); + + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const SafeByteArray& data); + + virtual HostAddressPort getLocalAddress() const; + + private: + void handleConnectFinished(Connection::ref connection); + void handleDataRead(boost::shared_ptr<SafeByteArray> data); + void handleDisconnected(const boost::optional<Error>& error); + void cancelConnector(); + + protected: + void setProxyInitializeFinished(bool success); + + virtual void initializeProxy() = 0; + virtual void handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data) = 0; + + const HostAddressPort& getServer() const { + return server_; + } + + private: + bool connected_; + DomainNameResolver* resolver_; + ConnectionFactory* connectionFactory_; + TimerFactory* timerFactory_; + std::string proxyHost_; + int proxyPort_; + HostAddressPort server_; + Connector::ref connector_; + boost::shared_ptr<Connection> connection_; + }; +} + diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index 54565b4..ea45149 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -3,6 +3,7 @@ Import("swiften_env") myenv = swiften_env.Clone() sourceList = [ + "ProxiedConnection.cpp", "HTTPConnectProxiedConnection.cpp", "HTTPConnectProxiedConnectionFactory.cpp", "SOCKS5ProxiedConnection.cpp", @@ -35,6 +36,7 @@ sourceList = [ "StaticDomainNameResolver.cpp", "HostAddress.cpp", "HostAddressPort.cpp", + "HostNameOrAddress.cpp", "NetworkFactories.cpp", "BoostNetworkFactories.cpp", "NetworkEnvironment.cpp", diff --git a/Swiften/Network/SOCKS5ProxiedConnection.cpp b/Swiften/Network/SOCKS5ProxiedConnection.cpp index 163e23a..bf7a056 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.cpp +++ b/Swiften/Network/SOCKS5ProxiedConnection.cpp @@ -18,157 +18,98 @@ using namespace Swift; -SOCKS5ProxiedConnection::SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) { - connected_ = false; -} - -SOCKS5ProxiedConnection::~SOCKS5ProxiedConnection() { - if (connection_) { - connection_->onDataRead.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleDataRead, shared_from_this(), _1)); - connection_->onDisconnected.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleDisconnected, shared_from_this(), _1)); - } - - if (connected_) { - std::cerr << "Warning: Connection was still established." << std::endl; - } -} - -void SOCKS5ProxiedConnection::connect(const HostAddressPort& server) { - server_ = server; - connection_ = connectionFactory_->createConnection(); - connection_->onConnectFinished.connect(boost::bind(&SOCKS5ProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); - connection_->onDataRead.connect(boost::bind(&SOCKS5ProxiedConnection::handleDataRead, shared_from_this(), _1)); - connection_->onDisconnected.connect(boost::bind(&SOCKS5ProxiedConnection::handleDisconnected, shared_from_this(), _1)); - SWIFT_LOG(debug) << "Trying to connect via proxy " << proxy_.getAddress().toString() << ":" << proxy_.getPort() << std::endl; - SWIFT_LOG(debug) << "to server " << server.getAddress().toString() << ":" << server.getPort() << std::endl; - connection_->connect(proxy_); -} - -void SOCKS5ProxiedConnection::listen() { - assert(false); - connection_->listen(); -} - -void SOCKS5ProxiedConnection::disconnect() { - connected_ = false; - if (connection_) { - connection_->disconnect(); - } -} - -void SOCKS5ProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { - onDisconnected(error); -} - -void SOCKS5ProxiedConnection::write(const SafeByteArray& data) { - if (connection_) { - connection_->write(data); - } -} +SOCKS5ProxiedConnection::SOCKS5ProxiedConnection( + DomainNameResolver* resolver, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + const std::string& proxyHost, + int proxyPort) : + ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort) { + } -void SOCKS5ProxiedConnection::handleConnectionConnectFinished(bool error) { - connection_->onConnectFinished.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); - if (!error) { - SWIFT_LOG(debug) << "Connection to proxy established, now connect to the server via it." << std::endl; - - proxyState_ = ProxyAuthenticating; - SafeByteArray socksConnect; - socksConnect.push_back(0x05); // VER = SOCKS5 = 0x05 - socksConnect.push_back(0x01); // Number of authentication methods after this byte. - socksConnect.push_back(0x00); // 0x00 == no authentication - // buffer.push_back(0x01); // 0x01 == GSSAPI - // buffer.push_back(0x02); // 0x02 == Username/Password - // rest see RFC 1928 (http://tools.ietf.org/html/rfc1928) - connection_->write(socksConnect); - } - else { - onConnectFinished(true); - } +void SOCKS5ProxiedConnection::initializeProxy() { + proxyState_ = ProxyAuthenticating; + SafeByteArray socksConnect; + socksConnect.push_back(0x05); // VER = SOCKS5 = 0x05 + socksConnect.push_back(0x01); // Number of authentication methods after this byte. + socksConnect.push_back(0x00); // 0x00 == no authentication + // buffer.push_back(0x01); // 0x01 == GSSAPI + // buffer.push_back(0x02); // 0x02 == Username/Password + // rest see RFC 1928 (http://tools.ietf.org/html/rfc1928) + write(socksConnect); } -void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { +void SOCKS5ProxiedConnection::handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data) { SafeByteArray socksConnect; - boost::asio::ip::address rawAddress = server_.getAddress().getRawAddress(); + boost::asio::ip::address rawAddress = getServer().getAddress().getRawAddress(); assert(rawAddress.is_v4() || rawAddress.is_v6()); - if (!connected_) { - if (proxyState_ == ProxyAuthenticating) { - SWIFT_LOG(debug) << "ProxyAuthenticating response received, reply with the connect BYTEs" << std::endl; - unsigned char choosenMethod = static_cast<unsigned char> ((*data)[1]); - if ((*data)[0] == 0x05 && choosenMethod != 0xFF) { - switch(choosenMethod) { // use the correct Method - case 0x00: - try { - proxyState_ = ProxyConnecting; - socksConnect.push_back(0x05); // VER = SOCKS5 = 0x05 - socksConnect.push_back(0x01); // Construct a TCP connection. (CMD) - socksConnect.push_back(0x00); // reserved. - socksConnect.push_back(rawAddress.is_v4() ? 0x01 : 0x04); // IPv4 == 0x01, Hostname == 0x02, IPv6 == 0x04. (ATYP) - size_t size = rawAddress.is_v4() ? rawAddress.to_v4().to_bytes().size() : rawAddress.to_v6().to_bytes().size(); - for (size_t s = 0; s < size; s++) { - unsigned char uc; - if(rawAddress.is_v4()) { - uc = rawAddress.to_v4().to_bytes()[s]; // the address. - } - else { - uc = rawAddress.to_v6().to_bytes()[s]; // the address. - } - socksConnect.push_back(static_cast<char>(uc)); - + + if (proxyState_ == ProxyAuthenticating) { + SWIFT_LOG(debug) << "ProxyAuthenticating response received, reply with the connect BYTEs" << std::endl; + unsigned char choosenMethod = static_cast<unsigned char> ((*data)[1]); + if ((*data)[0] == 0x05 && choosenMethod != 0xFF) { + switch(choosenMethod) { // use the correct Method + case 0x00: + try { + proxyState_ = ProxyConnecting; + socksConnect.push_back(0x05); // VER = SOCKS5 = 0x05 + socksConnect.push_back(0x01); // Construct a TCP connection. (CMD) + socksConnect.push_back(0x00); // reserved. + socksConnect.push_back(rawAddress.is_v4() ? 0x01 : 0x04); // IPv4 == 0x01, Hostname == 0x02, IPv6 == 0x04. (ATYP) + size_t size = rawAddress.is_v4() ? rawAddress.to_v4().to_bytes().size() : rawAddress.to_v6().to_bytes().size(); + for (size_t s = 0; s < size; s++) { + unsigned char uc; + if(rawAddress.is_v4()) { + uc = rawAddress.to_v4().to_bytes()[s]; // the address. } - socksConnect.push_back(static_cast<unsigned char> ((server_.getPort() >> 8) & 0xFF)); // highbyte of the port. - socksConnect.push_back(static_cast<unsigned char> (server_.getPort() & 0xFF)); // lowbyte of the port. - connection_->write(socksConnect); - return; - } - catch(...) { - std::cerr << "exception caught" << std::endl; + else { + uc = rawAddress.to_v6().to_bytes()[s]; // the address. + } + socksConnect.push_back(static_cast<char>(uc)); + } - connection_->write(socksConnect); - break; - default: - onConnectFinished(true); - break; - } - return; - } - } - else if (proxyState_ == ProxyConnecting) { - SWIFT_LOG(debug) << "Connect response received, check if successfully." << std::endl; - SWIFT_LOG(debug) << "Errorbyte: 0x" << std::hex << static_cast<int> ((*data)[1]) << std::dec << std::endl; - /* - - data.at(1) can be one of the following: - 0x00 succeeded - 0x01 general SOCKS server failure - 0x02 connection not allowed by ruleset - 0x03 Network unreachable - 0x04 Host unreachable - 0x05 Connection refused - 0x06 TTL expired - 0x07 Command not supported (CMD) - 0x08 Address type not supported (ATYP) - 0x09 bis 0xFF unassigned - */ - if ((*data)[0] == 0x05 && (*data)[1] == 0x0) { - SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl; - connected_ = true; - onConnectFinished(false); - return; - } - else { - std::cerr << "SOCKS Proxy returned an error: " << std::hex << (*data)[1] << std::endl; + socksConnect.push_back(static_cast<unsigned char> ((getServer().getPort() >> 8) & 0xFF)); // highbyte of the port. + socksConnect.push_back(static_cast<unsigned char> (getServer().getPort() & 0xFF)); // lowbyte of the port. + write(socksConnect); + return; + } + catch(...) { + std::cerr << "exception caught" << std::endl; + } + write(socksConnect); + break; + default: + setProxyInitializeFinished(true); + break; } return; } + setProxyInitializeFinished(false); } - else { - onDataRead(data); - return; + else if (proxyState_ == ProxyConnecting) { + SWIFT_LOG(debug) << "Connect response received, check if successfully." << std::endl; + SWIFT_LOG(debug) << "Errorbyte: 0x" << std::hex << static_cast<int> ((*data)[1]) << std::dec << std::endl; + /* + + data.at(1) can be one of the following: + 0x00 succeeded + 0x01 general SOCKS server failure + 0x02 connection not allowed by ruleset + 0x03 Network unreachable + 0x04 Host unreachable + 0x05 Connection refused + 0x06 TTL expired + 0x07 Command not supported (CMD) + 0x08 Address type not supported (ATYP) + 0x09 bis 0xFF unassigned + */ + if ((*data)[0] == 0x05 && (*data)[1] == 0x0) { + SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl; + setProxyInitializeFinished(true); + } + else { + std::cerr << "SOCKS Proxy returned an error: " << std::hex << (*data)[1] << std::endl; + setProxyInitializeFinished(false); + } } - disconnect(); - onConnectFinished(true); -} - -HostAddressPort SOCKS5ProxiedConnection::getLocalAddress() const { - return connection_->getLocalAddress(); } diff --git a/Swiften/Network/SOCKS5ProxiedConnection.h b/Swiften/Network/SOCKS5ProxiedConnection.h index 592ce7d..61092e0 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.h +++ b/Swiften/Network/SOCKS5ProxiedConnection.h @@ -6,54 +6,31 @@ #pragma once -#include <boost/enable_shared_from_this.hpp> - -#include <Swiften/Network/Connection.h> -#include <Swiften/Network/HostAddressPort.h> - -namespace boost { - class thread; - namespace system { - class error_code; - } -} +#include <Swiften/Network/ProxiedConnection.h> namespace Swift { class ConnectionFactory; + class DomainNameResolver; + class TimerFactory; - class SOCKS5ProxiedConnection : public Connection, public boost::enable_shared_from_this<SOCKS5ProxiedConnection> { + class SOCKS5ProxiedConnection : public ProxiedConnection { public: typedef boost::shared_ptr<SOCKS5ProxiedConnection> ref; - ~SOCKS5ProxiedConnection(); - - static ref create(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) { - return ref(new SOCKS5ProxiedConnection(connectionFactory, proxy)); + static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) { + return ref(new SOCKS5ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort)); } - virtual void listen(); - virtual void connect(const HostAddressPort& address); - virtual void disconnect(); - virtual void write(const SafeByteArray& data); - - virtual HostAddressPort getLocalAddress() const; - private: - SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + SOCKS5ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); - void handleConnectionConnectFinished(bool error); - void handleDataRead(boost::shared_ptr<SafeByteArray> data); - void handleDisconnected(const boost::optional<Error>& error); + virtual void initializeProxy(); + virtual void handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data); private: enum { ProxyAuthenticating = 0, ProxyConnecting, } proxyState_; - bool connected_; - ConnectionFactory* connectionFactory_; - HostAddressPort proxy_; - HostAddressPort server_; - boost::shared_ptr<Connection> connection_; }; } diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp index 272ade9..af99034 100644 --- a/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp @@ -10,11 +10,11 @@ namespace Swift { -SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy) { +SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort) { } boost::shared_ptr<Connection> SOCKS5ProxiedConnectionFactory::createConnection() { - return SOCKS5ProxiedConnection::create(connectionFactory_, proxy_); + return SOCKS5ProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, proxyHost_, proxyPort_); } } diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h index f36d42a..4c5c585 100644 --- a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h @@ -8,16 +8,23 @@ #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/HostNameOrAddress.h> namespace Swift { + class DomainNameResolver; + class TimerFactory; + class SOCKS5ProxiedConnectionFactory : public ConnectionFactory { public: - SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + SOCKS5ProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); virtual boost::shared_ptr<Connection> createConnection(); private: + DomainNameResolver* resolver_; ConnectionFactory* connectionFactory_; - HostAddressPort proxy_; + TimerFactory* timerFactory_; + std::string proxyHost_; + int proxyPort_; }; } diff --git a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp index e0dc0bf..31aed1b 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp @@ -192,7 +192,7 @@ class BOSHConnectionTest : public CppUnit::TestFixture { BOSHConnection::ref createTestling() { resolver->addAddress("wonderland.lit", HostAddress("127.0.0.1")); - Connector::ref connector = Connector::create("wonderland.lit", resolver, connectionFactory, timerFactory, 5280); + Connector::ref connector = Connector::create("wonderland.lit", 5280, false, resolver, connectionFactory, timerFactory); 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)); diff --git a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp index a2fceb9..9abed57 100644 --- a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp @@ -126,7 +126,7 @@ class ChainedConnectorTest : public CppUnit::TestFixture { std::vector<ConnectionFactory*> factories; factories.push_back(connectionFactory1); factories.push_back(connectionFactory2); - boost::shared_ptr<ChainedConnector> connector = boost::make_shared<ChainedConnector>("foo.com", resolver, factories, timerFactory); + boost::shared_ptr<ChainedConnector> connector = boost::make_shared<ChainedConnector>("foo.com", -1, true, resolver, factories, timerFactory); connector->onConnectFinished.connect(boost::bind(&ChainedConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; } diff --git a/Swiften/Network/UnitTest/ConnectorTest.cpp b/Swiften/Network/UnitTest/ConnectorTest.cpp index 67270be..2d96bda 100644 --- a/Swiften/Network/UnitTest/ConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ConnectorTest.cpp @@ -24,6 +24,8 @@ using namespace Swift; class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ConnectorTest); CPPUNIT_TEST(testConnect); + CPPUNIT_TEST(testConnect_NoServiceLookups); + CPPUNIT_TEST(testConnect_NoServiceLookups_DefaultPort); CPPUNIT_TEST(testConnect_FirstAddressHostFails); CPPUNIT_TEST(testConnect_NoSRVHost); CPPUNIT_TEST(testConnect_NoHosts); @@ -71,6 +73,38 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } + void testConnect_NoServiceLookups() { + Connector::ref testling(createConnector(4321, false)); + resolver->addXMPPClientService("foo.com", host1); + resolver->addXMPPClientService("foo.com", host2); + resolver->addAddress("foo.com", host3.getAddress()); + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(host3.getAddress() == (*(connections[0]->hostAddressPort)).getAddress()); + CPPUNIT_ASSERT(4321 == (*(connections[0]->hostAddressPort)).getPort()); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); + } + + void testConnect_NoServiceLookups_DefaultPort() { + Connector::ref testling(createConnector(-1, false)); + resolver->addXMPPClientService("foo.com", host1); + resolver->addXMPPClientService("foo.com", host2); + resolver->addAddress("foo.com", host3.getAddress()); + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(host3.getAddress() == (*(connections[0]->hostAddressPort)).getAddress()); + CPPUNIT_ASSERT_EQUAL(5222, (*(connections[0]->hostAddressPort)).getPort()); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); + } + void testConnect_NoSRVHost() { Connector::ref testling(createConnector()); resolver->addAddress("foo.com", host3.getAddress()); @@ -253,8 +287,8 @@ class ConnectorTest : public CppUnit::TestFixture { private: - Connector::ref createConnector() { - Connector::ref connector = Connector::create("foo.com", resolver, connectionFactory, timerFactory); + Connector::ref createConnector(int port = -1, bool doServiceLookups = true) { + Connector::ref connector = Connector::create("foo.com", port, doServiceLookups, resolver, connectionFactory, timerFactory); connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; } diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp index 347a145..134748f 100644 --- a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp +++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp @@ -170,7 +170,7 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { private: HTTPConnectProxiedConnection::ref createTestling() { - boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(resolver, connectionFactory, timerFactory, eventLoop, proxyHost, proxyPort, "", ""); + boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(resolver, connectionFactory, timerFactory, 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)); |