diff options
Diffstat (limited to 'Swiften/Network')
84 files changed, 1598 insertions, 527 deletions
diff --git a/Swiften/Network/BOSHConnection.cpp b/Swiften/Network/BOSHConnection.cpp index 73f8ed6..28e27d5 100644 --- a/Swiften/Network/BOSHConnection.cpp +++ b/Swiften/Network/BOSHConnection.cpp @@ -6,5 +6,5 @@ /* - * Copyright (c) 2011 Kevin Smith + * Copyright (c) 2011-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -33,4 +33,5 @@ BOSHConnection::BOSHConnection(const URL& boshURL, Connector::ref connector, XML sid_(), waitingForStartResponse_(false), + rid_(~0ULL), pending_(false), connectionReady_(false) @@ -61,9 +62,12 @@ void BOSHConnection::cancelConnector() { void BOSHConnection::disconnect() { - cancelConnector(); if (connection_) { connection_->disconnect(); sid_ = ""; } + else { + /* handleDisconnected takes care of the connector_ as well */ + handleDisconnected(boost::optional<Connection::Error>()); + } } @@ -102,7 +106,11 @@ std::pair<SafeByteArray, size_t> BOSHConnection::createHTTPRequest(const SafeByt size = safeContent.size(); - header << "POST /" << boshURL.getPath() << " HTTP/1.1\r\n" - << "Host: " << boshURL.getHost() << ":" << boshURL.getPort() << "\r\n" - /*<< "Accept-Encoding: deflate\r\n"*/ + header << "POST " << boshURL.getPath() << " HTTP/1.1\r\n" + << "Host: " << boshURL.getHost(); + if (boshURL.getPort()) { + header << ":" << *boshURL.getPort(); + } + header << "\r\n" + // << "Accept-Encoding: deflate\r\n" << "Content-Type: text/xml; charset=utf-8\r\n" << "Content-Length: " << size << "\r\n\r\n"; @@ -129,5 +137,5 @@ void BOSHConnection::write(const SafeByteArray& data, bool streamRestart, bool t void BOSHConnection::handleConnectFinished(Connection::ref connection) { cancelConnector(); - connectionReady_ = connection; + connectionReady_ = !!connection; if (connectionReady_) { connection_ = connection; @@ -150,5 +158,5 @@ void BOSHConnection::startStream(const std::string& to, unsigned long long rid) << " ver='1.6'" << " wait='60'" /* FIXME: we probably want this configurable*/ - /*<< " ack='0'" FIXME: support acks */ + // << " ack='0'" FIXME: support acks << " xml:lang='en'" << " xmlns:xmpp='urn:xmpp:bosh'" @@ -158,7 +166,11 @@ void BOSHConnection::startStream(const std::string& to, unsigned long long rid) 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"*/ + header << "POST " << boshURL_.getPath() << " HTTP/1.1\r\n" + << "Host: " << boshURL_.getHost(); + if (boshURL_.getPort()) { + header << ":" << *boshURL_.getPort(); + } + header << "\r\n" + // << "Accept-Encoding: deflate\r\n" << "Content-Type: text/xml; charset=utf-8\r\n" << "Content-Length: " << contentString.size() << "\r\n\r\n" @@ -198,5 +210,5 @@ void BOSHConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { sid_ = parser.getBody()->attributes.getAttribute("sid"); std::string requestsString = parser.getBody()->attributes.getAttribute("requests"); - int requests = 2; + size_t requests = 2; if (!requestsString.empty()) { try { @@ -274,5 +286,5 @@ void BOSHConnection::setSID(const std::string& sid) { void BOSHConnection::handleDisconnected(const boost::optional<Connection::Error>& error) { cancelConnector(); - onDisconnected(error); + onDisconnected(error ? true : false); sid_ = ""; connectionReady_ = false; diff --git a/Swiften/Network/BOSHConnection.h b/Swiften/Network/BOSHConnection.h index a2abfcd..01341cc 100644 --- a/Swiften/Network/BOSHConnection.h +++ b/Swiften/Network/BOSHConnection.h @@ -16,4 +16,5 @@ #include <boost/enable_shared_from_this.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/Connector.h> @@ -37,5 +38,5 @@ namespace Swift { class TLSContextFactory; - class BOSHError : public SessionStream::SessionStreamError { + class SWIFTEN_API BOSHError : public SessionStream::SessionStreamError { public: enum Type {BadRequest, HostGone, HostUnknown, ImproperAddressing, @@ -52,5 +53,5 @@ namespace Swift { - class BOSHConnection : public boost::enable_shared_from_this<BOSHConnection> { + class SWIFTEN_API BOSHConnection : public boost::enable_shared_from_this<BOSHConnection> { public: typedef boost::shared_ptr<BOSHConnection> ref; diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp index bb24aa5..fdfe420 100644 --- a/Swiften/Network/BOSHConnectionPool.cpp +++ b/Swiften/Network/BOSHConnectionPool.cpp @@ -15,5 +15,5 @@ #include <Swiften/Network/TLSConnectionFactory.h> #include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> -#include <Swiften/Network/CachingNameOnlyDomainNameResolver.h> +#include <Swiften/Network/CachingDomainNameResolver.h> namespace Swift { @@ -22,5 +22,4 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r connectionFactory(connectionFactoryParameter), xmlParserFactory(parserFactory), - tlsFactory(tlsFactory), timerFactory(timerFactory), rid(initialRID), @@ -31,10 +30,10 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r pendingRestart(false) { - if (!boshHTTPConnectProxyURL.empty()) { + if (!boshHTTPConnectProxyURL.isEmpty()) { if (boshHTTPConnectProxyURL.getScheme() == "https") { 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(), URL::getPortOrDefaultPort(boshHTTPConnectProxyURL), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); } if (boshURL.getScheme() == "https") { @@ -42,10 +41,17 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r myConnectionFactories.push_back(connectionFactory); } - resolver = new CachingNameOnlyDomainNameResolver(realResolver, eventLoop); + resolver = new CachingDomainNameResolver(realResolver, eventLoop); createConnection(); } BOSHConnectionPool::~BOSHConnectionPool() { - close(); + /* Don't do a normal close here. Instead kill things forcibly, as close() or writeFooter() will already have been called */ + std::vector<BOSHConnection::ref> connectionCopies = connections; + foreach (BOSHConnection::ref connection, connectionCopies) { + if (connection) { + destroyConnection(connection); + connection->disconnect(); + } + } foreach (ConnectionFactory* factory, myConnectionFactories) { delete factory; @@ -84,10 +90,14 @@ void BOSHConnectionPool::writeFooter() { void BOSHConnectionPool::close() { - /* TODO: Send a terminate here. */ + if (!sid.empty()) { + writeFooter(); + } + else { + pendingTerminate = true; std::vector<BOSHConnection::ref> connectionCopies = connections; foreach (BOSHConnection::ref connection, connectionCopies) { if (connection) { connection->disconnect(); - destroyConnection(connection); + } } } @@ -160,5 +170,6 @@ void BOSHConnectionPool::tryToSendQueuedData() { suitableConnection->setRID(rid); suitableConnection->terminateStream(); - onSessionTerminated(boost::shared_ptr<BOSHError>()); + sid = ""; + close(); } } @@ -200,9 +211,12 @@ void BOSHConnectionPool::handleHTTPError(const std::string& /*errorCode*/) { } -void BOSHConnectionPool::handleConnectionDisconnected(bool error, BOSHConnection::ref connection) { +void BOSHConnectionPool::handleConnectionDisconnected(bool/* error*/, BOSHConnection::ref connection) { destroyConnection(connection); - if (false && error) { - handleSessionTerminated(boost::make_shared<BOSHError>(BOSHError::UndefinedCondition)); + if (pendingTerminate && sid.empty() && connections.empty()) { + handleSessionTerminated(BOSHError::ref()); } + //else if (error) { + // handleSessionTerminated(boost::make_shared<BOSHError>(BOSHError::UndefinedCondition)); + //} else { /* We might have just freed up a connection slot to send with */ @@ -212,5 +226,5 @@ 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(), URL::getPortOrDefaultPort(boshURL), boost::optional<std::string>(), resolver, connectionFactory, timerFactory); BOSHConnection::ref connection = BOSHConnection::create(boshURL, connector, xmlParserFactory); connection->onXMPPDataRead.connect(boost::bind(&BOSHConnectionPool::handleDataRead, this, _1)); diff --git a/Swiften/Network/BOSHConnectionPool.h b/Swiften/Network/BOSHConnectionPool.h index 8bc0a7c..de707e8 100644 --- a/Swiften/Network/BOSHConnectionPool.h +++ b/Swiften/Network/BOSHConnectionPool.h @@ -10,4 +10,5 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeString.h> #include <Swiften/Network/BOSHConnection.h> @@ -16,8 +17,8 @@ namespace Swift { class HTTPConnectProxiedConnectionFactory; class TLSConnectionFactory; - class CachingNameOnlyDomainNameResolver; + class CachingDomainNameResolver; class EventLoop; - class BOSHConnectionPool : public boost::bsignals::trackable { + class SWIFTEN_API BOSHConnectionPool : public boost::bsignals::trackable { public: 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); @@ -54,5 +55,4 @@ namespace Swift { ConnectionFactory* connectionFactory; XMLParserFactory* xmlParserFactory; - TLSContextFactory* tlsFactory; TimerFactory* timerFactory; std::vector<BOSHConnection::ref> connections; @@ -66,5 +66,5 @@ namespace Swift { bool pendingRestart; std::vector<ConnectionFactory*> myConnectionFactories; - CachingNameOnlyDomainNameResolver* resolver; + CachingDomainNameResolver* resolver; }; } diff --git a/Swiften/Network/BoostConnection.cpp b/Swiften/Network/BoostConnection.cpp index 1d4bd32..5137c3c 100644 --- a/Swiften/Network/BoostConnection.cpp +++ b/Swiften/Network/BoostConnection.cpp @@ -15,4 +15,5 @@ #include <boost/asio/write.hpp> #include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Log.h> @@ -64,5 +65,5 @@ void BoostConnection::listen() { void BoostConnection::connect(const HostAddressPort& addressPort) { boost::asio::ip::tcp::endpoint endpoint( - boost::asio::ip::address::from_string(addressPort.getAddress().toString()), addressPort.getPort()); + boost::asio::ip::address::from_string(addressPort.getAddress().toString()), boost::numeric_cast<unsigned short>(addressPort.getPort())); socket_.async_connect( endpoint, diff --git a/Swiften/Network/BoostConnection.h b/Swiften/Network/BoostConnection.h index 0e29c54..636853a 100644 --- a/Swiften/Network/BoostConnection.h +++ b/Swiften/Network/BoostConnection.h @@ -12,4 +12,5 @@ #include <boost/thread/mutex.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/EventLoop/EventOwner.h> @@ -26,5 +27,5 @@ namespace Swift { class EventLoop; - class BoostConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<BoostConnection> { + class SWIFTEN_API BoostConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<BoostConnection> { public: typedef boost::shared_ptr<BoostConnection> ref; diff --git a/Swiften/Network/BoostConnectionServer.cpp b/Swiften/Network/BoostConnectionServer.cpp index eccffc6..c90b554 100644 --- a/Swiften/Network/BoostConnectionServer.cpp +++ b/Swiften/Network/BoostConnectionServer.cpp @@ -10,4 +10,6 @@ #include <boost/system/system_error.hpp> #include <boost/asio/placeholders.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <boost/optional.hpp> #include <Swiften/EventLoop/EventLoop.h> @@ -22,4 +24,11 @@ BoostConnectionServer::BoostConnectionServer(const HostAddress &address, int por void BoostConnectionServer::start() { + boost::optional<Error> error = tryStart(); + if (error) { + eventLoop->postEvent(boost::bind(boost::ref(onStopped), *error), shared_from_this()); + } +} + +boost::optional<BoostConnectionServer::Error> BoostConnectionServer::tryStart() { try { assert(!acceptor_); @@ -27,10 +36,10 @@ void BoostConnectionServer::start() { acceptor_ = new boost::asio::ip::tcp::acceptor( *ioService_, - boost::asio::ip::tcp::endpoint(address_.getRawAddress(), port_)); + boost::asio::ip::tcp::endpoint(address_.getRawAddress(), boost::numeric_cast<unsigned short>(port_))); } else { acceptor_ = new boost::asio::ip::tcp::acceptor( *ioService_, - boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port_)); + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), boost::numeric_cast<unsigned short>(port_))); } acceptNextConnection(); @@ -38,10 +47,11 @@ void BoostConnectionServer::start() { catch (const boost::system::system_error& e) { if (e.code() == boost::asio::error::address_in_use) { - eventLoop->postEvent(boost::bind(boost::ref(onStopped), Conflict), shared_from_this()); + return Conflict; } else { - eventLoop->postEvent(boost::bind(boost::ref(onStopped), UnknownError), shared_from_this()); + return UnknownError; } } + return boost::optional<Error>(); } diff --git a/Swiften/Network/BoostConnectionServer.h b/Swiften/Network/BoostConnectionServer.h index 56dc8bd..3ad0450 100644 --- a/Swiften/Network/BoostConnectionServer.h +++ b/Swiften/Network/BoostConnectionServer.h @@ -11,20 +11,17 @@ #include <boost/asio/ip/tcp.hpp> #include <boost/enable_shared_from_this.hpp> -#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/BoostConnection.h> #include <Swiften/Network/ConnectionServer.h> #include <Swiften/EventLoop/EventOwner.h> +#include <boost/optional/optional_fwd.hpp> namespace Swift { - class BoostConnectionServer : public ConnectionServer, public EventOwner, public boost::enable_shared_from_this<BoostConnectionServer> { + class SWIFTEN_API BoostConnectionServer : public ConnectionServer, public EventOwner, public boost::enable_shared_from_this<BoostConnectionServer> { public: typedef boost::shared_ptr<BoostConnectionServer> ref; - enum Error { - Conflict, - UnknownError - }; - static ref create(int port, boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) { return ref(new BoostConnectionServer(port, ioService, eventLoop)); @@ -35,4 +32,5 @@ namespace Swift { } + virtual boost::optional<Error> tryStart(); // FIXME: This should become the new start virtual void start(); virtual void stop(); diff --git a/Swiften/Network/BoostIOServiceThread.h b/Swiften/Network/BoostIOServiceThread.h index 00fb397..d1a5f37 100644 --- a/Swiften/Network/BoostIOServiceThread.h +++ b/Swiften/Network/BoostIOServiceThread.h @@ -11,6 +11,8 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> + namespace Swift { - class BoostIOServiceThread { + class SWIFTEN_API BoostIOServiceThread { public: BoostIOServiceThread(); diff --git a/Swiften/Network/BoostNetworkFactories.cpp b/Swiften/Network/BoostNetworkFactories.cpp index 488e519..870ae97 100644 --- a/Swiften/Network/BoostNetworkFactories.cpp +++ b/Swiften/Network/BoostNetworkFactories.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,11 +8,22 @@ #include <Swiften/Network/BoostTimerFactory.h> #include <Swiften/Network/BoostConnectionFactory.h> -#include <Swiften/Network/PlatformDomainNameResolver.h> + #include <Swiften/Network/BoostConnectionServerFactory.h> #include <Swiften/Network/PlatformNATTraversalWorker.h> #include <Swiften/Parser/PlatformXMLParserFactory.h> #include <Swiften/Network/NullNATTraverser.h> +#include <Swiften/Network/PlatformNetworkEnvironment.h> #include <Swiften/TLS/PlatformTLSFactories.h> #include <Swiften/Network/PlatformProxyProvider.h> +#include <Swiften/IDN/PlatformIDNConverter.h> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> +#include <Swiften/Crypto/CryptoProvider.h> + +#ifdef USE_UNBOUND +#include <Swiften/Network/UnboundDomainNameResolver.h> +#else +#include <Swiften/Network/PlatformDomainNameResolver.h> +#endif namespace Swift { @@ -21,5 +32,4 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(e timerFactory = new BoostTimerFactory(ioServiceThread.getIOService(), eventLoop); connectionFactory = new BoostConnectionFactory(ioServiceThread.getIOService(), eventLoop); - domainNameResolver = new PlatformDomainNameResolver(eventLoop); connectionServerFactory = new BoostConnectionServerFactory(ioServiceThread.getIOService(), eventLoop); #ifdef SWIFT_EXPERIMENTAL_FT @@ -28,16 +38,28 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(e natTraverser = new NullNATTraverser(eventLoop); #endif + networkEnvironment = new PlatformNetworkEnvironment(); xmlParserFactory = new PlatformXMLParserFactory(); tlsFactories = new PlatformTLSFactories(); proxyProvider = new PlatformProxyProvider(); + idnConverter = PlatformIDNConverter::create(); +#ifdef USE_UNBOUND + // TODO: What to do about idnConverter. + domainNameResolver = new UnboundDomainNameResolver(idnConverter, ioServiceThread.getIOService(), eventLoop); +#else + domainNameResolver = new PlatformDomainNameResolver(idnConverter, eventLoop); +#endif + cryptoProvider = PlatformCryptoProvider::create(); } BoostNetworkFactories::~BoostNetworkFactories() { + delete cryptoProvider; + delete domainNameResolver; + delete idnConverter; delete proxyProvider; delete tlsFactories; delete xmlParserFactory; + delete networkEnvironment; delete natTraverser; delete connectionServerFactory; - delete domainNameResolver; delete connectionFactory; delete timerFactory; diff --git a/Swiften/Network/BoostNetworkFactories.h b/Swiften/Network/BoostNetworkFactories.h index c9b12da..9c3bab1 100644 --- a/Swiften/Network/BoostNetworkFactories.h +++ b/Swiften/Network/BoostNetworkFactories.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,6 @@ #pragma once +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> #include <Swiften/Network/NetworkFactories.h> #include <Swiften/Network/BoostIOServiceThread.h> @@ -15,14 +17,14 @@ namespace Swift { class PlatformTLSFactories; - class BoostNetworkFactories : public NetworkFactories { + class SWIFTEN_API BoostNetworkFactories : public NetworkFactories { public: BoostNetworkFactories(EventLoop* eventLoop); ~BoostNetworkFactories(); - virtual TimerFactory* getTimerFactory() const { + virtual TimerFactory* getTimerFactory() const SWIFTEN_OVERRIDE { return timerFactory; } - virtual ConnectionFactory* getConnectionFactory() const { + virtual ConnectionFactory* getConnectionFactory() const SWIFTEN_OVERRIDE { return connectionFactory; } @@ -32,30 +34,42 @@ namespace Swift { } - DomainNameResolver* getDomainNameResolver() const { + DomainNameResolver* getDomainNameResolver() const SWIFTEN_OVERRIDE { return domainNameResolver; } - ConnectionServerFactory* getConnectionServerFactory() const { + ConnectionServerFactory* getConnectionServerFactory() const SWIFTEN_OVERRIDE { return connectionServerFactory; } - NATTraverser* getNATTraverser() const { + NetworkEnvironment* getNetworkEnvironment() const SWIFTEN_OVERRIDE { + return networkEnvironment; + } + + NATTraverser* getNATTraverser() const SWIFTEN_OVERRIDE { return natTraverser; } - virtual XMLParserFactory* getXMLParserFactory() const { + virtual XMLParserFactory* getXMLParserFactory() const SWIFTEN_OVERRIDE { return xmlParserFactory; } - virtual TLSContextFactory* getTLSContextFactory() const; + virtual TLSContextFactory* getTLSContextFactory() const SWIFTEN_OVERRIDE; - virtual ProxyProvider* getProxyProvider() const { + virtual ProxyProvider* getProxyProvider() const SWIFTEN_OVERRIDE { return proxyProvider; } - virtual EventLoop* getEventLoop() const { + virtual EventLoop* getEventLoop() const SWIFTEN_OVERRIDE { return eventLoop; } + virtual IDNConverter* getIDNConverter() const SWIFTEN_OVERRIDE { + return idnConverter; + } + + virtual CryptoProvider* getCryptoProvider() const SWIFTEN_OVERRIDE { + return cryptoProvider; + } + private: BoostIOServiceThread ioServiceThread; @@ -65,8 +79,11 @@ namespace Swift { ConnectionServerFactory* connectionServerFactory; NATTraverser* natTraverser; + NetworkEnvironment* networkEnvironment; XMLParserFactory* xmlParserFactory; PlatformTLSFactories* tlsFactories; ProxyProvider* proxyProvider; EventLoop* eventLoop; + IDNConverter* idnConverter; + CryptoProvider* cryptoProvider; }; } diff --git a/Swiften/Network/CachingDomainNameResolver.cpp b/Swiften/Network/CachingDomainNameResolver.cpp new file mode 100644 index 0000000..fea14a3 --- /dev/null +++ b/Swiften/Network/CachingDomainNameResolver.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/CachingDomainNameResolver.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +CachingDomainNameResolver::CachingDomainNameResolver(DomainNameResolver* realResolver, EventLoop*) : realResolver(realResolver) { +} + +CachingDomainNameResolver::~CachingDomainNameResolver() { + +} + +DomainNameServiceQuery::ref CachingDomainNameResolver::createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + //TODO: Cache + return realResolver->createServiceQuery(serviceLookupPrefix, domain); +} + +DomainNameAddressQuery::ref CachingDomainNameResolver::createAddressQuery(const std::string& name) { + //TODO: Cache + return realResolver->createAddressQuery(name); +} + +} diff --git a/Swiften/Network/CachingNameOnlyDomainNameResolver.h b/Swiften/Network/CachingDomainNameResolver.h index d9e78e6..3d50676 100644 --- a/Swiften/Network/CachingNameOnlyDomainNameResolver.h +++ b/Swiften/Network/CachingDomainNameResolver.h @@ -12,21 +12,20 @@ #include <Swiften/Network/StaticDomainNameResolver.h> - +/* + * FIXME: Does not do any caching yet. + */ namespace Swift { class EventLoop; - class CachingNameOnlyDomainNameResolver : public DomainNameResolver { + + class CachingDomainNameResolver : public DomainNameResolver { public: - CachingNameOnlyDomainNameResolver(DomainNameResolver* realResolver, EventLoop* eventLoop); - ~CachingNameOnlyDomainNameResolver(); + CachingDomainNameResolver(DomainNameResolver* realResolver, EventLoop* eventLoop); + ~CachingDomainNameResolver(); - virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& name); + virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain); 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/CachingNameOnlyDomainNameResolver.cpp b/Swiften/Network/CachingNameOnlyDomainNameResolver.cpp deleted file mode 100644 index a83bebd..0000000 --- a/Swiften/Network/CachingNameOnlyDomainNameResolver.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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/ChainedConnector.cpp b/Swiften/Network/ChainedConnector.cpp index 0a1283f..14d66ae 100644 --- a/Swiften/Network/ChainedConnector.cpp +++ b/Swiften/Network/ChainedConnector.cpp @@ -19,8 +19,12 @@ using namespace Swift; ChainedConnector::ChainedConnector( const std::string& hostname, + int port, + const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, const std::vector<ConnectionFactory*>& connectionFactories, TimerFactory* timerFactory) : hostname(hostname), + port(port), + serviceLookupPrefix(serviceLookupPrefix), resolver(resolver), connectionFactories(connectionFactories), @@ -59,5 +63,5 @@ void ChainedConnector::tryNextConnectionFactory() { 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, serviceLookupPrefix, resolver, connectionFactory, timerFactory); currentConnector->setTimeoutMilliseconds(timeoutMilliseconds); currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); diff --git a/Swiften/Network/ChainedConnector.h b/Swiften/Network/ChainedConnector.h index 12ef023..0a1cca9 100644 --- a/Swiften/Network/ChainedConnector.h +++ b/Swiften/Network/ChainedConnector.h @@ -11,5 +11,7 @@ #include <deque> #include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/Error.h> @@ -22,7 +24,7 @@ namespace Swift { class DomainNameResolver; - class ChainedConnector { + class SWIFTEN_API ChainedConnector { public: - ChainedConnector(const std::string& hostname, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); + ChainedConnector(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); void setTimeoutMilliseconds(int milliseconds); @@ -39,4 +41,6 @@ namespace Swift { private: std::string hostname; + int port; + boost::optional<std::string> serviceLookupPrefix; DomainNameResolver* resolver; std::vector<ConnectionFactory*> connectionFactories; @@ -47,3 +51,3 @@ namespace Swift { boost::shared_ptr<Error> lastError; }; -}; +} diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h index 6ad2999..97c287d 100644 --- a/Swiften/Network/Connection.h +++ b/Swiften/Network/Connection.h @@ -10,4 +10,5 @@ #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeByteArray.h> @@ -15,5 +16,5 @@ namespace Swift { class HostAddressPort; - class Connection { + class SWIFTEN_API Connection { public: typedef boost::shared_ptr<Connection> ref; diff --git a/Swiften/Network/ConnectionFactory.h b/Swiften/Network/ConnectionFactory.h index 9e92c36..c8be2fc 100644 --- a/Swiften/Network/ConnectionFactory.h +++ b/Swiften/Network/ConnectionFactory.h @@ -9,8 +9,10 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> + namespace Swift { class Connection; - class ConnectionFactory { + class SWIFTEN_API ConnectionFactory { public: virtual ~ConnectionFactory(); diff --git a/Swiften/Network/ConnectionServer.h b/Swiften/Network/ConnectionServer.h index 00703a4..2e09348 100644 --- a/Swiften/Network/ConnectionServer.h +++ b/Swiften/Network/ConnectionServer.h @@ -8,16 +8,25 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/HostAddressPort.h> +#include <boost/optional/optional_fwd.hpp> namespace Swift { - class ConnectionServer { + class SWIFTEN_API ConnectionServer { public: + enum Error { + Conflict, + UnknownError + }; + virtual ~ConnectionServer(); virtual HostAddressPort getAddressPort() const = 0; + virtual boost::optional<Error> tryStart() = 0; // FIXME: This should become the new start + virtual void start() = 0; diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp index 5e7f8d9..1db1eac 100644 --- a/Swiften/Network/Connector.cpp +++ b/Swiften/Network/Connector.cpp @@ -18,5 +18,5 @@ 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, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), port(port), serviceLookupPrefix(serviceLookupPrefix), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0), queriedAllServices(true), foundSomeDNS(false) { } @@ -32,13 +32,17 @@ void Connector::start() { 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(); } + if (serviceLookupPrefix) { + serviceQuery = resolver->createServiceQuery(*serviceLookupPrefix, hostname); + serviceQuery->onResult.connect(boost::bind(&Connector::handleServiceQueryResult, shared_from_this(), _1)); serviceQuery->run(); } + else { + queryAddress(hostname); + } +} void Connector::stop() { @@ -110,10 +114,10 @@ void Connector::tryNextAddress() { 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)); } } @@ -125,8 +129,15 @@ void Connector::tryConnect(const HostAddressPort& target) { currentConnection->onConnectFinished.connect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); currentConnection->connect(target); + if (timer) { + timer->start(); + } } void Connector::handleConnectionConnectFinished(bool error) { SWIFT_LOG(debug) << "ConnectFinished: " << (error ? "error" : "success") << std::endl; + if (timer) { + timer->stop(); + timer.reset(); + } currentConnection->onConnectFinished.disconnect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); if (error) { @@ -170,6 +181,6 @@ void Connector::finish(boost::shared_ptr<Connection> connection) { void Connector::handleTimeout() { SWIFT_LOG(debug) << "Timeout" << std::endl; - finish(boost::shared_ptr<Connection>()); + handleConnectionConnectFinished(true); } -}; +} diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h index bf0efaf..16f8539 100644 --- a/Swiften/Network/Connector.h +++ b/Swiften/Network/Connector.h @@ -10,5 +10,6 @@ #include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> - +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/DomainNameServiceQuery.h> #include <Swiften/Network/Connection.h> @@ -24,10 +25,10 @@ namespace Swift { class TimerFactory; - class Connector : public boost::bsignals::trackable, public boost::enable_shared_from_this<Connector> { + class SWIFTEN_API 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, int defaultPort = 5222) { - return ref(new Connector(hostname, resolver, connectionFactory, timerFactory, defaultPort)); + static Connector::ref create(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { + return ref(new Connector(hostname, port, serviceLookupPrefix, resolver, connectionFactory, timerFactory)); } @@ -39,5 +40,5 @@ namespace Swift { private: - Connector(const std::string& hostname, DomainNameResolver*, ConnectionFactory*, TimerFactory*, int defaultPort); + Connector(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver*, ConnectionFactory*, TimerFactory*); void handleServiceQueryResult(const std::vector<DomainNameServiceQuery::Result>& result); @@ -56,8 +57,9 @@ namespace Swift { private: std::string hostname; + int port; + boost::optional<std::string> serviceLookupPrefix; DomainNameResolver* resolver; ConnectionFactory* connectionFactory; TimerFactory* timerFactory; - int defaultPort; int timeoutMilliseconds; boost::shared_ptr<Timer> timer; @@ -70,3 +72,3 @@ namespace Swift { bool foundSomeDNS; }; -}; +} diff --git a/Swiften/Network/DomainNameResolver.h b/Swiften/Network/DomainNameResolver.h index b0ebc35..dc7013e 100644 --- a/Swiften/Network/DomainNameResolver.h +++ b/Swiften/Network/DomainNameResolver.h @@ -8,7 +8,8 @@ #include <boost/shared_ptr.hpp> - #include <string> +#include <Swiften/Base/API.h> + namespace Swift { class DomainNameServiceQuery; @@ -16,9 +17,9 @@ namespace Swift { - class DomainNameResolver { + class SWIFTEN_API DomainNameResolver { public: virtual ~DomainNameResolver(); - virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& name) = 0; + virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) = 0; virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name) = 0; }; diff --git a/Swiften/Network/DomainNameServiceQuery.cpp b/Swiften/Network/DomainNameServiceQuery.cpp index da1e1ab..5e87295 100644 --- a/Swiften/Network/DomainNameServiceQuery.cpp +++ b/Swiften/Network/DomainNameServiceQuery.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -14,6 +14,10 @@ #include <Swiften/Base/RandomGenerator.h> #include <boost/numeric/conversion/cast.hpp> +#include <boost/lambda/lambda.hpp> +#include <boost/lambda/bind.hpp> +#include <boost/typeof/typeof.hpp> using namespace Swift; +namespace lambda = boost::lambda; namespace { @@ -23,12 +27,4 @@ namespace { } }; - - struct GetWeight { - GetWeight() {} - - int operator()(const DomainNameServiceQuery::Result& result) { - return result.weight + 1 /* easy hack to account for '0' weights getting at least some weight */; - } - }; } @@ -40,5 +36,5 @@ DomainNameServiceQuery::~DomainNameServiceQuery() { void DomainNameServiceQuery::sortResults(std::vector<DomainNameServiceQuery::Result>& queries, RandomGenerator& generator) { ResultPriorityComparator comparator; - std::sort(queries.begin(), queries.end(), comparator); + std::stable_sort(queries.begin(), queries.end(), comparator); std::vector<DomainNameServiceQuery::Result>::iterator i = queries.begin(); @@ -47,10 +43,15 @@ void DomainNameServiceQuery::sortResults(std::vector<DomainNameServiceQuery::Res if (std::distance(i, next) > 1) { std::vector<int> weights; - std::transform(i, next, std::back_inserter(weights), GetWeight()); - for (size_t j = 0; j < weights.size() - 1; ++j) { + std::transform(i, next, std::back_inserter(weights), + /* easy hack to account for '0' weights getting at least some weight */ + lambda::bind(&Result::weight, lambda::_1) + 1); + for (int j = 0; j < boost::numeric_cast<int>(weights.size() - 1); ++j) { std::vector<int> cumulativeWeights; - std::partial_sum(weights.begin() + j, weights.end(), std::back_inserter(cumulativeWeights)); + std::partial_sum( + weights.begin() + j, + weights.end(), + std::back_inserter(cumulativeWeights)); int randomNumber = generator.generateRandomInteger(cumulativeWeights.back()); - int selectedIndex = std::lower_bound(cumulativeWeights.begin(), cumulativeWeights.end(), randomNumber) - cumulativeWeights.begin(); + BOOST_AUTO(selectedIndex, std::lower_bound(cumulativeWeights.begin(), cumulativeWeights.end(), randomNumber) - cumulativeWeights.begin()); std::swap(i[j], i[j + selectedIndex]); std::swap(weights.begin()[j], weights.begin()[j + selectedIndex]); diff --git a/Swiften/Network/DomainNameServiceQuery.h b/Swiften/Network/DomainNameServiceQuery.h index 0e80233..fdf5b5d 100644 --- a/Swiften/Network/DomainNameServiceQuery.h +++ b/Swiften/Network/DomainNameServiceQuery.h @@ -13,4 +13,5 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Network/DomainNameResolveError.h> @@ -18,5 +19,5 @@ namespace Swift { class RandomGenerator; - class DomainNameServiceQuery { + class SWIFTEN_API DomainNameServiceQuery { public: typedef boost::shared_ptr<DomainNameServiceQuery> ref; diff --git a/Swiften/Network/DummyConnection.h b/Swiften/Network/DummyConnection.h index 5191e30..36bf897 100644 --- a/Swiften/Network/DummyConnection.h +++ b/Swiften/Network/DummyConnection.h @@ -9,4 +9,5 @@ #include <boost/enable_shared_from_this.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/HostAddressPort.h> @@ -15,5 +16,5 @@ namespace Swift { - class DummyConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<DummyConnection> { + class SWIFTEN_API DummyConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<DummyConnection> { public: DummyConnection(EventLoop* eventLoop); diff --git a/Swiften/Network/DummyTimerFactory.h b/Swiften/Network/DummyTimerFactory.h index 0c49f3d..1e9413b 100644 --- a/Swiften/Network/DummyTimerFactory.h +++ b/Swiften/Network/DummyTimerFactory.h @@ -9,8 +9,9 @@ #include <list> +#include <Swiften/Base/API.h> #include <Swiften/Network/TimerFactory.h> namespace Swift { - class DummyTimerFactory : public TimerFactory { + class SWIFTEN_API DummyTimerFactory : public TimerFactory { public: class DummyTimer; diff --git a/Swiften/Network/FakeConnection.cpp b/Swiften/Network/FakeConnection.cpp index be5555c..a84c92e 100644 --- a/Swiften/Network/FakeConnection.cpp +++ b/Swiften/Network/FakeConnection.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -44,5 +44,5 @@ void FakeConnection::connect(const HostAddressPort& address) { } eventLoop->postEvent( - boost::bind(boost::ref(onConnectFinished), error), + boost::bind(boost::ref(onConnectFinished), error ? true : false), shared_from_this()); } diff --git a/Swiften/Network/FakeConnection.h b/Swiften/Network/FakeConnection.h index 99cb584..eca45da 100644 --- a/Swiften/Network/FakeConnection.h +++ b/Swiften/Network/FakeConnection.h @@ -11,4 +11,5 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/HostAddressPort.h> @@ -17,5 +18,5 @@ namespace Swift { - class FakeConnection : + class SWIFTEN_API FakeConnection : public Connection, public EventOwner, diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp index 512381f..a88ded1 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -16,5 +16,4 @@ #include <iostream> #include <boost/bind.hpp> -#include <boost/thread.hpp> #include <boost/lexical_cast.hpp> @@ -25,69 +24,25 @@ #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)); +void HTTPConnectProxiedConnection::initializeProxy() { std::stringstream connect; - connect << "CONNECT " << server_.getAddress().toString() << ":" << server_.getPort() << " HTTP/1.1\r\n"; + connect << "CONNECT " << getServer().getAddress().toString() << ":" << getServer().getPort() << " HTTP/1.1\r\n"; SafeByteArray data = createSafeByteArray(connect.str()); if (!authID_.empty() && !authPassword_.empty()) { @@ -101,34 +56,29 @@ void HTTPConnectProxiedConnection::handleConnectFinished(Connection::ref connect 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); - } + write(data); } -void HTTPConnectProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { - if (!connected_) { +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()); + try { + int status = boost::lexical_cast<int>(tmp[1]); SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl; if (status / 100 == 2) { // all 2XX states are OK - connected_ = true; - onConnectFinished(false); - return; + setProxyInitializeFinished(true); } + else { SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl; + setProxyInitializeFinished(false); } - disconnect(); - onConnectFinished(true); } - else { - onDataRead(data); + catch (boost::bad_lexical_cast&) { + SWIFT_LOG(warning) << "Unexpected response: " << tmp[1] << std::endl; + setProxyInitializeFinished(false); } } - -HostAddressPort HTTPConnectProxiedConnection::getLocalAddress() const { - return connection_->getLocalAddress(); + else { + setProxyInitializeFinished(false); + } } diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h index 8318ecc..c209dc1 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.h +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -14,58 +14,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/Base/API.h> +#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 SWIFTEN_API 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 @@ -17,13 +17,13 @@ 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 @@ -23,6 +23,6 @@ namespace Swift { 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(); @@ -32,5 +32,4 @@ namespace Swift { ConnectionFactory* connectionFactory_; TimerFactory* timerFactory_; - EventLoop* eventLoop_; std::string proxyHost_; int proxyPort_; diff --git a/Swiften/Network/HostAddress.cpp b/Swiften/Network/HostAddress.cpp index f00581f..ff5c1c4 100644 --- a/Swiften/Network/HostAddress.cpp +++ b/Swiften/Network/HostAddress.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,4 +16,7 @@ #include <string> +static boost::asio::ip::address localhost4 = boost::asio::ip::address(boost::asio::ip::address_v4::loopback()); +static boost::asio::ip::address localhost6 = boost::asio::ip::address(boost::asio::ip::address_v6::loopback()); + namespace Swift { @@ -29,9 +32,9 @@ HostAddress::HostAddress(const std::string& address) { } -HostAddress::HostAddress(const unsigned char* address, int length) { +HostAddress::HostAddress(const unsigned char* address, size_t length) { assert(length == 4 || length == 16); if (length == 4) { boost::asio::ip::address_v4::bytes_type data; - for (int i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) { data[i] = address[i]; } @@ -40,5 +43,5 @@ HostAddress::HostAddress(const unsigned char* address, int length) { else { boost::asio::ip::address_v6::bytes_type data; - for (int i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) { data[i] = address[i]; } @@ -62,3 +65,7 @@ boost::asio::ip::address HostAddress::getRawAddress() const { } +bool HostAddress::isLocalhost() const { + return address_ == localhost4 || address_ == localhost6; +} + } diff --git a/Swiften/Network/HostAddress.h b/Swiften/Network/HostAddress.h index 0b3bdda..c62239b 100644 --- a/Swiften/Network/HostAddress.h +++ b/Swiften/Network/HostAddress.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,10 +9,12 @@ #include <boost/asio/ip/address.hpp> +#include <Swiften/Base/API.h> + namespace Swift { - class HostAddress { + class SWIFTEN_API HostAddress { public: HostAddress(); HostAddress(const std::string&); - HostAddress(const unsigned char* address, int length); + HostAddress(const unsigned char* address, size_t length); HostAddress(const boost::asio::ip::address& address); @@ -25,4 +27,5 @@ namespace Swift { bool isValid() const; + bool isLocalhost() const; private: diff --git a/Swiften/Network/HostAddressPort.h b/Swiften/Network/HostAddressPort.h index e3c0413..68f3a1c 100644 --- a/Swiften/Network/HostAddressPort.h +++ b/Swiften/Network/HostAddressPort.h @@ -9,8 +9,9 @@ #include <boost/asio/ip/tcp.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/HostAddress.h> namespace Swift { - class HostAddressPort { + class SWIFTEN_API HostAddressPort { public: HostAddressPort(const HostAddress& address = HostAddress(), int port = -1); 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/MacOSXProxyProvider.cpp b/Swiften/Network/MacOSXProxyProvider.cpp index eaadd28..3456c73 100644 --- a/Swiften/Network/MacOSXProxyProvider.cpp +++ b/Swiften/Network/MacOSXProxyProvider.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + #include <Swiften/Base/Platform.h> #include <Swiften/Network/MacOSXProxyProvider.h> @@ -11,4 +17,5 @@ #include <stdlib.h> #include <iostream> +#include <boost/numeric/conversion/cast.hpp> #include <utility> @@ -17,4 +24,6 @@ #endif +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" + using namespace Swift; @@ -28,5 +37,5 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl CFNumberRef zero = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i); CFComparisonResult result = CFNumberCompare(numberValue, zero, NULL); - CFRelease(numberValue); + CFRelease(zero); if(result != kCFCompareEqualTo) { @@ -38,5 +47,4 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl if(numberValue != NULL) { CFNumberGetValue(numberValue, kCFNumberIntType, &port); - CFRelease(numberValue); } @@ -47,5 +55,5 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl // if the string is toby the length must be at least 5. CFIndex length = CFStringGetLength(stringValue) + 1; - buffer.resize(length); + buffer.resize(boost::numeric_cast<size_t>(length)); if(CFStringGetCString(stringValue, &buffer[0], length, kCFStringEncodingMacRoman)) { for(std::vector<char>::iterator iter = buffer.begin(); iter != buffer.end(); ++iter) { @@ -53,5 +61,4 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl } } - CFRelease(stringValue); } } @@ -79,4 +86,5 @@ HostAddressPort MacOSXProxyProvider::getHTTPConnectProxy() const { if(proxies != NULL) { result = getFromDictionary(proxies, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort); + CFRelease(proxies); } #endif @@ -90,4 +98,5 @@ HostAddressPort MacOSXProxyProvider::getSOCKS5Proxy() const { if(proxies != NULL) { result = getFromDictionary(proxies, kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort); + CFRelease(proxies); } #endif diff --git a/Swiften/Network/MiniUPnPInterface.cpp b/Swiften/Network/MiniUPnPInterface.cpp index c9f682f..bfa989f 100644 --- a/Swiften/Network/MiniUPnPInterface.cpp +++ b/Swiften/Network/MiniUPnPInterface.cpp @@ -7,6 +7,8 @@ #include <Swiften/Network/MiniUPnPInterface.h> +#include <miniupnpc.h> #include <upnpcommands.h> #include <upnperrors.h> +#include <boost/smart_ptr/make_shared.hpp> #include <boost/lexical_cast.hpp> @@ -15,32 +17,41 @@ namespace Swift { -MiniUPnPInterface::MiniUPnPInterface() : isValid(false) { +struct MiniUPnPInterface::Private { + bool isValid; + std::string localAddress; + UPNPDev* deviceList; + UPNPUrls urls; + IGDdatas data; +}; + +MiniUPnPInterface::MiniUPnPInterface() : p(boost::make_shared<Private>()) { + p->isValid = false; int error = 0; - deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); - if (!deviceList) { + p->deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); + if (!p->deviceList) { return; } char lanAddress[64]; - if (!UPNP_GetValidIGD(deviceList, &urls, &data, lanAddress, sizeof(lanAddress))) { + if (!UPNP_GetValidIGD(p->deviceList, &p->urls, &p->data, lanAddress, sizeof(lanAddress))) { return; } - localAddress = std::string(lanAddress); - isValid = true; + p->localAddress = std::string(lanAddress); + p->isValid = true; } MiniUPnPInterface::~MiniUPnPInterface() { - if (isValid) { - FreeUPNPUrls(&urls); + if (p->isValid) { + FreeUPNPUrls(&p->urls); } - freeUPNPDevlist(deviceList); + freeUPNPDevlist(p->deviceList); } boost::optional<HostAddress> MiniUPnPInterface::getPublicIP() { - if (!isValid) { + if (!p->isValid) { return boost::optional<HostAddress>(); } char externalIPAddress[40]; - int ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); + int ret = UPNP_GetExternalIPAddress(p->urls.controlURL, p->data.first.servicetype, externalIPAddress); if (ret != UPNPCOMMAND_SUCCESS) { return boost::optional<HostAddress>(); @@ -52,5 +63,5 @@ boost::optional<HostAddress> MiniUPnPInterface::getPublicIP() { boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(int actualLocalPort, int actualPublicPort) { - if (!isValid) { + if (!p->isValid) { return boost::optional<NATPortMapping>(); } @@ -62,5 +73,14 @@ boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(int actualLoca std::string leaseSeconds = boost::lexical_cast<std::string>(mapping.getLeaseInSeconds()); - int ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), localPort.c_str(), localAddress.c_str(), 0, mapping.getPublicPort() == NATPortMapping::TCP ? "TCP" : "UDP", 0, leaseSeconds.c_str()); + int ret = UPNP_AddPortMapping( + p->urls.controlURL, + p->data.first.servicetype, + publicPort.c_str(), + localPort.c_str(), + p->localAddress.c_str(), + 0, + mapping.getProtocol() == NATPortMapping::TCP ? "TCP" : "UDP", + 0, + leaseSeconds.c_str()); if (ret == UPNPCOMMAND_SUCCESS) { return mapping; @@ -72,5 +92,5 @@ boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(int actualLoca bool MiniUPnPInterface::removePortForward(const NATPortMapping& mapping) { - if (!isValid) { + if (!p->isValid) { return false; } @@ -80,7 +100,11 @@ bool MiniUPnPInterface::removePortForward(const NATPortMapping& mapping) { std::string leaseSeconds = boost::lexical_cast<std::string>(mapping.getLeaseInSeconds()); - int ret = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), mapping.getProtocol() == NATPortMapping::TCP ? "TCP" : "UDP", 0); + int ret = UPNP_DeletePortMapping(p->urls.controlURL, p->data.first.servicetype, publicPort.c_str(), mapping.getProtocol() == NATPortMapping::TCP ? "TCP" : "UDP", 0); return ret == UPNPCOMMAND_SUCCESS; } +bool MiniUPnPInterface::isAvailable() { + return p->isValid; +} + } diff --git a/Swiften/Network/MiniUPnPInterface.h b/Swiften/Network/MiniUPnPInterface.h index ae9be66..61d12ca 100644 --- a/Swiften/Network/MiniUPnPInterface.h +++ b/Swiften/Network/MiniUPnPInterface.h @@ -8,5 +8,6 @@ #include <boost/optional.hpp> -#include <miniupnpc.h> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> #include <Swiften/Network/NATPortMapping.h> @@ -14,12 +15,10 @@ namespace Swift { - class MiniUPnPInterface : public NATTraversalInterface { + class MiniUPnPInterface : public NATTraversalInterface, boost::noncopyable { public: MiniUPnPInterface(); ~MiniUPnPInterface(); - virtual bool isAvailable() { - return isValid; - } + virtual bool isAvailable(); boost::optional<HostAddress> getPublicIP(); @@ -28,9 +27,6 @@ namespace Swift { private: - bool isValid; - std::string localAddress; - UPNPDev* deviceList; - UPNPUrls urls; - IGDdatas data; + struct Private; + boost::shared_ptr<Private> p; }; } diff --git a/Swiften/Network/NATPMPInterface.cpp b/Swiften/Network/NATPMPInterface.cpp index 36553ed..dcae641 100644 --- a/Swiften/Network/NATPMPInterface.cpp +++ b/Swiften/Network/NATPMPInterface.cpp @@ -5,26 +5,43 @@ */ +/* +* Copyright (c) 2014 Kevin Smith +* Licensed under the GNU General Public License v3. +* See Documentation/Licenses/GPLv3.txt for more information. +*/ + #include <Swiften/Network/NATPMPInterface.h> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + #include <Swiften/Base/Log.h> +// This has to be included after the previous headers, because of WIN32 macro +// being defined somewhere. +#include <natpmp.h> + #pragma GCC diagnostic ignored "-Wold-style-cast" namespace Swift { -NATPMPInterface::NATPMPInterface() { - initnatpmp(&natpmp, 0, 0); +struct NATPMPInterface::Private { + natpmp_t natpmp; +}; + +NATPMPInterface::NATPMPInterface() : p(boost::make_shared<Private>()) { + initnatpmp(&p->natpmp, 0, 0); } NATPMPInterface::~NATPMPInterface() { - closenatpmp(&natpmp); + closenatpmp(&p->natpmp); } bool NATPMPInterface::isAvailable() { - return getPublicIP(); + return getPublicIP() ? true : false; } boost::optional<HostAddress> NATPMPInterface::getPublicIP() { - if (sendpublicaddressrequest(&natpmp) < 0) { + if (sendpublicaddressrequest(&p->natpmp) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!" << std::endl; return boost::optional<HostAddress>(); @@ -37,8 +54,8 @@ boost::optional<HostAddress> NATPMPInterface::getPublicIP() { struct timeval timeout; FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); + FD_SET(p->natpmp.s, &fds); + getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); + r = readnatpmpresponseorretry(&p->natpmp, &response); } while (r == NATPMP_TRYAGAIN); @@ -54,5 +71,10 @@ boost::optional<HostAddress> NATPMPInterface::getPublicIP() { boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, int publicPort) { NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); - if (sendnewportmappingrequest(&natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, mapping.getLeaseInSeconds(), mapping.getPublicPort(), mapping.getLocalPort()) < 0) { + if (sendnewportmappingrequest( + &p->natpmp, + mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, + boost::numeric_cast<uint16_t>(mapping.getLocalPort()), + boost::numeric_cast<uint16_t>(mapping.getPublicPort()), + boost::numeric_cast<uint32_t>(mapping.getLeaseInSeconds())) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!" << std::endl; return boost::optional<NATPortMapping>(); @@ -65,12 +87,12 @@ boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, i struct timeval timeout; FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); + FD_SET(p->natpmp.s, &fds); + getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); + r = readnatpmpresponseorretry(&p->natpmp, &response); } while(r == NATPMP_TRYAGAIN); if (r == 0) { - NATPortMapping result(response.pnu.newportmapping.privateport, response.pnu.newportmapping.mappedpublicport, NATPortMapping::TCP, response.pnu.newportmapping.lifetime); + NATPortMapping result(response.pnu.newportmapping.privateport, response.pnu.newportmapping.mappedpublicport, NATPortMapping::TCP, boost::numeric_cast<int>(response.pnu.newportmapping.lifetime)); return result; } @@ -82,5 +104,5 @@ boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, i bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { - if (sendnewportmappingrequest(&natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, mapping.getLocalPort()) < 0) { + if (sendnewportmappingrequest(&p->natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, boost::numeric_cast<uint32_t>(mapping.getLocalPort())) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!" << std::endl; return false; @@ -93,8 +115,8 @@ bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { struct timeval timeout; FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); + FD_SET(p->natpmp.s, &fds); + getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); + r = readnatpmpresponseorretry(&p->natpmp, &response); } while(r == NATPMP_TRYAGAIN); diff --git a/Swiften/Network/NATPMPInterface.h b/Swiften/Network/NATPMPInterface.h index 6e7fb73..e079a59 100644 --- a/Swiften/Network/NATPMPInterface.h +++ b/Swiften/Network/NATPMPInterface.h @@ -8,13 +8,11 @@ #include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> #include <Swiften/Network/NATPortMapping.h> #include <Swiften/Network/NATTraversalInterface.h> -// This has to be included after the previous headers, because of WIN32 macro -// being defined somewhere. -#include <natpmp.h> - namespace Swift { - class NATPMPInterface : public NATTraversalInterface { + class NATPMPInterface : public NATTraversalInterface, boost::noncopyable { public: NATPMPInterface(); @@ -28,5 +26,6 @@ namespace Swift { private: - natpmp_t natpmp; + struct Private; + boost::shared_ptr<Private> p; }; } diff --git a/Swiften/Network/NATPortMapping.h b/Swiften/Network/NATPortMapping.h index db14500..0f6bd95 100644 --- a/Swiften/Network/NATPortMapping.h +++ b/Swiften/Network/NATPortMapping.h @@ -14,8 +14,9 @@ namespace Swift { enum Protocol { TCP, - UDP, + UDP }; - NATPortMapping(int localPort, int publicPort, Protocol protocol = TCP, int leaseInSeconds = 60 * 60 * 24) : publicPort(publicPort), localPort(localPort), protocol(protocol), leaseInSeconds(leaseInSeconds) { + NATPortMapping(int localPort, int publicPort, Protocol protocol = TCP, int leaseInSeconds = 60 * 60 * 24) : + publicPort(publicPort), localPort(localPort), protocol(protocol), leaseInSeconds(leaseInSeconds) { } diff --git a/Swiften/Network/NATTraversalForwardPortRequest.h b/Swiften/Network/NATTraversalForwardPortRequest.h index 1bbc9ca..48f85ea 100644 --- a/Swiften/Network/NATTraversalForwardPortRequest.h +++ b/Swiften/Network/NATTraversalForwardPortRequest.h @@ -9,12 +9,14 @@ #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> #include <Swiften/Network/NATPortMapping.h> namespace Swift { - class NATTraversalForwardPortRequest { + class SWIFTEN_API NATTraversalForwardPortRequest { public: virtual ~NATTraversalForwardPortRequest(); - virtual void run() = 0; + virtual void start() = 0; + virtual void stop() = 0; boost::signal<void (boost::optional<NATPortMapping>)> onResult; diff --git a/Swiften/Network/NATTraversalGetPublicIPRequest.h b/Swiften/Network/NATTraversalGetPublicIPRequest.h index db1f005..1270db3 100644 --- a/Swiften/Network/NATTraversalGetPublicIPRequest.h +++ b/Swiften/Network/NATTraversalGetPublicIPRequest.h @@ -15,5 +15,6 @@ namespace Swift { virtual ~NATTraversalGetPublicIPRequest(); - virtual void run() = 0; + virtual void start() = 0; + virtual void stop() = 0; boost::signal<void (boost::optional<HostAddress>)> onResult; diff --git a/Swiften/Network/NATTraversalRemovePortForwardingRequest.h b/Swiften/Network/NATTraversalRemovePortForwardingRequest.h index cf349b1..210cbcb 100644 --- a/Swiften/Network/NATTraversalRemovePortForwardingRequest.h +++ b/Swiften/Network/NATTraversalRemovePortForwardingRequest.h @@ -16,5 +16,5 @@ namespace Swift { enum Protocol { TCP, - UDP, + UDP }; @@ -28,5 +28,6 @@ namespace Swift { virtual ~NATTraversalRemovePortForwardingRequest(); - virtual void run() = 0; + virtual void start() = 0; + virtual void stop() = 0; boost::signal<void (boost::optional<bool> /* failure */)> onResult; diff --git a/Swiften/Network/NetworkEnvironment.h b/Swiften/Network/NetworkEnvironment.h index fbff0cb..36a2bde 100644 --- a/Swiften/Network/NetworkEnvironment.h +++ b/Swiften/Network/NetworkEnvironment.h @@ -9,9 +9,10 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/NetworkInterface.h> namespace Swift { - class NetworkEnvironment { + class SWIFTEN_API NetworkEnvironment { public: virtual ~NetworkEnvironment(); diff --git a/Swiften/Network/NetworkFactories.h b/Swiften/Network/NetworkFactories.h index c8009a6..dd8e216 100644 --- a/Swiften/Network/NetworkFactories.h +++ b/Swiften/Network/NetworkFactories.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -18,4 +18,7 @@ namespace Swift { class ProxyProvider; class EventLoop; + class IDNConverter; + class NetworkEnvironment; + class CryptoProvider; /** @@ -31,8 +34,11 @@ namespace Swift { virtual ConnectionServerFactory* getConnectionServerFactory() const = 0; virtual NATTraverser* getNATTraverser() const = 0; + virtual NetworkEnvironment* getNetworkEnvironment() const = 0; virtual XMLParserFactory* getXMLParserFactory() const = 0; virtual TLSContextFactory* getTLSContextFactory() const = 0; virtual ProxyProvider* getProxyProvider() const = 0; virtual EventLoop* getEventLoop() const = 0; + virtual IDNConverter* getIDNConverter() const = 0; + virtual CryptoProvider* getCryptoProvider() const = 0; }; } diff --git a/Swiften/Network/NullNATTraverser.cpp b/Swiften/Network/NullNATTraverser.cpp index 8cb35cd..43fcd08 100644 --- a/Swiften/Network/NullNATTraverser.cpp +++ b/Swiften/Network/NullNATTraverser.cpp @@ -22,8 +22,11 @@ class NullNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPRequest } - virtual void run() { + virtual void start() { eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<HostAddress>())); } + virtual void stop() { + } + private: EventLoop* eventLoop; @@ -35,8 +38,11 @@ class NullNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest } - virtual void run() { + virtual void start() { eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<NATPortMapping>())); } + virtual void stop() { + } + private: EventLoop* eventLoop; @@ -48,8 +54,11 @@ class NullNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePor } - virtual void run() { + virtual void start() { eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<bool>(true))); } + virtual void stop() { + } + private: EventLoop* eventLoop; diff --git a/Swiften/Network/PlatformDomainNameAddressQuery.cpp b/Swiften/Network/PlatformDomainNameAddressQuery.cpp index ec7e663..91d15b9 100644 --- a/Swiften/Network/PlatformDomainNameAddressQuery.cpp +++ b/Swiften/Network/PlatformDomainNameAddressQuery.cpp @@ -14,5 +14,9 @@ namespace Swift { -PlatformDomainNameAddressQuery::PlatformDomainNameAddressQuery(const std::string& host, EventLoop* eventLoop, PlatformDomainNameResolver* resolver) : PlatformDomainNameQuery(resolver), hostname(host), eventLoop(eventLoop) { +PlatformDomainNameAddressQuery::PlatformDomainNameAddressQuery(const boost::optional<std::string>& host, EventLoop* eventLoop, PlatformDomainNameResolver* resolver) : PlatformDomainNameQuery(resolver), hostnameValid(false), eventLoop(eventLoop) { + if (!!host) { + hostname = *host; + hostnameValid = true; + } } @@ -22,4 +26,8 @@ void PlatformDomainNameAddressQuery::run() { void PlatformDomainNameAddressQuery::runBlocking() { + if (!hostnameValid) { + emitError(); + return; + } //std::cout << "PlatformDomainNameResolver::doRun()" << std::endl; boost::asio::ip::tcp::resolver resolver(ioService); diff --git a/Swiften/Network/PlatformDomainNameAddressQuery.h b/Swiften/Network/PlatformDomainNameAddressQuery.h index e1dc05f..9e89086 100644 --- a/Swiften/Network/PlatformDomainNameAddressQuery.h +++ b/Swiften/Network/PlatformDomainNameAddressQuery.h @@ -21,5 +21,5 @@ namespace Swift { class PlatformDomainNameAddressQuery : public DomainNameAddressQuery, public PlatformDomainNameQuery, public boost::enable_shared_from_this<PlatformDomainNameAddressQuery>, public EventOwner { public: - PlatformDomainNameAddressQuery(const std::string& host, EventLoop* eventLoop, PlatformDomainNameResolver*); + PlatformDomainNameAddressQuery(const boost::optional<std::string>& host, EventLoop* eventLoop, PlatformDomainNameResolver*); void run(); @@ -32,4 +32,5 @@ namespace Swift { boost::asio::io_service ioService; std::string hostname; + bool hostnameValid; EventLoop* eventLoop; }; diff --git a/Swiften/Network/PlatformDomainNameResolver.cpp b/Swiften/Network/PlatformDomainNameResolver.cpp index 63f7404..b65e884 100644 --- a/Swiften/Network/PlatformDomainNameResolver.cpp +++ b/Swiften/Network/PlatformDomainNameResolver.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ #include <string> -#include <Swiften/IDN/IDNA.h> +#include <Swiften/IDN/IDNConverter.h> #include <Swiften/Network/HostAddress.h> #include <Swiften/EventLoop/EventLoop.h> @@ -28,5 +28,5 @@ using namespace Swift; namespace Swift { -PlatformDomainNameResolver::PlatformDomainNameResolver(EventLoop* eventLoop) : eventLoop(eventLoop), stopRequested(false) { +PlatformDomainNameResolver::PlatformDomainNameResolver(IDNConverter* idnConverter, EventLoop* eventLoop) : idnConverter(idnConverter), eventLoop(eventLoop), stopRequested(false) { thread = new boost::thread(boost::bind(&PlatformDomainNameResolver::run, this)); } @@ -39,10 +39,15 @@ PlatformDomainNameResolver::~PlatformDomainNameResolver() { } -boost::shared_ptr<DomainNameServiceQuery> PlatformDomainNameResolver::createServiceQuery(const std::string& name) { - return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(IDNA::getEncoded(name), eventLoop, this)); +boost::shared_ptr<DomainNameServiceQuery> PlatformDomainNameResolver::createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + boost::optional<std::string> encodedDomain = idnConverter->getIDNAEncoded(domain); + std::string result; + if (encodedDomain) { + result = serviceLookupPrefix + *encodedDomain; + } + return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(result, eventLoop, this)); } boost::shared_ptr<DomainNameAddressQuery> PlatformDomainNameResolver::createAddressQuery(const std::string& name) { - return boost::shared_ptr<DomainNameAddressQuery>(new PlatformDomainNameAddressQuery(IDNA::getEncoded(name), eventLoop, this)); + return boost::shared_ptr<DomainNameAddressQuery>(new PlatformDomainNameAddressQuery(idnConverter->getIDNAEncoded(name), eventLoop, this)); } diff --git a/Swiften/Network/PlatformDomainNameResolver.h b/Swiften/Network/PlatformDomainNameResolver.h index 295ecc5..6c3bf10 100644 --- a/Swiften/Network/PlatformDomainNameResolver.h +++ b/Swiften/Network/PlatformDomainNameResolver.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,4 +12,5 @@ #include <boost/thread/condition_variable.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/DomainNameResolver.h> #include <Swiften/Network/PlatformDomainNameQuery.h> @@ -18,13 +19,13 @@ namespace Swift { - + class IDNConverter; class EventLoop; - class PlatformDomainNameResolver : public DomainNameResolver { + class SWIFTEN_API PlatformDomainNameResolver : public DomainNameResolver { public: - PlatformDomainNameResolver(EventLoop* eventLoop); + PlatformDomainNameResolver(IDNConverter* idnConverter, EventLoop* eventLoop); ~PlatformDomainNameResolver(); - virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& name); + virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain); virtual DomainNameAddressQuery::ref createAddressQuery(const std::string& name); @@ -36,4 +37,5 @@ namespace Swift { friend class PlatformDomainNameServiceQuery; friend class PlatformDomainNameAddressQuery; + IDNConverter* idnConverter; EventLoop* eventLoop; bool stopRequested; diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.cpp b/Swiften/Network/PlatformDomainNameServiceQuery.cpp index b0579a7..58cf8d2 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.cpp +++ b/Swiften/Network/PlatformDomainNameServiceQuery.cpp @@ -13,4 +13,5 @@ #include <Swiften/Base/Platform.h> #include <stdlib.h> +#include <boost/numeric/conversion/cast.hpp> #ifdef SWIFTEN_PLATFORM_WINDOWS #undef UNICODE @@ -38,5 +39,9 @@ using namespace Swift; namespace Swift { -PlatformDomainNameServiceQuery::PlatformDomainNameServiceQuery(const std::string& service, EventLoop* eventLoop, PlatformDomainNameResolver* resolver) : PlatformDomainNameQuery(resolver), eventLoop(eventLoop), service(service) { +PlatformDomainNameServiceQuery::PlatformDomainNameServiceQuery(const boost::optional<std::string>& serviceName, EventLoop* eventLoop, PlatformDomainNameResolver* resolver) : PlatformDomainNameQuery(resolver), eventLoop(eventLoop), serviceValid(false) { + if (!!serviceName) { + service = *serviceName; + serviceValid = true; + } } @@ -46,4 +51,9 @@ void PlatformDomainNameServiceQuery::run() { void PlatformDomainNameServiceQuery::runBlocking() { + if (!serviceValid) { + emitError(); + return; + } + SWIFT_LOG(debug) << "Querying " << service << std::endl; @@ -122,5 +132,5 @@ void PlatformDomainNameServiceQuery::runBlocking() { return; } - record.priority = ns_get16(currentEntry); + record.priority = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; @@ -130,5 +140,5 @@ void PlatformDomainNameServiceQuery::runBlocking() { return; } - record.weight = ns_get16(currentEntry); + record.weight = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; @@ -138,5 +148,5 @@ void PlatformDomainNameServiceQuery::runBlocking() { return; } - record.port = ns_get16(currentEntry); + record.port = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.h b/Swiften/Network/PlatformDomainNameServiceQuery.h index 3372517..e105479 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.h +++ b/Swiften/Network/PlatformDomainNameServiceQuery.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { class PlatformDomainNameServiceQuery : public DomainNameServiceQuery, public PlatformDomainNameQuery, public boost::enable_shared_from_this<PlatformDomainNameServiceQuery>, public EventOwner { public: - PlatformDomainNameServiceQuery(const std::string& service, EventLoop* eventLoop, PlatformDomainNameResolver* resolver); + PlatformDomainNameServiceQuery(const boost::optional<std::string>& serviceName, EventLoop* eventLoop, PlatformDomainNameResolver* resolver); virtual void run(); @@ -30,4 +30,5 @@ namespace Swift { EventLoop* eventLoop; std::string service; + bool serviceValid; }; } diff --git a/Swiften/Network/PlatformNATTraversalWorker.cpp b/Swiften/Network/PlatformNATTraversalWorker.cpp index c962b3b..65ff577 100644 --- a/Swiften/Network/PlatformNATTraversalWorker.cpp +++ b/Swiften/Network/PlatformNATTraversalWorker.cpp @@ -9,11 +9,17 @@ #include <boost/smart_ptr/make_shared.hpp> #include <boost/enable_shared_from_this.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Log.h> +#include <Swiften/EventLoop/EventLoop.h> #include <Swiften/Network/NATTraversalGetPublicIPRequest.h> #include <Swiften/Network/NATTraversalForwardPortRequest.h> #include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> +#ifdef HAVE_LIBNATPMP #include <Swiften/Network/NATPMPInterface.h> +#endif +#ifdef HAVE_LIBMINIUPNPC #include <Swiften/Network/MiniUPnPInterface.h> +#endif namespace Swift { @@ -38,4 +44,8 @@ class PlatformNATTraversalRequest : public boost::enable_shared_from_this<Platfo } + EventLoop* getEventLoop() const { + return worker->getEventLoop(); + } + virtual void runBlocking() = 0; @@ -50,10 +60,14 @@ class PlatformNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPReq } - virtual void run() { + virtual void start() { doRun(); } + virtual void stop() { + // TODO + } + virtual void runBlocking() { - onResult(getNATTraversalInterface()->getPublicIP()); + getEventLoop()->postEvent(boost::bind(boost::ref(onResult), getNATTraversalInterface()->getPublicIP())); } }; @@ -64,10 +78,14 @@ class PlatformNATTraversalForwardPortRequest : public NATTraversalForwardPortReq } - virtual void run() { + virtual void start() { doRun(); } + virtual void stop() { + // TODO + } + virtual void runBlocking() { - onResult(getNATTraversalInterface()->addPortForward(localIP, publicIP)); + getEventLoop()->postEvent(boost::bind(boost::ref(onResult), getNATTraversalInterface()->addPortForward(boost::numeric_cast<int>(localIP), boost::numeric_cast<int>(publicIP)))); } @@ -82,10 +100,14 @@ class PlatformNATTraversalRemovePortForwardingRequest : public NATTraversalRemov } - virtual void run() { + virtual void start() { doRun(); } + virtual void stop() { + // TODO + } + virtual void runBlocking() { - onResult(getNATTraversalInterface()->removePortForward(mapping)); + getEventLoop()->postEvent(boost::bind(boost::ref(onResult), getNATTraversalInterface()->removePortForward(mapping))); } @@ -96,5 +118,6 @@ class PlatformNATTraversalRemovePortForwardingRequest : public NATTraversalRemov PlatformNATTraversalWorker::PlatformNATTraversalWorker(EventLoop* eventLoop) : eventLoop(eventLoop), stopRequested(false), natPMPSupported(boost::logic::indeterminate), natPMPInterface(NULL), miniUPnPSupported(boost::logic::indeterminate), miniUPnPInterface(NULL) { nullNATTraversalInterface = new NullNATTraversalInterface(); - thread = new boost::thread(boost::bind(&PlatformNATTraversalWorker::run, this)); + // FIXME: This should be done from start(), and the current start() should be an internal method + thread = new boost::thread(boost::bind(&PlatformNATTraversalWorker::start, this)); } @@ -104,10 +127,15 @@ PlatformNATTraversalWorker::~PlatformNATTraversalWorker() { thread->join(); delete thread; +#ifdef HAVE_LIBNATPMP delete natPMPInterface; +#endif +#ifdef HAVE_LIBMINIUPNPC delete miniUPnPInterface; +#endif delete nullNATTraversalInterface; } NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() const { +#ifdef HAVE_LIBMINIUPNPC if (boost::logic::indeterminate(miniUPnPSupported)) { miniUPnPInterface = new MiniUPnPInterface(); @@ -117,6 +145,7 @@ NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() co return miniUPnPInterface; } +#endif - +#ifdef HAVE_LIBNATPMP if (boost::logic::indeterminate(natPMPSupported)) { natPMPInterface = new NATPMPInterface(); @@ -126,4 +155,5 @@ NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() co return natPMPInterface; } +#endif return nullNATTraversalInterface; @@ -143,5 +173,5 @@ boost::shared_ptr<NATTraversalRemovePortForwardingRequest> PlatformNATTraversalW } -void PlatformNATTraversalWorker::run() { +void PlatformNATTraversalWorker::start() { while (!stopRequested) { PlatformNATTraversalRequest::ref request; @@ -162,4 +192,8 @@ void PlatformNATTraversalWorker::run() { } +void PlatformNATTraversalWorker::stop() { + // TODO +} + void PlatformNATTraversalWorker::addRequestToQueue(PlatformNATTraversalRequest::ref request) { { diff --git a/Swiften/Network/PlatformNATTraversalWorker.h b/Swiften/Network/PlatformNATTraversalWorker.h index 94d3339..91b83f8 100644 --- a/Swiften/Network/PlatformNATTraversalWorker.h +++ b/Swiften/Network/PlatformNATTraversalWorker.h @@ -14,4 +14,5 @@ #include <boost/logic/tribool.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/NATTraverser.h> #include <Swiften/Network/HostAddressPort.h> @@ -29,5 +30,5 @@ namespace Swift { class NATPortMapping; - class PlatformNATTraversalWorker : public NATTraverser { + class SWIFTEN_API PlatformNATTraversalWorker : public NATTraverser { friend class PlatformNATTraversalRequest; @@ -43,5 +44,10 @@ namespace Swift { NATTraversalInterface* getNATTraversalInterface() const; void addRequestToQueue(boost::shared_ptr<PlatformNATTraversalRequest>); - void run(); + void start(); + void stop(); + + EventLoop* getEventLoop() const { + return eventLoop; + } private: diff --git a/Swiften/Network/PlatformNetworkEnvironment.h b/Swiften/Network/PlatformNetworkEnvironment.h index c6b945e..2092bfd 100644 --- a/Swiften/Network/PlatformNetworkEnvironment.h +++ b/Swiften/Network/PlatformNetworkEnvironment.h @@ -19,4 +19,10 @@ namespace Swift { typedef WindowsNetworkEnvironment PlatformNetworkEnvironment; } +#elif defined(SWIFTEN_PLATFORM_SOLARIS) +#include <Swiften/Network/SolarisNetworkEnvironment.h> +namespace Swift { + typedef SolarisNetworkEnvironment PlatformNetworkEnvironment; +} + #else #include <Swiften/Network/UnixNetworkEnvironment.h> diff --git a/Swiften/Network/ProxiedConnection.cpp b/Swiften/Network/ProxiedConnection.cpp new file mode 100644 index 0000000..0061820 --- /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_, boost::optional<std::string>(), 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/ProxyProvider.h b/Swiften/Network/ProxyProvider.h index 0b63d51..9a1ccee 100644 --- a/Swiften/Network/ProxyProvider.h +++ b/Swiften/Network/ProxyProvider.h @@ -8,5 +8,4 @@ #include <map> -#include <Swiften/Base/Log.h> #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Base/String.h> diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index ecd7be9..284c1f4 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -2,7 +2,11 @@ Import("swiften_env") myenv = swiften_env.Clone() -myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) + +if myenv.get("unbound", False) : + myenv.MergeFlags(myenv.get("UNBOUND_FLAGS", {})) + myenv.MergeFlags(myenv.get("LDNS_FLAGS", {})) sourceList = [ + "ProxiedConnection.cpp", "HTTPConnectProxiedConnection.cpp", "HTTPConnectProxiedConnectionFactory.cpp", @@ -16,5 +20,5 @@ sourceList = [ "BOSHConnection.cpp", "BOSHConnectionPool.cpp", - "CachingNameOnlyDomainNameResolver.cpp", + "CachingDomainNameResolver.cpp", "ConnectionFactory.cpp", "ConnectionServer.cpp", @@ -31,10 +35,8 @@ sourceList = [ "DomainNameAddressQuery.cpp", "DomainNameServiceQuery.cpp", - "PlatformDomainNameResolver.cpp", - "PlatformDomainNameServiceQuery.cpp", - "PlatformDomainNameAddressQuery.cpp", "StaticDomainNameResolver.cpp", "HostAddress.cpp", "HostAddressPort.cpp", + "HostNameOrAddress.cpp", "NetworkFactories.cpp", "BoostNetworkFactories.cpp", @@ -54,5 +56,13 @@ sourceList = [ ] -if myenv["PLATFORM"] == "darwin" : +if myenv.get("unbound", False) : + myenv.Append(CPPDEFINES = "USE_UNBOUND") + sourceList.append("UnboundDomainNameResolver.cpp") +else : + sourceList.append("PlatformDomainNameResolver.cpp") + sourceList.append("PlatformDomainNameServiceQuery.cpp") + sourceList.append("PlatformDomainNameAddressQuery.cpp") + +if myenv["PLATFORM"] == "darwin" and myenv["target"] != "android": myenv.Append(FRAMEWORKS = ["CoreServices", "SystemConfiguration"]) sourceList += [ "MacOSXProxyProvider.cpp" ] @@ -61,4 +71,8 @@ elif myenv["PLATFORM"] == "win32" : sourceList += [ "WindowsProxyProvider.cpp" ] sourceList += [ "WindowsNetworkEnvironment.cpp" ] +elif myenv["PLATFORM"] == "sunos" : + sourceList += [ "UnixProxyProvider.cpp" ] + sourceList += [ "SolarisNetworkEnvironment.cpp" ] + sourceList += [ "EnvironmentProxyProvider.cpp" ] else : sourceList += [ "UnixNetworkEnvironment.cpp" ] @@ -72,8 +86,10 @@ else : objects = myenv.SwiftenObject(sourceList) -if myenv["experimental"] : +if myenv["experimental_ft"] : # LibNATPMP classes + if myenv.get("HAVE_LIBNATPMP", False) : natpmp_env = myenv.Clone() natpmp_env.Append(CPPDEFINES = natpmp_env["LIBNATPMP_FLAGS"].get("INTERNAL_CPPDEFINES", [])) + myenv.Append(CPPDEFINES = ["HAVE_LIBNATPMP"]) objects += natpmp_env.SwiftenObject([ "NATPMPInterface.cpp", @@ -81,6 +97,8 @@ if myenv["experimental"] : # LibMINIUPnP classes + if myenv.get("HAVE_LIBMINIUPNPC", False) : upnp_env = myenv.Clone() upnp_env.Append(CPPDEFINES = upnp_env["LIBMINIUPNPC_FLAGS"].get("INTERNAL_CPPDEFINES", [])) + myenv.Append(CPPDEFINES = ["HAVE_LIBMINIUPNPC"]) objects += upnp_env.SwiftenObject([ "MiniUPnPInterface.cpp", diff --git a/Swiften/Network/SOCKS5ProxiedConnection.cpp b/Swiften/Network/SOCKS5ProxiedConnection.cpp index 163e23a..3fd8184 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.cpp +++ b/Swiften/Network/SOCKS5ProxiedConnection.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + #include <Swiften/Network/SOCKS5ProxiedConnection.h> @@ -19,57 +25,15 @@ 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); +SOCKS5ProxiedConnection::SOCKS5ProxiedConnection( + DomainNameResolver* resolver, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + const std::string& proxyHost, + int proxyPort) : + ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort), + proxyState_(Initial) { } -void SOCKS5ProxiedConnection::write(const SafeByteArray& data) { - if (connection_) { - connection_->write(data); - } -} - -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; - +void SOCKS5ProxiedConnection::initializeProxy() { proxyState_ = ProxyAuthenticating; SafeByteArray socksConnect; @@ -80,16 +44,12 @@ void SOCKS5ProxiedConnection::handleConnectionConnectFinished(bool error) { // buffer.push_back(0x02); // 0x02 == Username/Password // rest see RFC 1928 (http://tools.ietf.org/html/rfc1928) - connection_->write(socksConnect); - } - else { - onConnectFinished(true); - } + 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; @@ -113,10 +73,10 @@ void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> da uc = rawAddress.to_v6().to_bytes()[s]; // the address. } - socksConnect.push_back(static_cast<char>(uc)); + socksConnect.push_back(uc); } - 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); + 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; } @@ -124,12 +84,13 @@ void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> da std::cerr << "exception caught" << std::endl; } - connection_->write(socksConnect); + write(socksConnect); break; default: - onConnectFinished(true); + setProxyInitializeFinished(true); break; } return; } + setProxyInitializeFinished(false); } else if (proxyState_ == ProxyConnecting) { @@ -152,23 +113,10 @@ void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> da if ((*data)[0] == 0x05 && (*data)[1] == 0x0) { SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl; - connected_ = true; - onConnectFinished(false); - return; + setProxyInitializeFinished(true); } else { std::cerr << "SOCKS Proxy returned an error: " << std::hex << (*data)[1] << std::endl; + setProxyInitializeFinished(false); } - return; - } - } - else { - onDataRead(data); - return; } - disconnect(); - onConnectFinished(true); -} - -HostAddressPort SOCKS5ProxiedConnection::getLocalAddress() const { - return connection_->getLocalAddress(); } diff --git a/Swiften/Network/SOCKS5ProxiedConnection.h b/Swiften/Network/SOCKS5ProxiedConnection.h index 592ce7d..2c93468 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.h +++ b/Swiften/Network/SOCKS5ProxiedConnection.h @@ -7,53 +7,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, + Initial = 0, + ProxyAuthenticating, + 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 @@ -11,9 +11,9 @@ 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 @@ -9,15 +9,22 @@ #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/SolarisNetworkEnvironment.cpp b/Swiften/Network/SolarisNetworkEnvironment.cpp new file mode 100644 index 0000000..93eec32 --- /dev/null +++ b/Swiften/Network/SolarisNetworkEnvironment.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* +* Copyright (c) 2013-2014 Remko Tronçon and Kevin Smith +* Licensed under the GNU General Public License v3. +* See Documentation/Licenses/GPLv3.txt for more information. +*/ + +#include <Swiften/Network/SolarisNetworkEnvironment.h> + +#include <string> +#include <vector> +#include <map> +#include <boost/optional.hpp> + +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/sockio.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <net/if.h> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/NetworkInterface.h> + +/* + * Copyright (c) 2006 WIDE Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#undef ifa_broadaddr +#undef ifa_dstaddr +struct ifaddrs { + struct ifaddrs *ifa_next; /* Pointer to next struct */ + char *ifa_name; /* Interface name */ + uint64_t ifa_flags; /* Interface flags */ + struct sockaddr *ifa_addr; /* Interface address */ + struct sockaddr *ifa_netmask; /* Interface netmask */ + struct sockaddr *ifa_dstaddr; /* P2P interface destination */ +}; +#define ifa_broadaddr ifa_dstaddr + +static int +get_lifreq(int fd, struct lifreq **ifr_ret) +{ + struct lifnum lifn; + struct lifconf lifc; + struct lifreq *lifrp; + + lifn.lifn_family = AF_UNSPEC; + lifn.lifn_flags = 0; + if (ioctl(fd, SIOCGLIFNUM, &lifn) == -1) + lifn.lifn_count = 16; + else + lifn.lifn_count += 16; + + for (;;) { + lifc.lifc_len = lifn.lifn_count * sizeof (*lifrp); + lifrp = (struct lifreq *) malloc(lifc.lifc_len); + if (lifrp == NULL) + return (-1); + + lifc.lifc_family = AF_UNSPEC; + lifc.lifc_flags = 0; + lifc.lifc_buf = (char *)lifrp; + if (ioctl(fd, SIOCGLIFCONF, &lifc) == -1) { + free(lifrp); + if (errno == EINVAL) { + lifn.lifn_count <<= 1; + continue; + } + (void) close(fd); + return (-1); + } + if (lifc.lifc_len < (lifn.lifn_count - 1) * sizeof (*lifrp)) + break; + free(lifrp); + lifn.lifn_count <<= 1; + } + (void) close(fd); + + *ifr_ret = lifrp; + + return (lifc.lifc_len / sizeof (*lifrp)); +} + +static size_t +nbytes(const struct lifreq *lifrp, int nlif, size_t socklen) +{ + size_t len = 0; + size_t slen; + + while (nlif > 0) { + slen = strlen(lifrp->lifr_name) + 1; + len += sizeof (struct ifaddrs) + ((slen + 3) & ~3); + len += 3 * socklen; + lifrp++; + nlif--; + } + return (len); +} + +static struct sockaddr * +addrcpy(struct sockaddr_storage *addr, char **bufp) +{ + char *buf = *bufp; + size_t len; + + len = addr->ss_family == AF_INET ? sizeof (struct sockaddr_in) : + sizeof (struct sockaddr_in6); + (void) memcpy(buf, addr, len); + *bufp = buf + len; + return ((struct sockaddr *)buf); +} + +static int +populate(struct ifaddrs *ifa, int fd, struct lifreq *lifrp, int nlif, int af, + char **bufp) +{ + char *buf = *bufp; + size_t slen; + + while (nlif > 0) { + ifa->ifa_next = (nlif > 1) ? ifa + 1 : NULL; + (void) strcpy(ifa->ifa_name = buf, lifrp->lifr_name); + slen = strlen(lifrp->lifr_name) + 1; + buf += (slen + 3) & ~3; + if (ioctl(fd, SIOCGLIFFLAGS, lifrp) == -1) + ifa->ifa_flags = 0; + else + ifa->ifa_flags = lifrp->lifr_flags; + if (ioctl(fd, SIOCGLIFADDR, lifrp) == -1) + ifa->ifa_addr = NULL; + else + ifa->ifa_addr = addrcpy(&lifrp->lifr_addr, &buf); + if (ioctl(fd, SIOCGLIFNETMASK, lifrp) == -1) + ifa->ifa_netmask = NULL; + else + ifa->ifa_netmask = addrcpy(&lifrp->lifr_addr, &buf); + if (ifa->ifa_flags & IFF_POINTOPOINT) { + if (ioctl(fd, SIOCGLIFDSTADDR, lifrp) == -1) + ifa->ifa_dstaddr = NULL; + else + ifa->ifa_dstaddr = + addrcpy(&lifrp->lifr_dstaddr, &buf); + } else if (ifa->ifa_flags & IFF_BROADCAST) { + if (ioctl(fd, SIOCGLIFBRDADDR, lifrp) == -1) + ifa->ifa_broadaddr = NULL; + else + ifa->ifa_broadaddr = + addrcpy(&lifrp->lifr_broadaddr, &buf); + } else { + ifa->ifa_dstaddr = NULL; + } + + ifa++; + nlif--; + lifrp++; + } + *bufp = buf; + return (0); +} + +static int +getifaddrs(struct ifaddrs **ifap) +{ + int fd4, fd6; + int nif4, nif6 = 0; + struct lifreq *ifr4 = NULL; + struct lifreq *ifr6 = NULL; + struct ifaddrs *ifa = NULL; + char *buf; + + if ((fd4 = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + return (-1); + if ((fd6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1 && + errno != EAFNOSUPPORT) { + (void) close(fd4); + return (-1); + } + + if ((nif4 = get_lifreq(fd4, &ifr4)) == -1 || + (fd6 != -1 && (nif6 = get_lifreq(fd6, &ifr6)) == -1)) + goto failure; + + if (nif4 == 0 && nif6 == 0) { + *ifap = NULL; + return (0); + } + + ifa = (struct ifaddrs *) malloc(nbytes(ifr4, nif4, sizeof (struct sockaddr_in)) + + nbytes(ifr6, nif6, sizeof (struct sockaddr_in6))); + if (ifa == NULL) + goto failure; + + buf = (char *)(ifa + nif4 + nif6); + + if (populate(ifa, fd4, ifr4, nif4, AF_INET, &buf) == -1) + goto failure; + if (nif4 > 0 && nif6 > 0) + ifa[nif4 - 1].ifa_next = ifa + nif4; + if (populate(ifa + nif4, fd6, ifr6, nif6, AF_INET6, &buf) == -1) + goto failure; + + return (0); + +failure: + free(ifa); + (void) close(fd4); + if (fd6 != -1) + (void) close(fd6); + free(ifr4); + free(ifr6); + return (-1); +} + +static void +freeifaddrs(struct ifaddrs *ifa) +{ + free(ifa); +} + +/* End WIDE Project code */ + +namespace Swift { + +std::vector<NetworkInterface> SolarisNetworkEnvironment::getNetworkInterfaces() const { + std::map<std::string, NetworkInterface> interfaces; + + ifaddrs* addrs = 0; + int ret = getifaddrs(&addrs); + if (ret != 0) { + return std::vector<NetworkInterface>(); + } + + for (ifaddrs* a = addrs; a != 0; a = a->ifa_next) { + std::string name(a->ifa_name); + boost::optional<HostAddress> address; + if (a->ifa_addr->sa_family == PF_INET) { + sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(a->ifa_addr); + address = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin_addr)), 4); + } + else if (a->ifa_addr->sa_family == PF_INET6) { + sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(a->ifa_addr); + address = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); + } + if (address) { + std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, a->ifa_flags & IFF_LOOPBACK))).first; + i->second.addAddress(*address); + } + } + + freeifaddrs(addrs); + + std::vector<NetworkInterface> result; + for (std::map<std::string,NetworkInterface>::const_iterator i = interfaces.begin(); i != interfaces.end(); ++i) { + result.push_back(i->second); + } + return result; +} + +} diff --git a/Swiften/Network/SolarisNetworkEnvironment.h b/Swiften/Network/SolarisNetworkEnvironment.h new file mode 100644 index 0000000..7481ff4 --- /dev/null +++ b/Swiften/Network/SolarisNetworkEnvironment.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* +* Copyright (c) 2013-2014 Remko Tronçon and 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/boost_bsignals.h> + +#include <Swiften/Network/NetworkEnvironment.h> +#include <Swiften/Network/NetworkInterface.h> + +namespace Swift { + + class SolarisNetworkEnvironment : public NetworkEnvironment { + public: + std::vector<NetworkInterface> getNetworkInterfaces() const; + }; + +} diff --git a/Swiften/Network/StaticDomainNameResolver.cpp b/Swiften/Network/StaticDomainNameResolver.cpp index ee18ee5..17d9c3b 100644 --- a/Swiften/Network/StaticDomainNameResolver.cpp +++ b/Swiften/Network/StaticDomainNameResolver.cpp @@ -109,6 +109,6 @@ void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, c } -boost::shared_ptr<DomainNameServiceQuery> StaticDomainNameResolver::createServiceQuery(const std::string& name) { - return boost::shared_ptr<DomainNameServiceQuery>(new ServiceQuery(name, this, eventLoop, owner)); +boost::shared_ptr<DomainNameServiceQuery> StaticDomainNameResolver::createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + return boost::shared_ptr<DomainNameServiceQuery>(new ServiceQuery(serviceLookupPrefix + domain, this, eventLoop, owner)); } diff --git a/Swiften/Network/StaticDomainNameResolver.h b/Swiften/Network/StaticDomainNameResolver.h index 29d1629..81ff040 100644 --- a/Swiften/Network/StaticDomainNameResolver.h +++ b/Swiften/Network/StaticDomainNameResolver.h @@ -10,4 +10,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Network/HostAddress.h> #include <Swiften/Network/HostAddressPort.h> @@ -18,5 +19,5 @@ namespace Swift { - class StaticDomainNameResolver : public DomainNameResolver { + class SWIFTEN_API StaticDomainNameResolver : public DomainNameResolver { public: typedef std::map<std::string, std::vector<HostAddress> > AddressesMap; @@ -48,5 +49,5 @@ namespace Swift { } - virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& name); + virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain); virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name); private: diff --git a/Swiften/Network/TLSConnection.h b/Swiften/Network/TLSConnection.h index a798393..60f73ea 100644 --- a/Swiften/Network/TLSConnection.h +++ b/Swiften/Network/TLSConnection.h @@ -25,5 +25,5 @@ namespace Swift { virtual ~TLSConnection(); - virtual void listen() {assert(false);}; + virtual void listen() {assert(false);} virtual void connect(const HostAddressPort& address); virtual void disconnect(); diff --git a/Swiften/Network/Timer.h b/Swiften/Network/Timer.h index b7578f2..d08cf3c 100644 --- a/Swiften/Network/Timer.h +++ b/Swiften/Network/Timer.h @@ -8,4 +8,5 @@ #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> namespace Swift { @@ -13,5 +14,5 @@ namespace Swift { * A class for triggering an event after a given period. */ - class Timer { + class SWIFTEN_API Timer { public: typedef boost::shared_ptr<Timer> ref; diff --git a/Swiften/Network/TimerFactory.h b/Swiften/Network/TimerFactory.h index 99903c3..62850bc 100644 --- a/Swiften/Network/TimerFactory.h +++ b/Swiften/Network/TimerFactory.h @@ -9,8 +9,9 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Timer.h> namespace Swift { - class TimerFactory { + class SWIFTEN_API TimerFactory { public: virtual ~TimerFactory(); diff --git a/Swiften/Network/UnboundDomainNameResolver.cpp b/Swiften/Network/UnboundDomainNameResolver.cpp new file mode 100755 index 0000000..bc280eb --- /dev/null +++ b/Swiften/Network/UnboundDomainNameResolver.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "UnboundDomainNameResolver.h" + +#include <vector> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Network/DomainNameResolveError.h> +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/TimerFactory.h> + +#include <arpa/inet.h> +#include <unbound.h> +#include <ldns/ldns.h> +#include <unistd.h> + +namespace Swift { + +class UnboundQuery { + public: + UnboundQuery(UnboundDomainNameResolver* resolver, ub_ctx* context) : resolver(resolver), ubContext(context) {} + virtual ~UnboundQuery() {} + virtual void handleResult(int err, ub_result* result) = 0; + protected: + UnboundDomainNameResolver* resolver; + ub_ctx* ubContext; +}; + +struct UnboundWrapperHelper { + UnboundWrapperHelper(UnboundDomainNameResolver* resolver, boost::shared_ptr<UnboundQuery> query) : resolver(resolver), query(query) {} + UnboundDomainNameResolver* resolver; + boost::shared_ptr<UnboundQuery> query; +}; + +class UnboundDomainNameServiceQuery : public DomainNameServiceQuery, public UnboundQuery, public boost::enable_shared_from_this<UnboundDomainNameServiceQuery> { + public: + UnboundDomainNameServiceQuery(UnboundDomainNameResolver* resolver, ub_ctx* context, std::string name) : UnboundQuery(resolver, context), name(name) { + } + + virtual ~UnboundDomainNameServiceQuery() { } + + virtual void run() { + int retval; + UnboundWrapperHelper* helper = new UnboundWrapperHelper(resolver, shared_from_this()); + + retval = ub_resolve_async(ubContext, const_cast<char*>(name.c_str()), LDNS_RR_TYPE_SRV, + 1 /* CLASS IN (internet) */, + helper, UnboundDomainNameResolver::unbound_callback_wrapper, NULL); + if(retval != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + delete helper; + } + } + + void handleResult(int err, struct ub_result* result) { + std::vector<DomainNameServiceQuery::Result> serviceRecords; + + if(err != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + } else { + if(result->havedata) { + ldns_pkt* replyPacket = 0; + ldns_buffer* buffer = ldns_buffer_new(1024); + if (buffer && ldns_wire2pkt(&replyPacket, static_cast<const uint8_t*>(result->answer_packet), result->answer_len) == LDNS_STATUS_OK) { + ldns_rr_list* rrList = ldns_pkt_answer(replyPacket); + for (size_t n = 0; n < ldns_rr_list_rr_count(rrList); n++) { + ldns_rr* rr = ldns_rr_list_rr(rrList, n); + if ((ldns_rr_get_type(rr) != LDNS_RR_TYPE_SRV) || + (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) || + (ldns_rr_rd_count(rr) != 4)) { + continue; + } + + DomainNameServiceQuery::Result serviceRecord; + serviceRecord.priority = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0)); + serviceRecord.weight = ldns_rdf2native_int16(ldns_rr_rdf(rr, 1)); + serviceRecord.port = ldns_rdf2native_int16(ldns_rr_rdf(rr, 2)); + + ldns_buffer_rewind(buffer); + if ((ldns_rdf2buffer_str_dname(buffer, ldns_rr_rdf(rr, 3)) != LDNS_STATUS_OK) || + (ldns_buffer_position(buffer) < 2) || + !ldns_buffer_reserve(buffer, 1)) { + // either name invalid, empty or buffer to small + continue; + } + char terminator = 0; + ldns_buffer_write(buffer, &terminator, sizeof(terminator)); + + serviceRecord.hostname = std::string(reinterpret_cast<char*>(ldns_buffer_at(buffer, 0))); + serviceRecords.push_back(serviceRecord); + SWIFT_LOG(debug) << "hostname " << serviceRecord.hostname << " added" << std::endl; + } + } + if (replyPacket) ldns_pkt_free(replyPacket); + if (buffer) ldns_buffer_free(buffer); + } + } + + ub_resolve_free(result); + onResult(serviceRecords); + } + + private: + std::string name; +}; + +class UnboundDomainNameAddressQuery : public DomainNameAddressQuery, public UnboundQuery, public boost::enable_shared_from_this<UnboundDomainNameAddressQuery> { + public: + UnboundDomainNameAddressQuery(UnboundDomainNameResolver* resolver, ub_ctx* context, std::string name) : UnboundQuery(resolver, context), name(name) { + } + + virtual ~UnboundDomainNameAddressQuery() { } + + virtual void run() { + int retval; + UnboundWrapperHelper* helper = new UnboundWrapperHelper(resolver, shared_from_this()); + + //FIXME: support AAAA queries in some way + retval = ub_resolve_async(ubContext, const_cast<char*>(name.c_str()), LDNS_RR_TYPE_A, + 1 /* CLASS IN (internet) */, + helper, UnboundDomainNameResolver::unbound_callback_wrapper, NULL); + if(retval != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + delete helper; + } + } + + void handleResult(int err, struct ub_result* result) { + std::vector<HostAddress> addresses; + boost::optional<DomainNameResolveError> error; + SWIFT_LOG(debug) << "Result for: " << name << std::endl; + + if(err != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + error = DomainNameResolveError(); + } else { + if(result->havedata) { + for(int i=0; result->data[i]; i++) { + char address[100]; + const char* addressStr = 0; + if ((addressStr = inet_ntop(AF_INET, result->data[i], address, 100))) { + SWIFT_LOG(debug) << "IPv4 address: " << addressStr << std::endl; + addresses.push_back(HostAddress(std::string(addressStr))); + } else if ((addressStr = inet_ntop(AF_INET6, result->data[i], address, 100))) { + SWIFT_LOG(debug) << "IPv6 address: " << addressStr << std::endl; + addresses.push_back(HostAddress(std::string(addressStr))); + } else { + SWIFT_LOG(debug) << "inet_ntop() failed" << std::endl; + error = DomainNameResolveError(); + } + } + } else { + error = DomainNameResolveError(); + } + } + + ub_resolve_free(result); + onResult(addresses, error); + } + + private: + std::string name; +}; + +UnboundDomainNameResolver::UnboundDomainNameResolver(IDNConverter* idnConverter, boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : idnConverter(idnConverter), ioService(ioService), ubDescriptior(*ioService), eventLoop(eventLoop) { + ubContext = ub_ctx_create(); + if(!ubContext) { + SWIFT_LOG(debug) << "could not create unbound context" << std::endl; + } + eventOwner = boost::make_shared<EventOwner>(); + + ub_ctx_async(ubContext, true); + + int ret; + + /* read /etc/resolv.conf for DNS proxy settings (from DHCP) */ + if( (ret=ub_ctx_resolvconf(ubContext, const_cast<char*>("/etc/resolv.conf"))) != 0) { + SWIFT_LOG(error) << "error reading resolv.conf: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + } + /* read /etc/hosts for locally supplied host addresses */ + if( (ret=ub_ctx_hosts(ubContext, const_cast<char*>("/etc/hosts"))) != 0) { + SWIFT_LOG(error) << "error reading hosts: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + } + + ubDescriptior.assign(ub_fd(ubContext)); + + ubDescriptior.async_read_some(boost::asio::null_buffers(), boost::bind(&UnboundDomainNameResolver::handleUBSocketReadable, this, boost::asio::placeholders::error)); +} + +UnboundDomainNameResolver::~UnboundDomainNameResolver() { + eventLoop->removeEventsFromOwner(eventOwner); + if (ubContext) { + ub_ctx_delete(ubContext); + } +} + +void UnboundDomainNameResolver::unbound_callback(boost::shared_ptr<UnboundQuery> query, int err, ub_result* result) { + query->handleResult(err, result); +} + +void UnboundDomainNameResolver::unbound_callback_wrapper(void* data, int err, ub_result* result) { + UnboundWrapperHelper* helper = static_cast<UnboundWrapperHelper*>(data); + UnboundDomainNameResolver* resolver = helper->resolver; + resolver->unbound_callback(helper->query, err, result); + delete helper; +} + +void UnboundDomainNameResolver::handleUBSocketReadable(boost::system::error_code) { + eventLoop->postEvent(boost::bind(&UnboundDomainNameResolver::processData, this), eventOwner); + ubDescriptior.async_read_some(boost::asio::null_buffers(), boost::bind(&UnboundDomainNameResolver::handleUBSocketReadable, this, boost::asio::placeholders::error)); +} + +void UnboundDomainNameResolver::processData() { + if (ub_poll(ubContext)) { + int ret = ub_process(ubContext); + if(ret != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; + } + } +} + +boost::shared_ptr<DomainNameServiceQuery> UnboundDomainNameResolver::createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + boost::optional<std::string> encodedDomain = idnConverter->getIDNAEncoded(domain); + std::string result; + if (encodedDomain) { + result = serviceLookupPrefix + *encodedDomain; + } + return boost::make_shared<UnboundDomainNameServiceQuery>(this, ubContext, result); +} + +boost::shared_ptr<DomainNameAddressQuery> UnboundDomainNameResolver::createAddressQuery(const std::string& name) { + return boost::make_shared<UnboundDomainNameAddressQuery>(this, ubContext, idnConverter->getIDNAEncoded(name).get_value_or("")); +} + +} diff --git a/Swiften/Network/UnboundDomainNameResolver.h b/Swiften/Network/UnboundDomainNameResolver.h new file mode 100755 index 0000000..6b78cf3 --- /dev/null +++ b/Swiften/Network/UnboundDomainNameResolver.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/DomainNameResolver.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/EventLoop/EventOwner.h> + +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio.hpp> + +struct ub_ctx; +struct ub_result; + +namespace Swift { + class EventLoop; + class IDNConverter; + class TimerFactory; + + class UnboundDomainNameResolver; + class UnboundQuery; + + class UnboundDomainNameResolver : public DomainNameResolver, public EventOwner, public boost::enable_shared_from_this<UnboundDomainNameResolver> { + public: + UnboundDomainNameResolver(IDNConverter* idnConverter, boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop); + virtual ~UnboundDomainNameResolver(); + + virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain); + virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name); + + static void unbound_callback_wrapper(void* data, int err, ub_result* result); + + private: + void unbound_callback(boost::shared_ptr<UnboundQuery> query, int err, ub_result* result); + + void handleUBSocketReadable(boost::system::error_code); + void processData(); + + private: + IDNConverter* idnConverter; + boost::shared_ptr<EventOwner> eventOwner; + boost::shared_ptr<boost::asio::io_service> ioService; + boost::asio::posix::stream_descriptor ubDescriptior; + EventLoop* eventLoop; + ub_ctx* ubContext; + }; + +} diff --git a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp index 82762c5..8a63fcb 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp @@ -48,5 +48,5 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { void setUp() { to = "wonderland.lit"; - path = "http-bind"; + path = "/http-bind"; port = "5280"; sid = "MyShinySID"; @@ -171,5 +171,5 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { boost::shared_ptr<MockConnection> c0; boost::shared_ptr<MockConnection> c1; - long rid = initialRID; + unsigned long long rid = initialRID; PoolRef testling = createTestling(); @@ -237,5 +237,5 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { to = "prosody.doomsong.co.uk"; resolver->addAddress("prosody.doomsong.co.uk", HostAddress("127.0.0.1")); - path = "http-bind/"; + path = "/http-bind/"; boshURL = URL("http", to, 5280, path); @@ -275,4 +275,22 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); + + testling->restartStream(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); + CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); + + response = "<body 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><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><required/></bind><session xmlns='urn:ietf:params:xml:ns:xmpp-session'><optional/></session><sm xmlns='urn:xmpp:sm:2'><optional/></sm></stream:features></body>"; + readResponse(response, connectionFactory->connections[0]); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(st(5), boshDataWritten.size()); /* Now we've authed (restarted) we should be keeping one query in flight so the server can reply to us at any time it wants. */ + CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); + + send = "<body rid='2821988967416214' sid='cf663f6b94279d4f' xmlns='http://jabber.org/protocol/httpbind'><iq id='session-bind' type='set'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>d5a9744036cd20a0</resource></bind></iq></body>"; + testling->write(createSafeByteArray(send)); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(st(6), boshDataWritten.size()); + CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); /* and as it keeps one in flight, it's needed to open a second to send these data */ + } @@ -444,5 +462,5 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { std::string sid; std::string initial; - long initialRID; + unsigned long long initialRID; int sessionStarted; int sessionTerminated; diff --git a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp index e0dc0bf..0d06420 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp @@ -108,5 +108,5 @@ class BOSHConnectionTest : public CppUnit::TestFixture { testling->setSID("mySID"); CPPUNIT_ASSERT(testling->isReadyToSend()); - connectionFactory->connections[0]->onDisconnected(false); + connectionFactory->connections[0]->onDisconnected(boost::optional<Connection::Error>()); CPPUNIT_ASSERT(!testling->isReadyToSend()); } @@ -193,6 +193,6 @@ 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); - BOSHConnection::ref c = BOSHConnection::create(URL("http", "wonderland.lit", 5280, "http-bind"), connector, &parserFactory); + Connector::ref connector = Connector::create("wonderland.lit", 5280, boost::optional<std::string>(), 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..9176fe7 100644 --- a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp @@ -127,5 +127,5 @@ class ChainedConnectorTest : public CppUnit::TestFixture { 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, boost::optional<std::string>("_xmpp-client._tcp."), 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..3b1d4e4 100644 --- a/Swiften/Network/UnitTest/ConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ConnectorTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -25,4 +25,6 @@ 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); @@ -32,6 +34,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST(testConnect_AllSRVHostsFailWithFallbackHost); CPPUNIT_TEST(testConnect_SRVAndFallbackHostsFail); - CPPUNIT_TEST(testConnect_TimeoutDuringResolve); - CPPUNIT_TEST(testConnect_TimeoutDuringConnect); + //CPPUNIT_TEST(testConnect_TimeoutDuringResolve); + CPPUNIT_TEST(testConnect_TimeoutDuringConnectToOnlyCandidate); + CPPUNIT_TEST(testConnect_TimeoutDuringConnectToCandidateFallsBack); CPPUNIT_TEST(testConnect_NoTimeout); CPPUNIT_TEST(testStop_DuringSRVQuery); @@ -72,4 +75,36 @@ class ConnectorTest : public CppUnit::TestFixture { } + void testConnect_NoServiceLookups() { + Connector::ref testling(createConnector(4321, boost::optional<std::string>())); + 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, boost::optional<std::string>())); + 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()); @@ -176,5 +211,5 @@ class ConnectorTest : public CppUnit::TestFixture { } - void testConnect_TimeoutDuringResolve() { + /*void testConnect_TimeoutDuringResolve() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); @@ -189,7 +224,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); CPPUNIT_ASSERT(!connections[0]); - } + }*/ - void testConnect_TimeoutDuringConnect() { + void testConnect_TimeoutDuringConnectToOnlyCandidate() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); @@ -207,4 +242,28 @@ class ConnectorTest : public CppUnit::TestFixture { } + void testConnect_TimeoutDuringConnectToCandidateFallsBack() { + Connector::ref testling(createConnector()); + testling->setTimeoutMilliseconds(10); + + resolver->addXMPPClientService("foo.com", "host-foo.com", 1234); + HostAddress address1("1.1.1.1"); + resolver->addAddress("host-foo.com", address1); + HostAddress address2("2.2.2.2"); + resolver->addAddress("host-foo.com", address2); + + connectionFactory->isResponsive = false; + testling->start(); + eventLoop->processEvents(); + connectionFactory->isResponsive = true; + timerFactory->setTime(10); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(HostAddressPort(address2, 1234) == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); + } + + void testConnect_NoTimeout() { Connector::ref testling(createConnector()); @@ -254,6 +313,6 @@ 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, boost::optional<std::string> serviceLookupPrefix = boost::optional<std::string>("_xmpp-client._tcp.")) { + Connector::ref connector = Connector::create("foo.com", port, serviceLookupPrefix, 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 @@ -171,5 +171,5 @@ 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)); diff --git a/Swiften/Network/UnixNetworkEnvironment.cpp b/Swiften/Network/UnixNetworkEnvironment.cpp index 52c5cbe..e1fdc88 100644 --- a/Swiften/Network/UnixNetworkEnvironment.cpp +++ b/Swiften/Network/UnixNetworkEnvironment.cpp @@ -15,5 +15,8 @@ #include <arpa/inet.h> #include <net/if.h> + +#ifndef __ANDROID__ #include <ifaddrs.h> +#endif #include <Swiften/Base/boost_bsignals.h> @@ -25,5 +28,5 @@ namespace Swift { std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() const { std::map<std::string, NetworkInterface> interfaces; - +#ifndef __ANDROID__ ifaddrs* addrs = 0; int ret = getifaddrs(&addrs); @@ -43,5 +46,5 @@ std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() con address = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); } - if (address) { + if (address && !address->isLocalhost()) { std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, a->ifa_flags & IFF_LOOPBACK))).first; i->second.addAddress(*address); @@ -50,5 +53,5 @@ std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() con freeifaddrs(addrs); - +#endif std::vector<NetworkInterface> result; for (std::map<std::string,NetworkInterface>::const_iterator i = interfaces.begin(); i != interfaces.end(); ++i) { diff --git a/Swiften/Network/WindowsNetworkEnvironment.cpp b/Swiften/Network/WindowsNetworkEnvironment.cpp index 20f559d..e2d1966 100644 --- a/Swiften/Network/WindowsNetworkEnvironment.cpp +++ b/Swiften/Network/WindowsNetworkEnvironment.cpp @@ -51,5 +51,5 @@ std::vector<NetworkInterface> WindowsNetworkEnvironment::getNetworkInterfaces() hostAddress = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); } - if (hostAddress) { + if (hostAddress && !hostAddress->isLocalhost()) { std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, false))).first; i->second.addAddress(*hostAddress); diff --git a/Swiften/Network/WindowsNetworkEnvironment.h b/Swiften/Network/WindowsNetworkEnvironment.h index f43b951..18996ed 100644 --- a/Swiften/Network/WindowsNetworkEnvironment.h +++ b/Swiften/Network/WindowsNetworkEnvironment.h @@ -8,10 +8,11 @@ #include <vector> -#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/NetworkEnvironment.h> namespace Swift { - class WindowsNetworkEnvironment : public NetworkEnvironment { + class SWIFTEN_API WindowsNetworkEnvironment : public NetworkEnvironment { public: std::vector<NetworkInterface> getNetworkInterfaces() const; diff --git a/Swiften/Network/WindowsProxyProvider.h b/Swiften/Network/WindowsProxyProvider.h index c2d1f51..12aa18d 100644 --- a/Swiften/Network/WindowsProxyProvider.h +++ b/Swiften/Network/WindowsProxyProvider.h @@ -6,8 +6,10 @@ #pragma once + +#include <Swiften/Base/API.h> #include <Swiften/Network/ProxyProvider.h> namespace Swift { - class WindowsProxyProvider : public ProxyProvider { + class SWIFTEN_API WindowsProxyProvider : public ProxyProvider { public: WindowsProxyProvider(); |