Commit 67b46caa authored by Sébastien Blin's avatar Sébastien Blin Committed by Adrien Béraud

turn: cache resolved addresses

This avoid to re-resolve the TURN each time we need a new connection
The turn is resolved each time a connectivityChange occurs or
at the initialization of the account.
The resolved address is stored in the cache directory to speed-up
the initialization when possible. This Improve connection speed on
local netowrks.

Change-Id: Idff2631a4c9b874b5ef4226ac248b9045b310f68
parent 439a4349
......@@ -1519,6 +1519,8 @@ JamiAccount::doRegister()
} else {
doRegister_();
}
cacheTurnServers(); // reset cache for TURN servers
}
std::vector<std::string>
......@@ -1987,7 +1989,9 @@ JamiAccount::connectivityChanged()
}
dht_->connectivityChanged();
setPublishedAddress({}); // reset cache
// reset cache
setPublishedAddress({});
cacheTurnServers();
}
bool
......@@ -2642,4 +2646,69 @@ JamiAccount::setActiveCodecs(const std::vector<unsigned>& list)
}
}
void
JamiAccount::cacheTurnServers()
{
// The resolution of the TURN server can take quite some time (if timeout).
// So, run this in its own io thread to avoid to block the main thread.
dht::ThreadPool::io().run([this] {
// Avoid multiple refresh
if (isRefreshing_.exchange(true)) return;
if (!turnEnabled_) {
// In this case, we do not use any TURN server
std::lock_guard<std::mutex> lk(cachedTurnMutex_);
cacheTurnV4_.reset();
cacheTurnV6_.reset();
isRefreshing_ = false;
return;
}
JAMI_INFO("Refresh cache for TURN server resolution");
// Retrieve old cached value if available.
// This means that we directly get the correct value when launching the application on the same network
std::string server = turnServer_.empty() ? DEFAULT_TURN_SERVER : turnServer_;
fileutils::recursive_mkdir(cachePath_ + DIR_SEPARATOR_STR + "domains", 0700);
auto pathV4 = cachePath_ + DIR_SEPARATOR_STR + "domains" + DIR_SEPARATOR_STR + "v4." + server;
if (auto turnV4File = std::ifstream(pathV4)) {
std::string content((std::istreambuf_iterator<char>(turnV4File)), std::istreambuf_iterator<char>());
std::lock_guard<std::mutex> lk(cachedTurnMutex_);
cacheTurnV4_ = std::make_unique<IpAddr>(content, AF_INET);
}
auto pathV6 = cachePath_ + DIR_SEPARATOR_STR + "domains" + DIR_SEPARATOR_STR + "v6." + server;
if (auto turnV6File = std::ifstream(pathV6)) {
std::string content((std::istreambuf_iterator<char>(turnV6File)), std::istreambuf_iterator<char>());
std::lock_guard<std::mutex> lk(cachedTurnMutex_);
cacheTurnV6_ = std::make_unique<IpAddr>(content, AF_INET6);
}
// Resolve just in case. The user can have a different connectivity
auto turnV4 = IpAddr {server, AF_INET};
{
if (turnV4) {
// Cache value to avoid a delay when starting up Jami
std::ofstream turnV4File(pathV4);
turnV4File << turnV4.toString();
} else {
fileutils::remove(pathV4, true);
}
std::lock_guard<std::mutex> lk(cachedTurnMutex_);
// Update TURN
cacheTurnV4_ = std::make_unique<IpAddr>(std::move(turnV4));
}
auto turnV6 = IpAddr {server.empty() ? DEFAULT_TURN_SERVER : server, AF_INET6};
{
if (turnV6) {
// Cache value to avoid a delay when starting up Jami
std::ofstream turnV6File(pathV6);
turnV6File << turnV6.toString();
} else {
fileutils::remove(pathV6, true);
}
std::lock_guard<std::mutex> lk(cachedTurnMutex_);
// Update TURN
cacheTurnV6_ = std::make_unique<IpAddr>(std::move(turnV6));
}
isRefreshing_ = false;
JAMI_INFO("Cache refreshed for TURN resolution");
});
}
} // namespace jami
......@@ -646,6 +646,16 @@ private:
bool accountPublish_ {false};
std::shared_ptr<RepeatedTask> eventHandler {};
/**
* Avoid to refresh the cache multiple times
*/
std::atomic_bool isRefreshing_ {false};
/**
* This will cache the turn server resolution each time we launch
* Jami, or for each connectivityChange()
*/
void cacheTurnServers();
};
static inline std::ostream& operator<< (std::ostream& os, const JamiAccount& acc)
......
......@@ -548,8 +548,14 @@ DhtPeerConnector::Impl::turnConnect()
auto username = details[Conf::CONFIG_TURN_SERVER_UNAME];
auto password = details[Conf::CONFIG_TURN_SERVER_PWD];
auto turnCache = account.turnCache();
auto turn_param_v4 = TurnTransportParams {};
turn_param_v4.server = IpAddr {server.empty() ? "turn.jami.net" : server};
if (turnCache[0]) {
turn_param_v4.server = *turnCache[0];
} else {
turn_param_v4.server = IpAddr {server.empty() ? "turn.jami.net" : server};
}
turn_param_v4.realm = realm.empty() ? "ring" : realm;
turn_param_v4.username = username.empty() ? "ring" : username;
turn_param_v4.password = password.empty() ? "ring" : password;
......@@ -576,6 +582,11 @@ DhtPeerConnector::Impl::turnConnect()
if (!turnAuthv6_ || !turnAuthv6_->isReady()) {
auto turn_param_v6 = turn_param_v4;
if (turnCache[1]) {
turn_param_v6.server = *turnCache[1];
} else {
turn_param_v6.server = IpAddr {server.empty() ? "turn.jami.net" : server};
}
turn_param_v6.authorized_family = PJ_AF_INET6;
turnAuthv6_ = std::make_unique<TurnTransport>(turn_param_v6);
}
......
......@@ -370,15 +370,35 @@ SIPAccountBase::getIceOptions() const noexcept
{
auto opts = Account::getIceOptions(); // Local copy of global account ICE settings
// Note: we don't check of servers pre-existance, let underlaying stack do the job
if (stunEnabled_)
opts.stunServers.emplace_back(StunServerInfo().setUri(stunServer_));
if (turnEnabled_)
opts.turnServers.emplace_back(TurnServerInfo()
.setUri(turnServer_)
.setUsername(turnServerUserName_)
.setPassword(turnServerPwd_)
.setRealm(turnServerRealm_));
if (turnEnabled_) {
auto cached = false;
std::lock_guard<std::mutex> lk(cachedTurnMutex_);
cached = cacheTurnV4_ || cacheTurnV6_;
if (cacheTurnV4_ && *cacheTurnV4_) {
opts.turnServers.emplace_back(TurnServerInfo()
.setUri(*cacheTurnV4_)
.setUsername(turnServerUserName_)
.setPassword(turnServerPwd_)
.setRealm(turnServerRealm_));
}
if (cacheTurnV6_ && *cacheTurnV6_) {
opts.turnServers.emplace_back(TurnServerInfo()
.setUri(*cacheTurnV4_)
.setUsername(turnServerUserName_)
.setPassword(turnServerPwd_)
.setRealm(turnServerRealm_));
}
// Nothing cached, so do the resolution
if (!cached) {
opts.turnServers.emplace_back(TurnServerInfo()
.setUri(turnServer_)
.setUsername(turnServerUserName_)
.setPassword(turnServerPwd_)
.setRealm(turnServerRealm_));
}
}
return opts;
}
......
......@@ -298,6 +298,20 @@ public:
public: // overloaded methods
virtual void flush() override;
/**
* Return current turn resolved addresses
* @return {unique_ptr(v4 resolved), unique_ptr(v6 resolved)}
*/
std::array<std::unique_ptr<IpAddr>, 2> turnCache() {
std::lock_guard<std::mutex> lk {cachedTurnMutex_};
std::array<std::unique_ptr<IpAddr>, 2> result = {};
if (cacheTurnV4_ && *cacheTurnV4_)
result[0] = std::make_unique<IpAddr>(*cacheTurnV4_);
if (cacheTurnV6_ && *cacheTurnV6_)
result[1] = std::make_unique<IpAddr>(*cacheTurnV6_);
return result;
}
protected:
virtual void serialize(YAML::Emitter &out) const override;
virtual void serializeTls(YAML::Emitter &out) const;
......@@ -445,6 +459,10 @@ protected:
static constexpr size_t MAX_WAITING_MESSAGES_SIZE = 1000;
std::deque<DRing::Message> lastMessages_;
mutable std::mutex cachedTurnMutex_ {};
std::unique_ptr<IpAddr> cacheTurnV4_ {};
std::unique_ptr<IpAddr> cacheTurnV6_ {};
private:
NON_COPYABLE(SIPAccountBase);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment