summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-07-16 08:11:09 (GMT)
committerTobias Markmann <tm@ayena.de>2015-07-17 11:51:49 (GMT)
commit3e982c0a39d1d1833afaf558fc7b0f7aeffd2d64 (patch)
tree2b5c6ea333bfb97066cf60ff97345d73ee167581
parentb9edc9bbf5e304a1b2cec8f963c0d8d53ff0e2f2 (diff)
downloadswift-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.cpp70
-rw-r--r--Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h12
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
34SOCKS5BytestreamProxiesManager::~SOCKS5BytestreamProxiesManager() { 34SOCKS5BytestreamProxiesManager::~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
40void SOCKS5BytestreamProxiesManager::addS5BProxy(S5BProxyRequest::ref proxy) { 47void 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
57void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& sessionID) { 64void 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
76boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { 86boost::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
164void 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
182void 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
25namespace Swift { 27namespace 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 };