From eebf86014e66463e9fc4e0887280e06a26720ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Tue, 29 Jun 2021 15:37:54 -0400 Subject: [PATCH] sipcall: lock transport while initializing ICE When starting an outgoing call, if the ICE initialization is too fast: + SIPCall::initIceMediaTransport will init the ICE transport + onInitDone will be called before tmpMediaTransport_ initialized + JamiAccount::SIPStartCall will be called and add ICE candidates BUT because transportMtx_ is not locked, tmpMediaTransport_ will be null and no ICE transport will be added. This is why createUTransport should be done while locked. Anyway the method is async so should not block. GitLab: #574 Change-Id: Id88dc92f6d77c18de3ea4614e2b5fd79d3429ff0 --- src/jamidht/jamiaccount.cpp | 18 ++++++++++-------- src/sip/sipcall.cpp | 24 +++++++++++++++++------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index 345235fe67..3d63c45119 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -755,15 +755,17 @@ JamiAccount::onConnectedOutgoingCall(const std::shared_ptr<SIPCall>& call, // So, we need to run the call creation in the main thread // Also, we do not directly call SIPStartCall before receiving onInitDone, because // there is an inside waitForInitialization that can block the thread. - runOnMainThread([w = std::move(w), target = std::move(target), call = std::move(call)] { - auto shared = w.lock(); - if (!shared) - return; + // Note: avoid runMainThread as SIPStartCall use transportMutex + dht::ThreadPool::io().run( + [w = std::move(w), target = std::move(target), call = std::move(call)] { + auto shared = w.lock(); + if (!shared) + return; - if (not shared->SIPStartCall(*call, target)) { - JAMI_ERR("Could not send outgoing INVITE request for new call"); - } - }); + if (not shared->SIPStartCall(*call, target)) { + JAMI_ERR("Could not send outgoing INVITE request for new call"); + } + }); }; call->setIPToIP(true); call->setPeerNumber(to_id); diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index c2ab034280..1012db1a88 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -82,7 +82,8 @@ static constexpr std::chrono::milliseconds MS_BETWEEN_2_KEYFRAME_REQUEST {1000}; static constexpr int ICE_COMP_ID_RTP {1}; static constexpr int ICE_COMP_COUNT_PER_STREAM {2}; static constexpr auto MULTISTREAM_REQUIRED_VERSION_STR = "10.0.2"sv; -static const std::vector<unsigned> MULTISTREAM_REQUIRED_VERSION = split_string_to_unsigned(MULTISTREAM_REQUIRED_VERSION_STR, '.'); +static const std::vector<unsigned> MULTISTREAM_REQUIRED_VERSION + = split_string_to_unsigned(MULTISTREAM_REQUIRED_VERSION_STR, '.'); SIPCall::SIPCall(const std::shared_ptr<SIPAccountBase>& account, const std::string& callId, @@ -1535,14 +1536,18 @@ SIPCall::setPeerUaVersion(std::string_view ua) } if (peerUserAgent_.empty()) { - JAMI_DBG("[call:%s] Set peer's User-Agent to [%.*s]", getCallId().c_str(), (int)ua.size(), ua.data()); + JAMI_DBG("[call:%s] Set peer's User-Agent to [%.*s]", + getCallId().c_str(), + (int) ua.size(), + ua.data()); } else if (not peerUserAgent_.empty()) { // Unlikely, but should be handled since we dont have control over the peer. // Even if it's unexpected, we still try to parse the UA version. JAMI_WARN("[call:%s] Peer's User-Agent unexpectedly changed from [%s] to [%.*s]", getCallId().c_str(), peerUserAgent_.c_str(), - (int)ua.size(), ua.data()); + (int) ua.size(), + ua.data()); } peerUserAgent_ = ua; @@ -1585,10 +1590,15 @@ SIPCall::setPeerUaVersion(std::string_view ua) } // Check if peer's version is at least 10.0.2 to enable multi-stream. - peerSupportMultiStream_ = Account::meetMinimumRequiredVersion(peerVersion, MULTISTREAM_REQUIRED_VERSION); + peerSupportMultiStream_ = Account::meetMinimumRequiredVersion(peerVersion, + MULTISTREAM_REQUIRED_VERSION); if (not peerSupportMultiStream_) { - JAMI_DBG("Peer's version [%.*s] does not support multi-stream. Min required version: [%.*s]", - (int)version.size(), version.data(), (int)MULTISTREAM_REQUIRED_VERSION_STR.size(), MULTISTREAM_REQUIRED_VERSION_STR.data()); + JAMI_DBG( + "Peer's version [%.*s] does not support multi-stream. Min required version: [%.*s]", + (int) version.size(), + version.data(), + (int) MULTISTREAM_REQUIRED_VERSION_STR.size(), + MULTISTREAM_REQUIRED_VERSION_STR.data()); } } @@ -2873,8 +2883,8 @@ SIPCall::initIceMediaTransport(bool master, std::optional<IceTransportOptions> o // Each RTP stream requires a pair of ICE components (RTP + RTCP). iceOptions.compCountPerStream = ICE_COMP_COUNT_PER_STREAM; auto& iceTransportFactory = Manager::instance().getIceTransportFactory(); - auto transport = iceTransportFactory.createUTransport(getCallId().c_str(), iceOptions); std::lock_guard<std::mutex> lk(transportMtx_); + auto transport = iceTransportFactory.createUTransport(getCallId().c_str(), iceOptions); // Destroy old ice on a separate io pool if (tmpMediaTransport_) dht::ThreadPool::io().run([ice = std::make_shared<decltype(tmpMediaTransport_)>( -- GitLab