From 25e7cb5615aafa7b3da434532b8fc2609c2d1261 Mon Sep 17 00:00:00 2001 From: cmuhammedrafi <103924677+cmuhammedrafi@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:20:52 +0530 Subject: [PATCH] DELIA-64899: Implement Retry logic in Connectivity Monitoring (#5115) * connect only logic added * connectivity retry logic added (cherry picked from commit 9a2caf500342fba6bff3bf77b1ad757d28316367) --- Network/NetworkConnectivity.cpp | 131 ++++++++++++++++++-------------- Network/NetworkConnectivity.h | 10 +-- 2 files changed, 79 insertions(+), 62 deletions(-) diff --git a/Network/NetworkConnectivity.cpp b/Network/NetworkConnectivity.cpp index 0ea4f3ef9a..24d65cc4b9 100644 --- a/Network/NetworkConnectivity.cpp +++ b/Network/NetworkConnectivity.cpp @@ -178,9 +178,9 @@ namespace WPEFramework { else { if(isConnectivityMonitorEndpointSet()) - internetState = testConnectivity(getConnectivityMonitorEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, ipversion); + internetState = testConnectivity(getConnectivityMonitorEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, ipversion, false); else - internetState = testConnectivity(getConnectivityDefaultEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, ipversion); + internetState = testConnectivity(getConnectivityDefaultEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, ipversion, false); } return internetState; @@ -253,7 +253,7 @@ namespace WPEFramework { return size * nmemb; } - nsm_internetState Connectivity::testConnectivity(const std::vector& endpoints, long timeout_ms, nsm_ipversion ipversion) + nsm_internetState Connectivity::testConnectivity(const std::vector& endpoints, long timeout_ms, nsm_ipversion ipversion, bool connectOnly) { long deadline = current_time() + timeout_ms, time_now = 0, time_earlier = 0; if(endpoints.size() < 1) { @@ -287,7 +287,10 @@ namespace WPEFramework { curl_easy_setopt(curl_easy_handle, CURLOPT_HTTPHEADER, chunk); curl_easy_setopt(curl_easy_handle, CURLOPT_USERAGENT, "RDKCaptiveCheck/1.0"); /* set CURLOPT_HTTPGET option insted of CURLOPT_CONNECT_ONLY bcause we need to get the captiveportal URI not just connection only */ - curl_easy_setopt(curl_easy_handle, CURLOPT_HTTPGET, 1L); + if(connectOnly) + curl_easy_setopt(curl_easy_handle, CURLOPT_CONNECT_ONLY, 1L); + else + curl_easy_setopt(curl_easy_handle, CURLOPT_HTTPGET, 1L); curl_easy_setopt(curl_easy_handle, CURLOPT_WRITEFUNCTION, writeFunction); curl_easy_setopt(curl_easy_handle, CURLOPT_TIMEOUT_MS, deadline - current_time()); if ((ipversion == CURL_IPRESOLVE_V4) || (ipversion == CURL_IPRESOLVE_V6)) @@ -322,12 +325,14 @@ namespace WPEFramework { continue; if (CURLE_OK == msg->data.result) { curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &endpoint); - if (curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK) { + if(connectOnly) + response_code = HttpStatus_204_No_Content; + else if (curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK) { if(curlVerboseEnabled()) LOGINFO("endpoint = <%s> http response code <%d>", endpoint, static_cast(response_code)); if (HttpStatus_302_Found == response_code) { if ( (curl_easy_getinfo(msg->easy_handle, CURLINFO_REDIRECT_URL, &url) == CURLE_OK) && url != nullptr) { - //LOGWARN("captive portal found !!!"); + LOGWARN("captive portal found !!!"); setCaptivePortal(url); } } @@ -438,7 +443,6 @@ namespace WPEFramework { break; } } - return InternetConnectionState; } @@ -452,12 +456,11 @@ namespace WPEFramework { timeout.store(timeoutInSeconds >= MONITOR_TIMEOUT_INTERVAL_MIN ? timeoutInSeconds:defaultTimeoutInSec); - if (isMonitorThreadRunning()) + if (isMonitorThreadRunning() && stopFlag == false) { isContinuesMonitoringNeeded = true; + resetTimeout = true; cv_.notify_all(); - LOGINFO("Connectivity monitor Restarted with %d", timeout.load()); - //TODO check still active } else { @@ -472,7 +475,6 @@ namespace WPEFramework { isContinuesMonitoringNeeded = true; stopFlag = false; thread_ = std::thread(&ConnectivityMonitor::connectivityMonitorFunction, this); - threadRunning = true; LOGINFO("Connectivity monitor started with %d", timeout.load()); } @@ -487,7 +489,7 @@ namespace WPEFramework { return false; } - if (isMonitorThreadRunning()) + if (isMonitorThreadRunning() && stopFlag == false) { LOGINFO("Connectivity Monitor Thread is active so notify"); cv_.notify_all(); @@ -505,7 +507,6 @@ namespace WPEFramework { stopFlag = false; timeout.store(timeoutInSeconds >= MONITOR_TIMEOUT_INTERVAL_MIN ? timeoutInSeconds:defaultTimeoutInSec); thread_ = std::thread(&ConnectivityMonitor::connectivityMonitorFunction, this); - threadRunning = true; LOGINFO("Initial Connectivity Monitoring started with %d", timeout.load()); } @@ -514,58 +515,38 @@ namespace WPEFramework { bool ConnectivityMonitor::isMonitorThreadRunning() { - return threadRunning.load(); + return thread_.joinable(); } bool ConnectivityMonitor::stopInitialConnectivityMonitoring() { - if(isContinuesMonitoringNeeded) { LOGWARN("Continuous Connectivity Monitor is running"); return true; } - else - { - if (!isMonitorThreadRunning()) - { - LOGWARN("Connectivity monitor not running"); - } - stopFlag = true; - cv_.notify_all(); + stopFlag = true; + cv_.notify_all(); - if (thread_.joinable()) - { - thread_.join(); - threadRunning = false; - LOGINFO("Stoping Initial Connectivity Monitor"); - } - else - LOGWARN("thread not joinable !"); - } + if (thread_.joinable()) + thread_.join(); + + LOGINFO("Initial Connectivity Monitor stopped"); return true; } bool ConnectivityMonitor::stopContinuousConnectivityMonitoring() { - if (!isMonitorThreadRunning()) - { - LOGWARN("Connectivity monitor not running"); - } - cv_.notify_all(); stopFlag = true; + cv_.notify_all(); if (thread_.joinable()) - { thread_.join(); - isContinuesMonitoringNeeded = false; - threadRunning = false; - LOGINFO("Continuous Connectivity monitor stopped"); - } - else - LOGWARN("thread not joinable !"); + + isContinuesMonitoringNeeded = false; + LOGINFO("Continuous Connectivity monitor stopped"); return true; } @@ -573,8 +554,8 @@ namespace WPEFramework { { if (isMonitorThreadRunning()) { - /* Reset the global value to UNKNOWN state*/ - resetConnectivityCache(); + /* Reset the global value to UNKNOWN state so the cache is reset */ + g_internetState = nsm_internetState::UNKNOWN; cv_.notify_all(); } } @@ -582,39 +563,75 @@ namespace WPEFramework { void ConnectivityMonitor::connectivityMonitorFunction() { nsm_internetState InternetConnectionState = nsm_internetState::UNKNOWN; + int notifyWaitCount = DEFAULT_MONITOR_RETRY_COUNT; + int tempTimeout = defaultTimeoutInSec; do { - InternetConnectionState = testConnectivity(getConnectivityMonitorEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, NSM_IPRESOLVE_WHATEVER); + if(g_internetState.load() == nsm_internetState::FULLY_CONNECTED) + /*if previous check was fully connected then do connect only curl check*/ + InternetConnectionState = testConnectivity(getConnectivityMonitorEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, NSM_IPRESOLVE_WHATEVER, true); + else + /*curl get request*/ + InternetConnectionState = testConnectivity(getConnectivityMonitorEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, NSM_IPRESOLVE_WHATEVER, false); + if(g_internetState.load() != InternetConnectionState) { - g_internetState.store(InternetConnectionState); - Network::notifyInternetStatusChange(g_internetState.load()); + LOGINFO("notification count %d ...", notifyWaitCount); + if(InternetConnectionState == nsm_internetState::NO_INTERNET && notifyWaitCount > 0) + { + /* Decrease the notification count to create a delay in posting the 'no internet' state. */ + notifyWaitCount--; + /* change the timeout value to 5 sec so that next check will happens with in 5 sec */ + tempTimeout = 5; + LOGINFO("notification count change to %d timeout %d ...", notifyWaitCount, tempTimeout); + } + else + { + g_internetState.store(InternetConnectionState); + Network::notifyInternetStatusChange(g_internetState.load()); + notifyWaitCount = DEFAULT_MONITOR_RETRY_COUNT; + /* change the timeout value to actual requested value */ + tempTimeout = timeout.load(); + LOGINFO("notification count change to default %d ...", notifyWaitCount); + } } if(!isContinuesMonitoringNeeded && (g_internetState.load() == FULLY_CONNECTED)) { stopFlag = true; - LOGINFO("Initial Connectivity Monitoring done Exiting ... Internet state FULLY_CONNECTED"); - threadRunning = false; + LOGINFO("Initial Connectivity Monitoring done Exiting ... FULLY_CONNECTED"); break; } if(stopFlag) - { - threadRunning = false; break; - } - //wait for next timout or conditon signal + // wait for next timout or conditon signal std::unique_lock lock(mutex_); - if (cv_.wait_for(lock, std::chrono::seconds(timeout.load())) != std::cv_status::timeout) + if (cv_.wait_for(lock, std::chrono::seconds(tempTimeout)) != std::cv_status::timeout) { if(!stopFlag) { - LOGINFO("Connectivity monitor received a trigger"); + /* + * We don't need to notify immediately when restarting the thread. + * Immediate notification should occur only when any connection change happens. + * + */ + + if(resetTimeout) + { + LOGINFO("Connectivity monitor Restarted with %d", timeout.load()); + resetTimeout = false; + } + else + { + notifyWaitCount = -1; + LOGINFO("Connectivity monitor received trigger"); + } } } } while (!stopFlag); + g_internetState = nsm_internetState::UNKNOWN; LOGWARN("Connectivity monitor exiting"); } diff --git a/Network/NetworkConnectivity.h b/Network/NetworkConnectivity.h index c5398671e8..4bf2fc4c51 100644 --- a/Network/NetworkConnectivity.h +++ b/Network/NetworkConnectivity.h @@ -13,7 +13,8 @@ #define CAPTIVEPORTAL_MAX_LEN 512 #define DEFAULT_MONITOR_TIMEOUT 60 // in seconds #define MONITOR_TIMEOUT_INTERVAL_MIN 5 -#define TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS 10000 +#define TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS 5000 +#define DEFAULT_MONITOR_RETRY_COUNT 2 enum nsm_ipversion { NSM_IPRESOLVE_WHATEVER = 0, /* default, resolves addresses to all IP*/ @@ -82,7 +83,7 @@ namespace WPEFramework { } ~Connectivity(){} - nsm_internetState testConnectivity(const std::vector& endpoints, long timeout_ms, nsm_ipversion ipversion); + nsm_internetState testConnectivity(const std::vector& endpoints, long timeout_ms, nsm_ipversion ipversion, bool connectOnly); std::vector getConnectivityDefaultEndpoints() { return m_defaultEndpoints; }; std::string getCaptivePortal() { const std::lock_guard lock(capitiveMutex); return g_captivePortal; } void setCaptivePortal(const char* captivePortal) {const std::lock_guard lock(capitiveMutex); g_captivePortal = captivePortal; } @@ -112,9 +113,8 @@ namespace WPEFramework { bool isConnectivityMonitorEndpointSet(); bool isMonitorThreadRunning(); void signalConnectivityMonitor(); - void resetConnectivityCache() { g_internetState = nsm_internetState::UNKNOWN;} - ConnectivityMonitor() : stopFlag(false), threadRunning(false), isContinuesMonitoringNeeded(false) + ConnectivityMonitor() : stopFlag(false), resetTimeout(false), isContinuesMonitoringNeeded(false) { setConnectivityMonitorEndpoints(getConnectivityDefaultEndpoints()); } @@ -134,7 +134,7 @@ namespace WPEFramework { std::thread thread_; std::atomic stopFlag; - std::atomic threadRunning; + std::atomic resetTimeout; std::atomic isContinuesMonitoringNeeded; std::condition_variable cv_; std::atomic timeout;