diff --git a/src/connectivity/turn_cache.cpp b/src/connectivity/turn_cache.cpp index 2a6d856f92c6421fecf115af063f0d5312190d0d..12fbb43c3c358139420da84e5253d5b3bac65af0 100644 --- a/src/connectivity/turn_cache.cpp +++ b/src/connectivity/turn_cache.cpp @@ -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) { diff --git a/src/connectivity/turn_cache.h b/src/connectivity/turn_cache.h index 967ede7abb8dabd42318af168889d80912ab10d0..9c5fa04f3ddbd96dba76d994e1067eb540691df2 100644 --- a/src/connectivity/turn_cache.h +++ b/src/connectivity/turn_cache.h @@ -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