From b34cd486e27430a5535d4dc48eb4e6297626d92d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Tue, 22 Dec 2020 16:38:37 -0500
Subject: [PATCH] conference: properly protect confInfo_

Change-Id: Ifb897e5918163fe9d6ee7eefb9e65a76c441d8dc
---
 src/call.cpp       | 12 ++----
 src/conference.cpp | 99 +++++++++++++++++-----------------------------
 src/conference.h   |  3 +-
 3 files changed, 42 insertions(+), 72 deletions(-)

diff --git a/src/call.cpp b/src/call.cpp
index 38687832e5..907bea10e1 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -648,17 +648,13 @@ Call::setConferenceInfo(const std::string& msg)
         if (confID_.empty()) {
             // confID_ empty -> participant set confInfo with the received one
             confInfo_ = std::move(newInfo);
-            std::vector<std::map<std::string, std::string>> toSend =
-                                        confInfo_.toVectorMapStringString();
-
             // Inform client that layout has changed
-            jami::emitSignal<DRing::CallSignal::OnConferenceInfosUpdated>(id_, std::move(toSend));
+            jami::emitSignal<DRing::CallSignal::OnConferenceInfosUpdated>(id_, confInfo_.toVectorMapStringString());
         } else {
             // confID_ not empty -> host merge confInfo with the received confInfo
-            auto oldInfo = confInfo_;
             for (auto& newI : newInfo) {
                 bool isNewParticipant = true;
-                for (auto& oldI : oldInfo) {
+                for (auto& oldI : confInfo_) {
                     if (newI.uri == oldI.uri) {
                         oldI = newI;
                         isNewParticipant = false;
@@ -669,11 +665,9 @@ Call::setConferenceInfo(const std::string& msg)
                     // ParticipantInfo not present in confInfo -> the sender of newInfo ...
                     // is currently hosting another conference. Add the unknown participant ...
                     // to the confInfo
-                    oldInfo.emplace_back(newI);
+                    confInfo_.emplace_back(newI);
                 }
             }
-            confInfo_ = std::move(oldInfo);
-
             if (auto conf = Manager::instance().getConferenceFromID(confID_))
                 conf->updateConferenceInfo(confInfo_);
         }
diff --git a/src/conference.cpp b/src/conference.cpp
index e860e519b9..90b17b3dc0 100644
--- a/src/conference.cpp
+++ b/src/conference.cpp
@@ -92,11 +92,10 @@ Conference::Conference()
                 if (auto videoMixer = shared->getVideoMixer())
                     active = info.source == videoMixer->getActiveParticipant();
                 subCalls.erase(it->second);
-                std::string_view partURI = uri;
-                partURI = string_remove_suffix(partURI, '@');
+                std::string_view partURI = string_remove_suffix(uri, '@');
                 auto isModerator = shared->isModerator(partURI);
                 if (uri.empty())
-                    partURI = "host";
+                    partURI = "host"sv;
                 auto isMuted = shared->isMuted(partURI);
                 newInfo.emplace_back(ParticipantInfo {std::move(uri),
                                                       "",
@@ -120,12 +119,7 @@ Conference::Conference()
                     ParticipantInfo {std::move(uri), "", false, 0, 0, 0, 0, true, false, isModerator});
             }
 
-            {
-                std::lock_guard<std::mutex> lk2(shared->confInfoMutex_);
-                shared->confInfo_ = std::move(newInfo);
-            }
-
-            shared->sendConferenceInfos();
+            shared->updateConferenceInfo(std::move(newInfo));
         });
     });
 #endif
@@ -184,9 +178,7 @@ Conference::add(const std::string& participant_id)
         // Check if participant was muted before conference
         if (auto call = Manager::instance().callFactory.getCall<SIPCall>(participant_id)) {
             if (call->isPeerMuted()) {
-                auto uri = call->getPeerNumber();
-                uri = string_remove_suffix(uri, '@');
-                participantsMuted_.emplace(uri);
+                participantsMuted_.emplace(string_remove_suffix(call->getPeerNumber(), '@'));
             }
         }
 #ifdef ENABLE_VIDEO
@@ -256,11 +248,8 @@ ConfInfo::toVectorMapStringString() const
 {
     std::vector<std::map<std::string, std::string>> infos;
     infos.reserve(size());
-    auto it = cbegin();
-    while (it != cend()) {
-        infos.emplace_back(it->toMap());
-        ++it;
-    }
+    for (const auto& info : *this)
+        infos.emplace_back(info.toMap());
     return infos;
 }
 
@@ -277,20 +266,19 @@ Conference::sendConferenceInfos()
             if (!account)
                 continue;
 
-            ConfInfo confInfo = std::move(getConfInfoHostUri(account->getUsername()+ "@ring.dht"));
+            ConfInfo confInfo = getConfInfoHostUri(account->getUsername()+ "@ring.dht");
             Json::Value jsonArray = {};
-            {
-                std::lock_guard<std::mutex> lk2(confInfoMutex_);
-                for (const auto& info : confInfo) {
-                    jsonArray.append(info.toJson());
-                }
+            for (const auto& info : confInfo) {
+                jsonArray.append(info.toJson());
             }
 
-            Json::StreamWriterBuilder builder = {};
-            const auto confInfoStr = Json::writeString(builder, jsonArray);
-            call->sendTextMessage(std::map<std::string, std::string> {{"application/confInfo+json",
-                                                                    confInfoStr}},
-                                account->getFromUri());
+            runOnMainThread([
+                call,
+                confInfoStr = Json::writeString(Json::StreamWriterBuilder{}, jsonArray),
+                from = account->getFromUri()
+            ] {
+                call->sendTextMessage({{"application/confInfo+json", confInfoStr}}, from);
+            });
         }
     }
 
@@ -417,8 +405,7 @@ Conference::bindHost()
 
     for (const auto& item : participants_) {
         if (auto call = Manager::instance().getCallFromCallID(item)) {
-            std::string_view uri = call->getPeerNumber();
-            uri = string_remove_suffix(uri, '@');
+            auto uri = string_remove_suffix(call->getPeerNumber(), '@');
             if (isMuted(uri))
                 continue;
             rbPool.bindCallID(item, RingBufferPool::DEFAULT_ID);
@@ -547,8 +534,7 @@ Conference::onConfOrder(const std::string& callId, const std::string& confOrder)
 {
     // Check if the peer is a master
     if (auto call = Manager::instance().getCallFromCallID(callId)) {
-        std::string_view uri = call->getPeerNumber();
-        uri = string_remove_suffix(uri, '@');
+        auto uri = string_remove_suffix(call->getPeerNumber(), '@');
         if (!isModerator(uri)) {
             JAMI_WARN("Received conference order from a non master (%s)", uri.data());
             return;
@@ -593,8 +579,7 @@ Conference::setModerator(const std::string& uri, const bool& state)
 {
     for (const auto& p : participants_) {
         if (auto call = Manager::instance().callFactory.getCall<SIPCall>(p)) {
-            std::string_view partURI = call->getPeerNumber();
-            partURI = string_remove_suffix(partURI, '@');
+            auto partURI = string_remove_suffix(call->getPeerNumber(), '@');
             if (partURI == uri) {
                 if (state and not isModerator(uri)) {
                     JAMI_DBG("Add %s as moderator", partURI.data());
@@ -615,13 +600,9 @@ Conference::setModerator(const std::string& uri, const bool& state)
 void
 Conference::updateModerators()
 {
-    {
-        std::lock_guard<std::mutex> lk2(confInfoMutex_);
-        for (auto& info : confInfo_) {
-            auto uri = info.uri;
-            uri = string_remove_suffix(uri, '@');
-            info.isModerator = isModerator(uri);
-        }
+    std::lock_guard<std::mutex> lk(confInfoMutex_);
+    for (auto& info : confInfo_) {
+        info.isModerator = isModerator(string_remove_suffix(info.uri, '@'));
     }
     sendConferenceInfos();
 }
@@ -673,19 +654,18 @@ Conference::muteParticipant(const std::string& uri, const bool& state, const std
     }
 
     // Mute participant
+    auto peerURI = string_remove_suffix(uri, '@');
     for (const auto& p : participants_) {
-        std::string_view peerURI = string_remove_suffix(uri, '@');
         if (auto call = Manager::instance().callFactory.getCall<SIPCall>(p)) {
-            std::string_view partURI = call->getPeerNumber();
-            partURI = string_remove_suffix(partURI, '@');
+            auto partURI = string_remove_suffix(call->getPeerNumber(), '@');
             if (partURI == peerURI) {
                 if (state and not isMuted(partURI)) {
-                    JAMI_DBG("Mute participant %s", partURI.data());
+                    JAMI_DBG("Mute participant %.*s", (int)partURI.size(), partURI.data());
                     participantsMuted_.emplace(std::string(partURI));
                     unbindParticipant(p);
                     updateMuted();
                 } else if (not state and isMuted(partURI)) {
-                    JAMI_DBG("Unmute participant %s", partURI.data());
+                    JAMI_DBG("Unmute participant %.*s", (int)partURI.size(), partURI.data());
                     participantsMuted_.erase(std::string(partURI));
                     bindParticipant(p);
                     updateMuted();
@@ -699,14 +679,12 @@ Conference::muteParticipant(const std::string& uri, const bool& state, const std
 void
 Conference::updateMuted()
 {
-    {
-        std::lock_guard<std::mutex> lk2(confInfoMutex_);
-        for (auto& info : confInfo_) {
-            auto uri = string_remove_suffix(info.uri, '@');
-            if (uri.empty())
-                uri = "host";
-            info.audioMuted = isMuted(uri);
-        }
+    std::lock_guard<std::mutex> lk(confInfoMutex_);
+    for (auto& info : confInfo_) {
+        auto uri = string_remove_suffix(info.uri, '@');
+        if (uri.empty())
+            uri = "host"sv;
+        info.audioMuted = isMuted(uri);
     }
     sendConferenceInfos();
 }
@@ -735,12 +713,9 @@ Conference::isHost(std::string_view uri) const
     // (a local URI can be in the call with another device)
     for (const auto& p : participants_) {
         if (auto call = Manager::instance().callFactory.getCall<SIPCall>(p)) {
-            auto w = call->getAccount();
-            auto account = w.lock();
-            if (!account)
-                continue;
-            if (account->getUsername() == uri) {
-                return true;
+            if (auto account = call->getAccount().lock()) {
+                if (account->getUsername() == uri)
+                    return true;
             }
         }
     }
@@ -750,6 +725,7 @@ Conference::isHost(std::string_view uri) const
 void
 Conference::updateConferenceInfo(ConfInfo confInfo)
 {
+    std::lock_guard<std::mutex> lk(confInfoMutex_);
     confInfo_ = std::move(confInfo);
     sendConferenceInfos();
 }
@@ -764,8 +740,7 @@ Conference::hangupParticipant(const std::string& participant_id)
 
     for (const auto& p : participants_) {
         if (auto call = Manager::instance().callFactory.getCall<SIPCall>(p)) {
-            std::string_view partURI = call->getPeerNumber();
-            partURI = string_remove_suffix(partURI, '@');
+            std::string_view partURI = string_remove_suffix(call->getPeerNumber(), '@');
             if (partURI == participant_id) {
                 Manager::instance().hangupCall(call->getCallId());
                 return;
diff --git a/src/conference.h b/src/conference.h
index cb7801a726..e50ef0c5d0 100644
--- a/src/conference.h
+++ b/src/conference.h
@@ -254,7 +254,8 @@ private:
     ParticipantSet participants_;
 
     mutable std::mutex confInfoMutex_ {};
-    mutable ConfInfo confInfo_ {};
+    ConfInfo confInfo_ {};
+
     void sendConferenceInfos();
     // We need to convert call to frame
     std::mutex videoToCallMtx_;
-- 
GitLab