From bb42fa74de9518051e2ccaff9c323f108fa2cbfc Mon Sep 17 00:00:00 2001
From: RAFI <103924677+cmuhammedrafi@users.noreply.github.com>
Date: Mon, 7 Oct 2024 06:05:31 +0530
Subject: [PATCH] DELIA-65737: Wi-Fi interface shows IP even after Wi-Fi is
 disconnected (#1)

Implemented a cache logic to handle redundant calls
* update the review comments
---
 NetworkManager.cpp         |  2 +-
 NetworkManager.h           | 62 +++++++++++++++++++++++++++++++++--
 NetworkManagerJsonRpc.cpp  | 66 ++++++++++++++++++++++++++++++++------
 NetworkManagerRDKProxy.cpp |  2 +-
 4 files changed, 119 insertions(+), 13 deletions(-)

diff --git a/NetworkManager.cpp b/NetworkManager.cpp
index c7d57b87..baa8d482 100644
--- a/NetworkManager.cpp
+++ b/NetworkManager.cpp
@@ -44,7 +44,7 @@ namespace WPEFramework
               _notification(this)
         {
             // Don't do any work in the constructor - all set up should be done in Initialize
-            m_defaultInterface = "wlan0";
+            m_primaryInterfaceCache = "wlan0";
         }
 
         NetworkManager::~NetworkManager()
diff --git a/NetworkManager.h b/NetworkManager.h
index ce4771cf..1838c545 100644
--- a/NetworkManager.h
+++ b/NetworkManager.h
@@ -28,6 +28,7 @@
 
 #include <string>
 #include <atomic>
+#include <mutex>
 
 namespace WPEFramework
 {
@@ -123,7 +124,12 @@ namespace WPEFramework
                     JsonObject params;
                     params["interface"] = interface;
                     params["state"] = InterfaceStateToString(event);
+                    if(interface == "wlan0")
+                        _parent.m_wifiStateCache.reset();
                     _parent.Notify("onInterfaceStateChange", params);
+                    _parent.m_primaryInterfaceCache.reset();
+                    _parent.m_ipv6AddressCache.reset();
+                    _parent.m_ipv4AddressCache.reset();
                 }
 
                 void onIPAddressChange(const string interface, const bool isAcquired, const bool isIPv6, const string ipAddress) override
@@ -134,6 +140,10 @@ namespace WPEFramework
                     params["interface"] = interface;
                     params["ipAddress"] = ipAddress;
                     params["isIPv6"] = isIPv6;
+                    if(isIPv6)
+                        _parent.m_ipv6AddressCache.reset();
+                    else
+                        _parent.m_ipv4AddressCache.reset();
                     _parent.Notify("onIPAddressChange", params);
                 }
 
@@ -144,7 +154,7 @@ namespace WPEFramework
                     params["oldInterfaceName"] = prevActiveInterface;
                     params["newInterfaceName"] = currentActiveinterface;
                     _parent.Notify("onActiveInterfaceChange", params);
-
+                    _parent.m_primaryInterfaceCache.reset();
                 }
 
                 void onInternetStatusChange(const Exchange::INetworkManager::InternetStatus oldState, const Exchange::INetworkManager::InternetStatus newstate) override
@@ -184,6 +194,7 @@ namespace WPEFramework
                     JsonObject result;
                     result["state"] = static_cast <int> (state);
                     _parent.Notify("onWiFiStateChange", result);
+                    _parent.m_wifiStateCache = state;
                 }
 
                 void onWiFiSignalStrengthChange(const string ssid, const string signalLevel, const Exchange::INetworkManager::WiFiSignalQuality signalQuality) override
@@ -264,7 +275,55 @@ namespace WPEFramework
                 return (m_publicIPAddress.empty() == true ? PluginHost::ISubSystem::IInternet::UNKNOWN : (m_publicIPAddressType == "IPV6" ? PluginHost::ISubSystem::IInternet::IPV6 : PluginHost::ISubSystem::IInternet::IPV4));
             }
             void PublishToThunderAboutInternet();
+            /* Class to store and manage cached data */
+            template<typename CacheValue>
+            class Cache {
+            public:
+                Cache() : is_set(false) {}
+
+                Cache& operator=(const CacheValue& value) {
+                    std::lock_guard<std::mutex> lock(mutex);
+                    this->value = value;
+                    is_set.store(true);
+                    return *this;
+                }
+
+                Cache& operator=(CacheValue&& value) {
+                    std::lock_guard<std::mutex> lock(mutex);
+                    this->value = std::move(value);
+                    is_set.store(true);
+                    return *this;
+                }
+
+                bool isSet() const {
+                    return is_set.load();
+                }
+
+                void reset() {
+                    is_set.store(false);
+                }
+
+                const CacheValue& getValue() const {
+                    std::lock_guard<std::mutex> lock(mutex);
+                    return value;
+                }
+
+                CacheValue& getValue() {
+                    std::lock_guard<std::mutex> lock(mutex);
+                    return value;
+                }
+
+            private:
+                CacheValue value;
+                std::atomic<bool> is_set;
+                mutable std::mutex mutex;
+            };
 
+            // cached varibales
+            Cache<Exchange::INetworkManager::WiFiState> m_wifiStateCache;
+            Cache<Exchange::INetworkManager::IPAddressInfo> m_ipv4AddressCache;
+            Cache<Exchange::INetworkManager::IPAddressInfo> m_ipv6AddressCache;
+            Cache<std::string> m_primaryInterfaceCache;
         private:
             // Notification/event handlers
             // Clean up when we're told to deactivate
