Skip to content

Commit

Permalink
DELIA-64899: Implement Retry logic in Connectivity Monitoring (rdkcen…
Browse files Browse the repository at this point in the history
…tral#5115)

* connect only logic added

* connectivity retry logic added

(cherry picked from commit 9a2caf5)
  • Loading branch information
cmuhammedrafi committed Apr 17, 2024
1 parent 68e363e commit 25e7cb5
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 62 deletions.
131 changes: 74 additions & 57 deletions Network/NetworkConnectivity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -253,7 +253,7 @@ namespace WPEFramework {
return size * nmemb;
}

nsm_internetState Connectivity::testConnectivity(const std::vector<std::string>& endpoints, long timeout_ms, nsm_ipversion ipversion)
nsm_internetState Connectivity::testConnectivity(const std::vector<std::string>& 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) {
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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<int>(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);
}
}
Expand Down Expand Up @@ -438,7 +443,6 @@ namespace WPEFramework {
break;
}
}

return InternetConnectionState;
}

Expand All @@ -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
{
Expand All @@ -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());
}

Expand All @@ -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();
Expand 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());
}

Expand All @@ -514,107 +515,123 @@ 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;
}

void ConnectivityMonitor::signalConnectivityMonitor()
{
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();
}
}

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<std::mutex> 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");
}
Expand Down
10 changes: 5 additions & 5 deletions Network/NetworkConnectivity.h
Original file line number Diff line number Diff line change
Expand Up @@ -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*/
Expand Down Expand Up @@ -82,7 +83,7 @@ namespace WPEFramework {
}
~Connectivity(){}

nsm_internetState testConnectivity(const std::vector<std::string>& endpoints, long timeout_ms, nsm_ipversion ipversion);
nsm_internetState testConnectivity(const std::vector<std::string>& endpoints, long timeout_ms, nsm_ipversion ipversion, bool connectOnly);
std::vector<std::string> getConnectivityDefaultEndpoints() { return m_defaultEndpoints; };
std::string getCaptivePortal() { const std::lock_guard<std::mutex> lock(capitiveMutex); return g_captivePortal; }
void setCaptivePortal(const char* captivePortal) {const std::lock_guard<std::mutex> lock(capitiveMutex); g_captivePortal = captivePortal; }
Expand Down Expand Up @@ -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());
}
Expand All @@ -134,7 +134,7 @@ namespace WPEFramework {

std::thread thread_;
std::atomic<bool> stopFlag;
std::atomic<bool> threadRunning;
std::atomic<bool> resetTimeout;
std::atomic<bool> isContinuesMonitoringNeeded;
std::condition_variable cv_;
std::atomic<int> timeout;
Expand Down

0 comments on commit 25e7cb5

Please sign in to comment.