From bb396ff0ff010c6f0f9ab255916230ddf69ba62e Mon Sep 17 00:00:00 2001
From: Mohamed Chibani <mohamed.chibani@savoirfairelinux.com>
Date: Wed, 7 Apr 2021 15:20:35 -0400
Subject: [PATCH] upnp/account: create upnp controller instance only when
 needed

Create upnp controller instance only when needed. Particularly
prevents creating instances when storing account data.

Gitlab: #510

Change-Id: I99f119f5015389eec769e21e0f6ef70f1663f5da
---
 src/account.cpp             | 15 ++++++++++-----
 src/account.h               |  2 +-
 src/jamidht/jamiaccount.cpp | 35 +++--------------------------------
 src/jamidht/jamiaccount.h   |  1 -
 src/upnp/upnp_control.cpp   | 20 ++++++++++----------
 src/upnp/upnp_control.h     |  4 ++--
 6 files changed, 26 insertions(+), 51 deletions(-)

diff --git a/src/account.cpp b/src/account.cpp
index 789d4ece98..f52a336572 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -157,14 +157,18 @@ Account::hangupCalls()
 }
 
 void
-Account::enableUpnp(bool state)
+Account::updateUpnpController()
 {
     std::lock_guard<std::mutex> lk {upnp_mtx};
 
-    if (state and !upnpCtrl_)
+    if (upnpEnabled_ and not upnpCtrl_) {
         upnpCtrl_.reset(new upnp::Controller());
-    else if (!state and upnpCtrl_)
+        if (not upnpCtrl_) {
+            throw std::runtime_error("Failed to create a UPNP Controller instance!");
+        }
+    } else if (not upnpEnabled_) {
         upnpCtrl_.reset();
+    }
 }
 
 void
@@ -287,7 +291,7 @@ Account::unserialize(const YAML::Node& node)
     }
 
     parseValue(node, UPNP_ENABLED_KEY, upnpEnabled_);
-    enableUpnp(upnpEnabled_ && isEnabled());
+    updateUpnpController();
 
     std::string defMod;
     parseValueOptional(node, DEFAULT_MODERATORS_KEY, defMod);
@@ -318,7 +322,8 @@ Account::setAccountDetails(const std::map<std::string, std::string>& details)
         parseString(details, Conf::CONFIG_ACCOUNT_USERAGENT, customUserAgent_);
 
     parseBool(details, Conf::CONFIG_UPNP_ENABLED, upnpEnabled_);
-    enableUpnp(upnpEnabled_ && isEnabled());
+    updateUpnpController();
+
     std::string defMod;
     parseString(details, Conf::CONFIG_DEFAULT_MODERATORS, defMod);
     defaultModerators_ = string_split_set(defMod);
diff --git a/src/account.h b/src/account.h
index 95058f2116..efb68b723c 100644
--- a/src/account.h
+++ b/src/account.h
@@ -373,7 +373,7 @@ private:
     std::set<std::string> callIDSet_;
 
 protected:
-    virtual void enableUpnp(bool state);
+    void updateUpnpController();
 
     static void parseString(const std::map<std::string, std::string>& details,
                             const char* key,
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index 24ee9c0e1a..4d01aace0c 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -2079,35 +2079,6 @@ JamiAccount::doRegister()
     cacheTurnServers(); // reset cache for TURN servers
 }
 
-void
-JamiAccount::enableUpnp(bool enable)
-{
-    std::lock_guard<std::mutex> lk {upnp_mtx};
-
-    if (enable) {
-        auto const& addr = getPublishedIpAddress();
-
-        if (upnpCtrl_ and upnpCtrl_->getExternalIP() == addr) {
-            JAMI_DBG(
-                "[Account %s] Already have a valid controller instance with external address [%s]",
-                getAccountID().c_str(),
-                upnpCtrl_->getExternalIP().toString().c_str());
-            return;
-        }
-
-        JAMI_DBG("[Account %s] Creating a new upnp controller instance", getAccountID().c_str());
-        // Need a known IPv4 address to validate the external address
-        // returned by the IGD.
-        if (addr and addr.getFamily() == AF_INET) {
-            upnpCtrl_.reset(new upnp::Controller(addr));
-        } else {
-            upnpCtrl_.reset(new upnp::Controller());
-        }
-    } else {
-        upnpCtrl_.reset();
-    }
-}
-
 std::vector<std::string>
 JamiAccount::loadBootstrap() const
 {
@@ -3741,9 +3712,9 @@ JamiAccount::storeActiveIpAddress()
                  getAccountID().c_str(),
                  publicAddr.toString().c_str());
 
-        // Check if we need to create a new UPNP controller instance.
-        if (upnpEnabled_ and (not upnpCtrl_ or not upnpCtrl_->isReady())) {
-            enableUpnp(true);
+        // Set the known public address in UPNP if enabled.
+        if (upnpCtrl_) {
+            upnpCtrl_->setPublicAddress(publicAddr);
         }
     }
 
diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h
index 4bbe027c55..103bc2e64f 100644
--- a/src/jamidht/jamiaccount.h
+++ b/src/jamidht/jamiaccount.h
@@ -221,7 +221,6 @@ public:
      */
     void doUnregister(std::function<void(bool)> cb = {}) override;
 
-    void enableUpnp(bool enable) override;
     /**
      * @return pj_str_t "From" uri based on account information.
      * From RFC3261: "The To header field first and foremost specifies the desired
diff --git a/src/upnp/upnp_control.cpp b/src/upnp/upnp_control.cpp
index 0aecf23942..d6ab3badd4 100644
--- a/src/upnp/upnp_control.cpp
+++ b/src/upnp/upnp_control.cpp
@@ -39,16 +39,6 @@ Controller::Controller()
     JAMI_DBG("Controller@%p: Created UPnP Controller session", this);
 }
 
-Controller::Controller(const IpAddr& addr)
-    : Controller()
-{
-    assert(upnpContext_);
-    assert(addr);
-    assert(addr.getFamily() == AF_INET);
-
-    upnpContext_->setPublicAddress(addr);
-}
-
 Controller::~Controller()
 {
     JAMI_DBG("Controller@%p: Destroying UPnP Controller session", this);
@@ -57,6 +47,16 @@ Controller::~Controller()
     upnpContext_->unregisterController(this);
 }
 
+void
+Controller::setPublicAddress(const IpAddr& addr)
+{
+    assert(upnpContext_);
+
+    if (addr and addr.getFamily() == AF_INET) {
+        upnpContext_->setPublicAddress(addr);
+    }
+}
+
 bool
 Controller::isReady() const
 {
diff --git a/src/upnp/upnp_control.h b/src/upnp/upnp_control.h
index d19ac8e4bd..918c255d9a 100644
--- a/src/upnp/upnp_control.h
+++ b/src/upnp/upnp_control.h
@@ -48,12 +48,12 @@ class Controller
 {
 public:
     Controller();
-    Controller(const IpAddr& addr);
     ~Controller();
 
+    // Set known public address
+    void setPublicAddress(const IpAddr& addr);
     // Checks if a valid IGD is available.
     bool isReady() const;
-
     // Gets the external ip of the first valid IGD in the list.
     IpAddr getExternalIP() const;
 
-- 
GitLab