@@ -315,7 +374,6 @@ namespace WPEFramework
             Exchange::INetworkManager *_networkManager;
             Core::Sink<Notification> _notification;
             string m_publicIPAddress;
-            string m_defaultInterface;
             string m_publicIPAddressType;
         };
     }
diff --git a/NetworkManagerJsonRpc.cpp b/NetworkManagerJsonRpc.cpp
index a99978e6..06da7b6f 100644
--- a/NetworkManagerJsonRpc.cpp
+++ b/NetworkManagerJsonRpc.cpp
@@ -179,7 +179,13 @@ namespace WPEFramework
             LOG_INPARAM();
             uint32_t rc = Core::ERROR_GENERAL;
             string interface;
-            if (_networkManager)
+            if(m_primaryInterfaceCache.isSet())
+            {
+                NMLOG_INFO("reading interface cached values");
+                interface = m_primaryInterfaceCache.getValue();
+                rc = Core::ERROR_NONE;
+            }
+            else if (_networkManager)
                 rc = _networkManager->GetPrimaryInterface(interface);
             else
                 rc = Core::ERROR_UNAVAILABLE;
@@ -187,7 +193,7 @@ namespace WPEFramework
             if (Core::ERROR_NONE == rc)
             {
                 response["interface"] = interface;      
-                m_defaultInterface = interface;
+                m_primaryInterfaceCache = interface;
                 response["success"] = true;
             }
             LOG_OUTPARAM();
@@ -278,6 +284,7 @@ namespace WPEFramework
             uint32_t rc = Core::ERROR_GENERAL;
             string interface = "";
             string ipversion = "";
+            bool isCacheLoaded = false;
             Exchange::INetworkManager::IPAddressInfo result{};
 
             if (parameters.HasLabel("interface"))
@@ -285,16 +292,56 @@ namespace WPEFramework
             if (parameters.HasLabel("ipversion"))
                 ipversion = parameters["ipversion"].String();
 
-            if (!interface.empty() && ("wlan0" != interface) && ("eth0" != interface))
+            if (interface.empty() || ("wlan0" != interface && "eth0" != interface))
             {
-                rc = Core::ERROR_BAD_REQUEST;
-                return rc;
+                if(!interface.empty()) {
+                    NMLOG_WARNING("interface is neither wlan0 nor eth0: %s", interface.c_str());
+                    return Core::ERROR_BAD_REQUEST;
+                }
+
+                interface = m_primaryInterfaceCache.getValue();
             }
 
-            if (_networkManager)
-                rc = _networkManager->GetIPSettings(interface, ipversion, result);
-            else
-                rc = Core::ERROR_UNAVAILABLE;
+            if(m_primaryInterfaceCache.isSet() && (interface == m_primaryInterfaceCache.getValue()))
+            {
+                /* If ipversion is empty, IPv4 will be taken as the default version */
+                if(m_ipv4AddressCache.isSet() && (ipversion.empty() || strcasecmp(ipversion.c_str(), "IPv4") == 0))
+                {
+                    NMLOG_INFO("reading ipv4 settings cached values");
+                    result = m_ipv4AddressCache.getValue();
+                    rc = Core::ERROR_NONE;
+                    isCacheLoaded = true;
+                }
+                else if(m_ipv6AddressCache.isSet() && (ipversion.empty() || strcasecmp(ipversion.c_str(), "IPv6") == 0))
+                {
+                    NMLOG_INFO("reading ipv6 settings cached values");
+                    result = m_ipv6AddressCache.getValue();
+                    rc = Core::ERROR_NONE;
+                    isCacheLoaded = true;
+                }
+            }
+
+            if (!isCacheLoaded)
+            {
+                if (_networkManager)
+                {
+                    rc = _networkManager->GetIPSettings(interface, ipversion, result);
+                    /* The value will be cached only for the primary interface IP address. */
+                    if(Core::ERROR_NONE == rc && m_primaryInterfaceCache.isSet() && (interface == m_primaryInterfaceCache.getValue()))
+                    {
+                        NMLOG_DEBUG("caching the ip address values");
+                        if (strcasecmp(result.m_ipAddrType.c_str(), "IPv4") == 0)
+                            m_ipv4AddressCache = result;
+                        else if (strcasecmp(result.m_ipAddrType.c_str(), "IPv6") == 0)
+                            m_ipv6AddressCache = result;
+                    }
+                }
+                else
+                {
+                    NMLOG_ERROR("_networkManager == null");
+                    rc = Core::ERROR_UNAVAILABLE;
+                }
+            }
 
             if (Core::ERROR_NONE == rc)
             {
@@ -982,6 +1029,7 @@ namespace WPEFramework
             if (Core::ERROR_NONE == rc)
             {
                 response["state"] = static_cast <int> (state);
+                m_wifiStateCache = state;
                 response["success"] = true;
             }
             LOG_OUTPARAM();
diff --git a/NetworkManagerRDKProxy.cpp b/NetworkManagerRDKProxy.cpp
index d8272132..67052cdc 100644
--- a/NetworkManagerRDKProxy.cpp
+++ b/NetworkManagerRDKProxy.cpp
@@ -629,7 +629,7 @@ namespace WPEFramework
                 std::vector<InterfaceDetails> interfaceList;
                 for (int i = 0; i < list.size; i++)
                 {
-                    NMLOG_INFO ("Interface Name = %s", list.interfaces[i].name);
+                    NMLOG_DEBUG("Interface Name = %s", list.interfaces[i].name);
                     string interfaceName(list.interfaces[i].name);
                     if (("eth0" == interfaceName) || ("wlan0" == interfaceName))
                     {