diff options
| author | Tobias Markmann <tm@ayena.de> | 2015-07-16 08:11:09 (GMT) |
|---|---|---|
| committer | Tobias Markmann <tm@ayena.de> | 2015-07-17 11:51:49 (GMT) |
| commit | 3e982c0a39d1d1833afaf558fc7b0f7aeffd2d64 (patch) | |
| tree | 2b5c6ea333bfb97066cf60ff97345d73ee167581 | |
| parent | b9edc9bbf5e304a1b2cec8f963c0d8d53ff0e2f2 (diff) | |
| download | swift-3e982c0a39d1d1833afaf558fc7b0f7aeffd2d64.zip swift-3e982c0a39d1d1833afaf558fc7b0f7aeffd2d64.tar.bz2 | |
Fix S5B proxy connection management for multiple hosts per JID
A recent commit introduced resolving of S5B proxy domain names
to their IPv4 and IPv6 addresses. With that a proxy identified
by a JID can have more than one host and we try them in parallel
until the first succeeds.
The old code just handled one host per proxy JID and a failed
IPv6 attempt would override the succeeded connection. The code
uses shared pointers and the succeeded connecting is deallocated
and disconnected when it is replaced with the failing IPv6
connection.
The result is the proxy server complaining that we are not
connected as we try to activate the proxy stream.
This commit changes the the proxy management to handle multiple
connections per proxy JID. Failing connections are removed from
the proxy sessions data structure. With the first succeeding
connections, others are stopped and also removed.
Test-Information:
Tested on Linux (Elementary OS 0.2) with
"Swiften/QA/FileTransferTest/FileTransferTest 4 4", which forces
the use of SOCKS5 bytestream proxy.
Change-Id: If3071c3d058e1040556bb72702bf83f4f5f25334
| -rw-r--r-- | Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp | 70 | ||||
| -rw-r--r-- | Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h | 12 |
2 files changed, 68 insertions, 14 deletions
diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp index 2956ff7..1036e12 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp | |||
| @@ -33,10 +33,17 @@ SOCKS5BytestreamProxiesManager::SOCKS5BytestreamProxiesManager(ConnectionFactory | |||
| 33 | 33 | ||
| 34 | SOCKS5BytestreamProxiesManager::~SOCKS5BytestreamProxiesManager() { | 34 | SOCKS5BytestreamProxiesManager::~SOCKS5BytestreamProxiesManager() { |
| 35 | if (proxyFinder_) { | 35 | if (proxyFinder_) { |
| 36 | proxyFinder_->stop(); | 36 | proxyFinder_->stop(); |
| 37 | } | 37 | } |
| 38 | |||
| 39 | foreach (const ProxySessionsMap::value_type& sessionsForID, proxySessions_) { | ||
| 40 | foreach (const ProxyJIDClientSessionVector::value_type& session, sessionsForID.second) { | ||
| 41 | session.second->onSessionReady.disconnect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionReady, this,sessionsForID.first, session.first, session.second, _1)); | ||
| 42 | session.second->onFinished.disconnect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionFinished, this, sessionsForID.first, session.first, session.second, _1)); | ||
| 43 | } | ||
| 44 | } | ||
| 38 | } | 45 | } |
| 39 | 46 | ||
| 40 | void SOCKS5BytestreamProxiesManager::addS5BProxy(S5BProxyRequest::ref proxy) { | 47 | void SOCKS5BytestreamProxiesManager::addS5BProxy(S5BProxyRequest::ref proxy) { |
| 41 | if (proxy) { | 48 | if (proxy) { |
| 42 | SWIFT_LOG_ASSERT(HostAddress(proxy->getStreamHost().get().host).isValid(), warning) << std::endl; | 49 | SWIFT_LOG_ASSERT(HostAddress(proxy->getStreamHost().get().host).isValid(), warning) << std::endl; |
| @@ -54,20 +61,23 @@ const boost::optional<std::vector<S5BProxyRequest::ref> >& SOCKS5BytestreamProxi | |||
| 54 | return localS5BProxies_; | 61 | return localS5BProxies_; |
| 55 | } | 62 | } |
| 56 | 63 | ||
| 57 | void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& sessionID) { | 64 | void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& sessionID) { |
| 58 | SWIFT_LOG(debug) << "session ID: " << sessionID << std::endl; | 65 | SWIFT_LOG(debug) << "session ID: " << sessionID << std::endl; |
| 59 | ProxyJIDClientSessionMap clientSessions; | 66 | ProxyJIDClientSessionVector clientSessions; |
| 60 | 67 | ||
| 61 | if (localS5BProxies_) { | 68 | if (localS5BProxies_) { |
| 62 | foreach(S5BProxyRequest::ref proxy, localS5BProxies_.get()) { | 69 | foreach(S5BProxyRequest::ref proxy, localS5BProxies_.get()) { |
| 63 | boost::shared_ptr<Connection> conn = connectionFactory_->createConnection(); | 70 | boost::shared_ptr<Connection> conn = connectionFactory_->createConnection(); |
| 64 | 71 | ||
| 65 | HostAddressPort addressPort = HostAddressPort(proxy->getStreamHost().get().host, proxy->getStreamHost().get().port); | 72 | HostAddressPort addressPort = HostAddressPort(proxy->getStreamHost().get().host, proxy->getStreamHost().get().port); |
| 66 | SWIFT_LOG_ASSERT(addressPort.isValid(), warning) << std::endl; | 73 | SWIFT_LOG_ASSERT(addressPort.isValid(), warning) << std::endl; |
| 67 | boost::shared_ptr<SOCKS5BytestreamClientSession> session = boost::make_shared<SOCKS5BytestreamClientSession>(conn, addressPort, sessionID, timerFactory_); | 74 | boost::shared_ptr<SOCKS5BytestreamClientSession> session = boost::make_shared<SOCKS5BytestreamClientSession>(conn, addressPort, sessionID, timerFactory_); |
| 68 | clientSessions[proxy->getStreamHost().get().jid] = session; | 75 | JID proxyJid = proxy->getStreamHost().get().jid; |
| 76 | clientSessions.push_back(std::pair<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> >(proxyJid, session)); | ||
| 77 | session->onSessionReady.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionReady, this,sessionID, proxyJid, session, _1)); | ||
| 78 | session->onFinished.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionFinished, this, sessionID, proxyJid, session, _1)); | ||
| 69 | session->start(); | 79 | session->start(); |
| 70 | } | 80 | } |
| 71 | } | 81 | } |
| 72 | 82 | ||
| 73 | proxySessions_[sessionID] = clientSessions; | 83 | proxySessions_[sessionID] = clientSessions; |
| @@ -76,21 +86,22 @@ void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& session | |||
| 76 | boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { | 86 | boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { |
| 77 | // checking parameters | 87 | // checking parameters |
| 78 | if (proxySessions_.find(sessionID) == proxySessions_.end()) { | 88 | if (proxySessions_.find(sessionID) == proxySessions_.end()) { |
| 79 | return boost::shared_ptr<SOCKS5BytestreamClientSession>(); | 89 | return boost::shared_ptr<SOCKS5BytestreamClientSession>(); |
| 80 | } | 90 | } |
| 81 | if (proxySessions_[sessionID].find(proxyJID) == proxySessions_[sessionID].end()) { | ||
| 82 | return boost::shared_ptr<SOCKS5BytestreamClientSession>(); | ||
| 83 | } | ||
| 84 | 91 | ||
| 85 | // get active session | 92 | // get active session |
| 86 | boost::shared_ptr<SOCKS5BytestreamClientSession> activeSession = proxySessions_[sessionID][proxyJID]; | 93 | boost::shared_ptr<SOCKS5BytestreamClientSession> activeSession; |
| 87 | proxySessions_[sessionID].erase(proxyJID); | 94 | for (ProxyJIDClientSessionVector::iterator i = proxySessions_[sessionID].begin(); i != proxySessions_[sessionID].end(); i++) { |
| 88 | 95 | i->second->onSessionReady.disconnect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionReady, this,sessionID, proxyJID, i->second, _1)); | |
| 89 | // close other sessions | 96 | i->second->onFinished.disconnect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionFinished, this, sessionID, proxyJID, i->second, _1)); |
| 90 | foreach(const ProxyJIDClientSessionMap::value_type& myPair, proxySessions_[sessionID]) { | 97 | if (i->first == proxyJID && !activeSession) { |
| 91 | myPair.second->stop(); | 98 | activeSession = i->second; |
| 99 | } | ||
| 100 | else { | ||
| 101 | i->second->stop(); | ||
| 102 | } | ||
| 92 | } | 103 | } |
| 93 | 104 | ||
| 94 | proxySessions_.erase(sessionID); | 105 | proxySessions_.erase(sessionID); |
| 95 | 106 | ||
| 96 | return activeSession; | 107 | return activeSession; |
| @@ -148,6 +159,43 @@ void SOCKS5BytestreamProxiesManager::queryForProxies() { | |||
| 148 | 159 | ||
| 149 | proxyFinder_->onProxyFound.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxyFound, this, _1)); | 160 | proxyFinder_->onProxyFound.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxyFound, this, _1)); |
| 150 | proxyFinder_->start(); | 161 | proxyFinder_->start(); |
| 151 | } | 162 | } |
| 152 | 163 | ||
| 164 | 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)); | ||
| 166 | if (!error) { | ||
| 167 | // The SOCKS5 bytestream session to the proxy succeeded; stop and remove other sessions. | ||
| 168 | if (proxySessions_.find(sessionID) != proxySessions_.end()) { | ||
| 169 | for (ProxyJIDClientSessionVector::iterator i = proxySessions_[sessionID].begin(); i != proxySessions_[sessionID].end();) { | ||
| 170 | if ((i->first == jid) && (i->second != session)) { | ||
| 171 | i->second->stop(); | ||
| 172 | i = proxySessions_[sessionID].erase(i); | ||
| 173 | } | ||
| 174 | else { | ||
| 175 | i++; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | void SOCKS5BytestreamProxiesManager::handleProxySessionFinished(const std::string& sessionID, const JID& jid, boost::shared_ptr<SOCKS5BytestreamClientSession> session, boost::optional<FileTransferError> error) { | ||
| 183 | session->onFinished.disconnect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxySessionFinished, this, sessionID, jid, session, _1)); | ||
| 184 | if (error.is_initialized()) { | ||
| 185 | // The SOCKS5 bytestream session to the proxy failed; remove it. | ||
| 186 | if (proxySessions_.find(sessionID) != proxySessions_.end()) { | ||
| 187 | for (ProxyJIDClientSessionVector::iterator i = proxySessions_[sessionID].begin(); i != proxySessions_[sessionID].end();) { | ||
| 188 | if ((i->first == jid) && (i->second == session)) { | ||
| 189 | i->second->stop(); | ||
| 190 | i = proxySessions_[sessionID].erase(i); | ||
| 191 | break; | ||
| 192 | } | ||
| 193 | else { | ||
| 194 | i++; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 153 | } | 201 | } |
diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h index 06db76c..e4bf1d9 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h | |||
| @@ -11,18 +11,20 @@ | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | #pragma once | 14 | #pragma once |
| 15 | 15 | ||
| 16 | #include <map> | ||
| 16 | #include <string> | 17 | #include <string> |
| 18 | #include <utility> | ||
| 17 | #include <vector> | 19 | #include <vector> |
| 18 | 20 | ||
| 19 | #include <Swiften/Base/API.h> | 21 | #include <Swiften/Base/API.h> |
| 20 | #include <Swiften/Elements/S5BProxyRequest.h> | 22 | #include <Swiften/Elements/S5BProxyRequest.h> |
| 21 | #include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> | 23 | #include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> |
| 22 | #include <Swiften/JID/JID.h> | ||
| 23 | #include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> | 24 | #include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> |
| 25 | #include <Swiften/JID/JID.h> | ||
| 24 | 26 | ||
| 25 | namespace Swift { | 27 | namespace Swift { |
| 26 | class TimerFactory; | 28 | class TimerFactory; |
| 27 | class ConnectionFactory; | 29 | class ConnectionFactory; |
| 28 | class DomainNameResolver; | 30 | class DomainNameResolver; |
| @@ -57,19 +59,23 @@ namespace Swift { | |||
| 57 | void handleProxyFound(S5BProxyRequest::ref proxy); | 59 | void handleProxyFound(S5BProxyRequest::ref proxy); |
| 58 | void handleNameLookupResult(const std::vector<HostAddress>&, boost::optional<DomainNameResolveError>, S5BProxyRequest::ref proxy); | 60 | void handleNameLookupResult(const std::vector<HostAddress>&, boost::optional<DomainNameResolveError>, S5BProxyRequest::ref proxy); |
| 59 | 61 | ||
| 60 | void queryForProxies(); | 62 | void queryForProxies(); |
| 61 | 63 | ||
| 64 | void handleProxySessionReady(const std::string& sessionID, const JID& jid, boost::shared_ptr<SOCKS5BytestreamClientSession> session, bool error); | ||
| 65 | void handleProxySessionFinished(const std::string& sessionID, const JID& jid, boost::shared_ptr<SOCKS5BytestreamClientSession> session, boost::optional<FileTransferError> error); | ||
| 66 | |||
| 62 | private: | 67 | private: |
| 63 | ConnectionFactory* connectionFactory_; | 68 | ConnectionFactory* connectionFactory_; |
| 64 | TimerFactory* timerFactory_; | 69 | TimerFactory* timerFactory_; |
| 65 | DomainNameResolver* resolver_; | 70 | DomainNameResolver* resolver_; |
| 66 | IQRouter* iqRouter_; | 71 | IQRouter* iqRouter_; |
| 67 | JID serviceRoot_; | 72 | JID serviceRoot_; |
| 68 | 73 | ||
| 69 | typedef std::map<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> > ProxyJIDClientSessionMap; | 74 | typedef std::vector<std::pair<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> > > ProxyJIDClientSessionVector; |
| 70 | std::map<std::string, ProxyJIDClientSessionMap> proxySessions_; | 75 | typedef std::map<std::string, ProxyJIDClientSessionVector> ProxySessionsMap; |
| 76 | ProxySessionsMap proxySessions_; | ||
| 71 | 77 | ||
| 72 | boost::shared_ptr<SOCKS5BytestreamProxyFinder> proxyFinder_; | 78 | boost::shared_ptr<SOCKS5BytestreamProxyFinder> proxyFinder_; |
| 73 | 79 | ||
| 74 | boost::optional<std::vector<S5BProxyRequest::ref> > localS5BProxies_; | 80 | boost::optional<std::vector<S5BProxyRequest::ref> > localS5BProxies_; |
| 75 | }; | 81 | }; |
Swift