diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index 861b5f8577914efd8c00ae8bd23fef5cd6cd7609..3bc9f5bc69115e2b444767aa88e33c9bf1a8ef73 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -77,14 +77,15 @@ #include <algorithm> #include <array> -#include <memory> -#include <sstream> #include <cctype> #include <cinttypes> #include <cstdarg> +#include <initializer_list> +#include <memory> +#include <regex> +#include <sstream> #include <string> #include <system_error> -#include <initializer_list> namespace ring { @@ -215,6 +216,7 @@ static constexpr const char * DEFAULT_TURN_SERVER = "turn.jami.net"; static constexpr const char * DEFAULT_TURN_USERNAME = "ring"; static constexpr const char * DEFAULT_TURN_PWD = "ring"; static constexpr const char * DEFAULT_TURN_REALM = "ring"; +static const auto PROXY_REGEX = std::regex("(https?://)?([\\w\\.]+)(:(\\d+)|:\\[(.+)-(.+)\\])?"); constexpr const char* const RingAccount::ACCOUNT_TYPE; /* constexpr */ const std::pair<uint16_t, uint16_t> RingAccount::DHT_PORT_RANGE {4000, 8888}; @@ -291,6 +293,10 @@ RingAccount::RingAccount(const std::string& accountID, bool /* presenceEnabled * turnServerPwd_ = DEFAULT_TURN_PWD; turnServerRealm_ = DEFAULT_TURN_REALM; turnEnabled_ = true; + + std::ifstream proxyCache(cachePath_ + DIR_SEPARATOR_STR "dhtproxy"); + if (proxyCache) + std::getline(proxyCache, proxyServerCached_); } RingAccount::~RingAccount() @@ -1526,10 +1532,21 @@ RingAccount::setAccountDetails(const std::map<std::string, std::string>& details parseString(details, DRing::Account::ConfProperties::RING_DEVICE_NAME, ringDeviceName_); parseBool(details, DRing::Account::ConfProperties::PROXY_ENABLED, proxyEnabled_); + auto oldProxyServer = proxyServer_; parseString(details, DRing::Account::ConfProperties::PROXY_SERVER, proxyServer_); parseString(details, DRing::Account::ConfProperties::PROXY_PUSH_TOKEN, deviceKey_); - if (proxyServer_.empty()) + // Migrate from old versions + if (proxyServer_.empty() + || ((proxyServer_ == "dhtproxy.jami.net" + || proxyServer_ == "dhtproxy.ring.cx") + && proxyServerCached_.empty())) proxyServer_ = DHT_DEFAULT_PROXY; + if (proxyServer_ != oldProxyServer) { + RING_DBG("DHT Proxy configuration changed, resetting cache"); + proxyServerCached_ = {}; + auto proxyCachePath = cachePath_ + DIR_SEPARATOR_STR "dhtproxy"; + std::remove(proxyCachePath.c_str()); + } #if HAVE_RINGNS parseString(details, DRing::Account::ConfProperties::RingNS::URI, nameServer_); @@ -2103,7 +2120,7 @@ RingAccount::doRegister_() config.dht_config.node_config.network = 0; config.dht_config.node_config.maintain_storage = false; config.dht_config.id = identity_; - config.proxy_server = proxyEnabled_ ? proxyServer_ : std::string(); + config.proxy_server = getDhtProxyServer(); config.push_node_id = getAccountID(); config.threaded = true; if (not config.proxy_server.empty()) @@ -2851,6 +2868,50 @@ RingAccount::loadDhParams(const std::string path) } } +std::string +RingAccount::getDhtProxyServer() +{ + if (!proxyEnabled_) return {}; + if (proxyServerCached_.empty()) { + std::vector<std::string> proxys; + // Split the list of servers + std::sregex_iterator begin = {proxyServer_.begin(), proxyServer_.end(), PROXY_REGEX}, end; + for (auto it = begin; it != end; ++it) { + auto &match = *it; + if (match[5].matched and match[6].matched) { + try { + auto start = std::stoi(match[5]), end = std::stoi(match[6]); + for (auto p = start; p <= end; p++) + proxys.emplace_back(match[1].str() + match[2].str() + ":" + + std::to_string(p)); + } catch (...) { + RING_WARN("Malformed proxy, ignore it"); + continue; + } + } else { + proxys.emplace_back(match[0].str()); + } + } + if (proxys.empty()) + return {}; + // Select one of the list as the current proxy. + auto randIt = proxys.begin(); + std::advance(randIt, std::rand() % proxys.size()); + proxyServerCached_ = *randIt; + // Cache it! + fileutils::check_dir(cachePath_.c_str(), 0700); + std::string proxyCachePath = cachePath_ + DIR_SEPARATOR_STR "dhtproxy"; + std::ofstream file(proxyCachePath); + RING_DBG("Cache DHT proxy server: %s", proxyServerCached_.c_str()); + if (file.is_open()) + file << proxyServerCached_; + else + RING_WARN("Cannot write into %s", proxyCachePath.c_str()); + return proxyServerCached_; + } + return proxyServerCached_; +} + void RingAccount::generateDhParams() { diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index 2bf02d69c046c1799b8a583aafcb70daab57de4e..6e33020d8e18d0c13bb1f8a104b76c2d0c93e030 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -86,7 +86,7 @@ class RingAccount : public SIPAccountBase { constexpr static const char* const ACCOUNT_TYPE = "RING"; constexpr static const in_port_t DHT_DEFAULT_PORT = 4222; constexpr static const char* const DHT_DEFAULT_BOOTSTRAP = "bootstrap.jami.net"; - constexpr static const char* const DHT_DEFAULT_PROXY = "dhtproxy.jami.net"; + constexpr static const char* const DHT_DEFAULT_PROXY = "dhtproxy.jami.net:[80-100]"; constexpr static const char* const DHT_TYPE_NS = "cx.ring"; /* constexpr */ static const std::pair<uint16_t, uint16_t> DHT_PORT_RANGE; @@ -635,7 +635,9 @@ class RingAccount : public SIPAccountBase { */ bool proxyEnabled_; std::string proxyServer_; + std::string proxyServerCached_; std::string deviceKey_; + std::string getDhtProxyServer(); /** * The TLS settings, used only if tls is chosen as a sip transport.