diff options
| author | Tobias Markmann <tm@ayena.de> | 2015-10-07 21:57:17 (GMT) | 
|---|---|---|
| committer | Tobias Markmann <tm@ayena.de> | 2015-10-07 21:57:17 (GMT) | 
| commit | df5bfad6f032b17ee0dffe85cdaadc2c20edaae2 (patch) | |
| tree | 5b5166d0aeae60ab78d75528adeea8ef620cd7bd | |
| parent | 37aafcb4d693a0b4f5944a52e0c070e5aa384245 (diff) | |
| download | swift-df5bfad6f032b17ee0dffe85cdaadc2c20edaae2.zip swift-df5bfad6f032b17ee0dffe85cdaadc2c20edaae2.tar.bz2 | |
Fix hang during file-transfer preparation with missing proxy
The code used to call the onProxiesFound signal only if a
proxy was found. In case of missing S5B proxy at the users
server, the file-transfer preparation would hang.
Now the code wants until the discovery phase is done and then
calls the onProxiesFound signal with the list of discovered
proxies. In case of missing S5B proxy server the signal is
called with an empty list so the file-transfer flow can
continue.
Test-Information:
Ran FileTransferTest integration test and manually tested a
file-transfer on a server without S5B proxy.
Change-Id: I31d3cc08fe6453b5cdfe6be286f884a920470d28
4 files changed, 54 insertions, 27 deletions
| diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp index 1036e12..25a12ea 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp | |||
| @@ -110,25 +110,24 @@ boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager: | |||
| 110 | boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { | 110 | boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { | 
| 111 | SOCKS5BytestreamClientSession::ref connection = boost::make_shared<SOCKS5BytestreamClientSession>(connectionFactory_->createConnection(), addressPort, destAddr, timerFactory_); | 111 | SOCKS5BytestreamClientSession::ref connection = boost::make_shared<SOCKS5BytestreamClientSession>(connectionFactory_->createConnection(), addressPort, destAddr, timerFactory_); | 
| 112 | return connection; | 112 | return connection; | 
| 113 | } | 113 | } | 
| 114 | 114 | ||
| 115 | void SOCKS5BytestreamProxiesManager::handleProxyFound(S5BProxyRequest::ref proxy) { | 115 | void SOCKS5BytestreamProxiesManager::handleProxiesFound(std::vector<S5BProxyRequest::ref> proxyHosts) { | 
| 116 | if (proxy) { | 116 | foreach(S5BProxyRequest::ref proxy, proxyHosts) { | 
| 117 | if (HostAddress(proxy->getStreamHost().get().host).isValid()) { | 117 | if (proxy) { | 
| 118 | addS5BProxy(proxy); | 118 | if (HostAddress(proxy->getStreamHost().get().host).isValid()) { | 
| 119 | onDiscoveredProxiesChanged(); | 119 | addS5BProxy(proxy); | 
| 120 | } | 120 | onDiscoveredProxiesChanged(); | 
| 121 | else { | 121 | } | 
| 122 | DomainNameAddressQuery::ref resolveRequest = resolver_->createAddressQuery(proxy->getStreamHost().get().host); | 122 | else { | 
| 123 | resolveRequest->onResult.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleNameLookupResult, this, _1, _2, proxy)); | 123 | DomainNameAddressQuery::ref resolveRequest = resolver_->createAddressQuery(proxy->getStreamHost().get().host); | 
| 124 | resolveRequest->run(); | 124 | resolveRequest->onResult.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleNameLookupResult, this, _1, _2, proxy)); | 
| 125 | resolveRequest->run(); | ||
| 126 | } | ||
| 125 | } | 127 | } | 
| 126 | } | 128 | } | 
| 127 | else { | ||
| 128 | onDiscoveredProxiesChanged(); | ||
| 129 | } | ||
| 130 | proxyFinder_->stop(); | 129 | proxyFinder_->stop(); | 
| 131 | proxyFinder_.reset(); | 130 | proxyFinder_.reset(); | 
| 132 | } | 131 | } | 
| 133 | 132 | ||
| 134 | void SOCKS5BytestreamProxiesManager::handleNameLookupResult(const std::vector<HostAddress>& addresses, boost::optional<DomainNameResolveError> error, S5BProxyRequest::ref proxy) { | 133 | void SOCKS5BytestreamProxiesManager::handleNameLookupResult(const std::vector<HostAddress>& addresses, boost::optional<DomainNameResolveError> error, S5BProxyRequest::ref proxy) { | 
| @@ -155,16 +154,16 @@ void SOCKS5BytestreamProxiesManager::handleNameLookupResult(const std::vector<Ho | |||
| 155 | } | 154 | } | 
| 156 | 155 | ||
| 157 | void SOCKS5BytestreamProxiesManager::queryForProxies() { | 156 | void SOCKS5BytestreamProxiesManager::queryForProxies() { | 
| 158 | proxyFinder_ = boost::make_shared<SOCKS5BytestreamProxyFinder>(serviceRoot_, iqRouter_); | 157 | proxyFinder_ = boost::make_shared<SOCKS5BytestreamProxyFinder>(serviceRoot_, iqRouter_); | 
| 159 | 158 | ||
| 160 | proxyFinder_->onProxyFound.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxyFound, this, _1)); | 159 | proxyFinder_->onProxiesFound.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxiesFound, this, _1)); | 
| 161 | proxyFinder_->start(); | 160 | proxyFinder_->start(); | 
| 162 | } | 161 | } | 
| 163 | 162 | ||
| 164 | void SOCKS5BytestreamProxiesManager::handleProxySessionReady(const std::string& sessionID, const JID& jid, boost::shared_ptr<SOCKS5BytestreamClientSession> session, bool error) { | 163 | void SOCKS5BytestreamProxiesManager::handleProxySessionReady(const std::string& sessionID, const JID& jid, boost::shared_ptr<SOCKS5BytestreamClientSession> session, bool error) { | 
| 165 | session->onSessionReady.disconnect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionFinished, this, boost::cref(sessionID), boost::cref(jid), session, _1)); | 164 | session->onSessionReady.disconnect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionReady, this, boost::cref(sessionID), boost::cref(jid), session, _1)); | 
| 166 | if (!error) { | 165 | if (!error) { | 
| 167 | // The SOCKS5 bytestream session to the proxy succeeded; stop and remove other sessions. | 166 | // The SOCKS5 bytestream session to the proxy succeeded; stop and remove other sessions. | 
| 168 | if (proxySessions_.find(sessionID) != proxySessions_.end()) { | 167 | if (proxySessions_.find(sessionID) != proxySessions_.end()) { | 
| 169 | for (ProxyJIDClientSessionVector::iterator i = proxySessions_[sessionID].begin(); i != proxySessions_[sessionID].end();) { | 168 | for (ProxyJIDClientSessionVector::iterator i = proxySessions_[sessionID].begin(); i != proxySessions_[sessionID].end();) { | 
| 170 | if ((i->first == jid) && (i->second != session)) { | 169 | if ((i->first == jid) && (i->second != session)) { | 
| diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h index e4bf1d9..c7daee7 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h | |||
| @@ -27,10 +27,11 @@ | |||
| 27 | namespace Swift { | 27 | namespace Swift { | 
| 28 | class TimerFactory; | 28 | class TimerFactory; | 
| 29 | class ConnectionFactory; | 29 | class ConnectionFactory; | 
| 30 | class DomainNameResolver; | 30 | class DomainNameResolver; | 
| 31 | class DomainNameResolveError; | 31 | class DomainNameResolveError; | 
| 32 | class IQRouter; | ||
| 32 | 33 | ||
| 33 | /** | 34 | /** | 
| 34 | * - manages list of working S5B proxies | 35 | * - manages list of working S5B proxies | 
| 35 | * - creates initial connections (for the candidates you provide) | 36 | * - creates initial connections (for the candidates you provide) | 
| 36 | */ | 37 | */ | 
| @@ -54,11 +55,11 @@ namespace Swift { | |||
| 54 | 55 | ||
| 55 | public: | 56 | public: | 
| 56 | boost::signal<void ()> onDiscoveredProxiesChanged; | 57 | boost::signal<void ()> onDiscoveredProxiesChanged; | 
| 57 | 58 | ||
| 58 | private: | 59 | private: | 
| 59 | void handleProxyFound(S5BProxyRequest::ref proxy); | 60 | void handleProxiesFound(std::vector<S5BProxyRequest::ref> proxyHosts); | 
| 60 | void handleNameLookupResult(const std::vector<HostAddress>&, boost::optional<DomainNameResolveError>, S5BProxyRequest::ref proxy); | 61 | void handleNameLookupResult(const std::vector<HostAddress>&, boost::optional<DomainNameResolveError>, S5BProxyRequest::ref proxy); | 
| 61 | 62 | ||
| 62 | void queryForProxies(); | 63 | void queryForProxies(); | 
| 63 | 64 | ||
| 64 | void handleProxySessionReady(const std::string& sessionID, const JID& jid, boost::shared_ptr<SOCKS5BytestreamClientSession> session, bool error); | 65 | void handleProxySessionReady(const std::string& sessionID, const JID& jid, boost::shared_ptr<SOCKS5BytestreamClientSession> session, bool error); | 
| diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp index 9d7505b..78cf2e6 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp | |||
| @@ -2,16 +2,23 @@ | |||
| 2 | * Copyright (c) 2011 Tobias Markmann | 2 | * Copyright (c) 2011 Tobias Markmann | 
| 3 | * Licensed under the simplified BSD license. | 3 | * Licensed under the simplified BSD license. | 
| 4 | * See Documentation/Licenses/BSD-simplified.txt for more information. | 4 | * See Documentation/Licenses/BSD-simplified.txt for more information. | 
| 5 | */ | 5 | */ | 
| 6 | 6 | ||
| 7 | /* | ||
| 8 | * Copyright (c) 2015 Isode Limited. | ||
| 9 | * All rights reserved. | ||
| 10 | * See the COPYING file for more information. | ||
| 11 | */ | ||
| 12 | |||
| 7 | #include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> | 13 | #include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> | 
| 8 | 14 | ||
| 9 | #include <boost/smart_ptr/make_shared.hpp> | ||
| 10 | #include <boost/bind.hpp> | 15 | #include <boost/bind.hpp> | 
| 16 | #include <boost/smart_ptr/make_shared.hpp> | ||
| 11 | 17 | ||
| 12 | #include <Swiften/Base/Log.h> | 18 | #include <Swiften/Base/Log.h> | 
| 19 | #include <Swiften/Base/foreach.h> | ||
| 13 | #include <Swiften/Elements/S5BProxyRequest.h> | 20 | #include <Swiften/Elements/S5BProxyRequest.h> | 
| 14 | #include <Swiften/Queries/GenericRequest.h> | 21 | #include <Swiften/Queries/GenericRequest.h> | 
| 15 | #include <Swiften/Queries/IQRouter.h> | 22 | #include <Swiften/Queries/IQRouter.h> | 
| 16 | 23 | ||
| 17 | namespace Swift { | 24 | namespace Swift { | 
| @@ -23,40 +30,58 @@ SOCKS5BytestreamProxyFinder::~SOCKS5BytestreamProxyFinder() { | |||
| 23 | } | 30 | } | 
| 24 | 31 | ||
| 25 | void SOCKS5BytestreamProxyFinder::start() { | 32 | void SOCKS5BytestreamProxyFinder::start() { | 
| 26 | serviceWalker = boost::make_shared<DiscoServiceWalker>(service, iqRouter); | 33 | serviceWalker = boost::make_shared<DiscoServiceWalker>(service, iqRouter); | 
| 27 | serviceWalker->onServiceFound.connect(boost::bind(&SOCKS5BytestreamProxyFinder::handleServiceFound, this, _1, _2)); | 34 | serviceWalker->onServiceFound.connect(boost::bind(&SOCKS5BytestreamProxyFinder::handleServiceFound, this, _1, _2)); | 
| 35 | serviceWalker->onWalkComplete.connect(boost::bind(&SOCKS5BytestreamProxyFinder::handleWalkEnded, this)); | ||
| 28 | serviceWalker->beginWalk(); | 36 | serviceWalker->beginWalk(); | 
| 29 | } | 37 | } | 
| 30 | 38 | ||
| 31 | void SOCKS5BytestreamProxyFinder::stop() { | 39 | void SOCKS5BytestreamProxyFinder::stop() { | 
| 40 | typedef boost::shared_ptr<GenericRequest<S5BProxyRequest> > S5BProxyRequestGenericRequest; | ||
| 41 | foreach (S5BProxyRequestGenericRequest requester, pendingRequests) { | ||
| 42 | requester->onResponse.disconnect(boost::bind(&SOCKS5BytestreamProxyFinder::handleProxyResponse, this, requester, _1, _2)); | ||
| 43 | } | ||
| 44 | |||
| 32 | serviceWalker->endWalk(); | 45 | serviceWalker->endWalk(); | 
| 33 | serviceWalker->onServiceFound.disconnect(boost::bind(&SOCKS5BytestreamProxyFinder::handleServiceFound, this, _1, _2)); | 46 | serviceWalker->onServiceFound.disconnect(boost::bind(&SOCKS5BytestreamProxyFinder::handleServiceFound, this, _1, _2)); | 
| 47 | serviceWalker->onWalkComplete.disconnect(boost::bind(&SOCKS5BytestreamProxyFinder::handleWalkEnded, this)); | ||
| 34 | serviceWalker.reset(); | 48 | serviceWalker.reset(); | 
| 35 | } | 49 | } | 
| 36 | 50 | ||
| 37 | void SOCKS5BytestreamProxyFinder::sendBytestreamQuery(const JID& jid) { | 51 | void SOCKS5BytestreamProxyFinder::sendBytestreamQuery(const JID& jid) { | 
| 38 | S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); | 52 | S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); | 
| 39 | boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Get, jid, proxyRequest, iqRouter); | 53 | boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Get, jid, proxyRequest, iqRouter); | 
| 40 | request->onResponse.connect(boost::bind(&SOCKS5BytestreamProxyFinder::handleProxyResponse, this, _1, _2)); | 54 | request->onResponse.connect(boost::bind(&SOCKS5BytestreamProxyFinder::handleProxyResponse, this, request, _1, _2)); | 
| 55 | pendingRequests.insert(request); | ||
| 41 | request->send(); | 56 | request->send(); | 
| 42 | } | 57 | } | 
| 43 | 58 | ||
| 44 | void SOCKS5BytestreamProxyFinder::handleServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> discoInfo) { | 59 | void SOCKS5BytestreamProxyFinder::handleServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> discoInfo) { | 
| 45 | if (discoInfo->hasFeature(DiscoInfo::Bytestream)) { | 60 | if (discoInfo->hasFeature(DiscoInfo::Bytestream)) { | 
| 46 | sendBytestreamQuery(jid); | 61 | sendBytestreamQuery(jid); | 
| 47 | } | 62 | } | 
| 48 | } | 63 | } | 
| 49 | 64 | ||
| 50 | void SOCKS5BytestreamProxyFinder::handleProxyResponse(boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error) { | 65 | void SOCKS5BytestreamProxyFinder::handleWalkEnded() { | 
| 66 | if (pendingRequests.empty()) { | ||
| 67 | onProxiesFound(proxyHosts); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | void SOCKS5BytestreamProxyFinder::handleProxyResponse(boost::shared_ptr<GenericRequest<S5BProxyRequest> > requester, boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error) { | ||
| 72 | requester->onResponse.disconnect(boost::bind(&SOCKS5BytestreamProxyFinder::handleProxyResponse, this, requester, _1, _2)); | ||
| 73 | pendingRequests.erase(requester); | ||
| 51 | if (error) { | 74 | if (error) { | 
| 52 | SWIFT_LOG(debug) << "ERROR" << std::endl; | 75 | SWIFT_LOG(debug) << "ERROR" << std::endl; | 
| 53 | } else { | 76 | } else { | 
| 54 | if (request) { | 77 | if (request) { | 
| 55 | onProxyFound(request); | 78 | SWIFT_LOG(debug) << "add request" << std::endl; | 
| 56 | } else { | 79 | proxyHosts.push_back(request); | 
| 57 | //assert(false); | ||
| 58 | } | 80 | } | 
| 59 | } | 81 | } | 
| 82 | if (pendingRequests.empty() && !serviceWalker->isActive()) { | ||
| 83 | onProxiesFound(proxyHosts); | ||
| 84 | } | ||
| 60 | } | 85 | } | 
| 61 | 86 | ||
| 62 | } | 87 | } | 
| diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h index c5ad72a..1c24497 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h | |||
| @@ -15,11 +15,10 @@ | |||
| 15 | 15 | ||
| 16 | #include <boost/shared_ptr.hpp> | 16 | #include <boost/shared_ptr.hpp> | 
| 17 | 17 | ||
| 18 | #include <Swiften/Base/API.h> | 18 | #include <Swiften/Base/API.h> | 
| 19 | #include <Swiften/Disco/DiscoServiceWalker.h> | 19 | #include <Swiften/Disco/DiscoServiceWalker.h> | 
| 20 | #include <Swiften/Network/HostAddressPort.h> | ||
| 21 | #include <Swiften/Elements/S5BProxyRequest.h> | 20 | #include <Swiften/Elements/S5BProxyRequest.h> | 
| 22 | 21 | ||
| 23 | namespace Swift { | 22 | namespace Swift { | 
| 24 | 23 | ||
| 25 | class JID; | 24 | class JID; | 
| @@ -35,20 +34,23 @@ class SWIFTEN_API SOCKS5BytestreamProxyFinder { | |||
| 35 | ~SOCKS5BytestreamProxyFinder(); | 34 | ~SOCKS5BytestreamProxyFinder(); | 
| 36 | 35 | ||
| 37 | void start(); | 36 | void start(); | 
| 38 | void stop(); | 37 | void stop(); | 
| 39 | 38 | ||
| 40 | boost::signal<void(boost::shared_ptr<S5BProxyRequest>)> onProxyFound; | 39 | boost::signal<void(std::vector<boost::shared_ptr<S5BProxyRequest> >)> onProxiesFound; | 
| 41 | 40 | ||
| 42 | private: | 41 | private: | 
| 43 | void sendBytestreamQuery(const JID&); | 42 | void sendBytestreamQuery(const JID&); | 
| 44 | 43 | ||
| 45 | void handleServiceFound(const JID&, boost::shared_ptr<DiscoInfo>); | 44 | void handleServiceFound(const JID&, boost::shared_ptr<DiscoInfo>); | 
| 46 | void handleProxyResponse(boost::shared_ptr<S5BProxyRequest>, ErrorPayload::ref); | 45 | void handleProxyResponse(boost::shared_ptr<GenericRequest<S5BProxyRequest> > requester, boost::shared_ptr<S5BProxyRequest>, ErrorPayload::ref); | 
| 46 | void handleWalkEnded(); | ||
| 47 | |||
| 47 | private: | 48 | private: | 
| 48 | JID service; | 49 | JID service; | 
| 49 | IQRouter* iqRouter; | 50 | IQRouter* iqRouter; | 
| 50 | boost::shared_ptr<DiscoServiceWalker> serviceWalker; | 51 | boost::shared_ptr<DiscoServiceWalker> serviceWalker; | 
| 51 | std::vector<boost::shared_ptr<GenericRequest<S5BProxyRequest> > > requests; | 52 | std::vector<S5BProxyRequest::ref> proxyHosts; | 
| 52 | }; | 53 | std::set<boost::shared_ptr<GenericRequest<S5BProxyRequest> > > pendingRequests; | 
| 54 | }; | ||
| 53 | 55 | ||
| 54 | } | 56 | } | 
 Swift
 Swift