Skip to content
Snippets Groups Projects
Commit 0b1b9ee7 authored by Sébastien Blin's avatar Sébastien Blin
Browse files

turn_cache: avoid potential deadlock on start

Creating the TURNTransport and starting it can call the callback
in the same thread, causing a deadlock. This patch retriggers the
callback to avoid a double lock.

Change-Id: I955ce0503a7f34c0d2241000193861f9b5d1cb49
parent 5a30c3b8
Branches
No related tags found
No related merge requests found
......@@ -24,6 +24,7 @@
#include "fileutils.h"
#include "manager.h"
#include "opendht/thread_pool.h" // TODO remove asio
#include "turn_cache.h"
namespace jami {
......@@ -37,10 +38,25 @@ TurnCache::TurnCache(const std::string& accountId,
{
refreshTimer_ = std::make_unique<asio::steady_timer>(*io_context,
std::chrono::steady_clock::now());
onConnectedTimer_ = std::make_unique<asio::steady_timer>(*io_context,
std::chrono::steady_clock::now());
reconfigure(params, enabled);
}
TurnCache::~TurnCache() {}
TurnCache::~TurnCache() {
{
std::lock_guard<std::mutex> lock(shutdownMtx_);
onConnectedTimer_->cancel();
onConnectedTimer_.reset();
}
{
std::lock_guard<std::mutex> lock(cachedTurnMutex_);
testTurnV4_.reset();
testTurnV6_.reset();
cacheTurnV4_.reset();
cacheTurnV6_.reset();
}
}
std::optional<IpAddr>
TurnCache::getResolvedTurn(uint16_t family) const
......@@ -159,24 +175,40 @@ TurnCache::testTurn(IpAddr server)
try {
turn = std::make_unique<TurnTransport>(
params, std::move([this, server](bool ok) {
std::lock_guard<std::mutex> lk(cachedTurnMutex_);
auto& cacheTurn = server.isIpv4() ? cacheTurnV4_ : cacheTurnV6_;
if (!ok) {
JAMI_ERROR("Connection to {:s} failed - reset", server.toString());
cacheTurn.reset();
} else {
JAMI_DEBUG("Connection to {:s} ready", server.toString());
cacheTurn = std::make_unique<IpAddr>(server);
// Stop server in an async job, because this callback can be called
// immediately and cachedTurnMutex_ must not be locked.
std::lock_guard<std::mutex> lock(shutdownMtx_);
if (onConnectedTimer_) {
onConnectedTimer_->expires_at(std::chrono::steady_clock::now());
onConnectedTimer_->async_wait(std::bind(&TurnCache::onConnected, this, std::placeholders::_1, ok, server));
}
refreshTurnDelay(!cacheTurnV6_ && !cacheTurnV4_);
auto& turn = server.isIpv4() ? testTurnV4_ : testTurnV6_;
turn->shutdown();
}));
} catch (const std::exception& e) {
JAMI_ERROR("TurnTransport creation error: {}", e.what());
}
}
void
TurnCache::onConnected(const asio::error_code& ec, bool ok, IpAddr server)
{
if (ec == asio::error::operation_aborted)
return;
std::lock_guard<std::mutex> lk(cachedTurnMutex_);
auto& cacheTurn = server.isIpv4() ? cacheTurnV4_ : cacheTurnV6_;
if (!ok) {
JAMI_ERROR("Connection to {:s} failed - reset", server.toString());
cacheTurn.reset();
} else {
JAMI_DEBUG("Connection to {:s} ready", server.toString());
cacheTurn = std::make_unique<IpAddr>(server);
}
refreshTurnDelay(!cacheTurnV6_ && !cacheTurnV4_);
if (auto& turn = server.isIpv4() ? testTurnV4_ : testTurnV6_)
turn->shutdown();
}
void
TurnCache::refreshTurnDelay(bool scheduleNext)
{
......
......@@ -80,9 +80,15 @@ private:
std::unique_ptr<IpAddr> cacheTurnV4_ {};
std::unique_ptr<IpAddr> cacheTurnV6_ {};
void onConnected(const asio::error_code& ec, bool ok, IpAddr server);
// io
std::shared_ptr<asio::io_context> io_context;
std::unique_ptr<asio::steady_timer> refreshTimer_;
std::unique_ptr<asio::steady_timer> onConnectedTimer_;
std::mutex shutdownMtx_;
};
} // namespace jami
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment