Skip to content

Commit

Permalink
RDKTV-29964,DELIA-64899,DELIA-65238: Implement Retry logic in Connect…
Browse files Browse the repository at this point in the history
…ivity Monitoring (rdkcentral#5168) (rdkcentral#5272)

* DELIA-64899: Implement Retry logic in Connectivity Monitoring (rdkcentral#5168)

* DELIA-64899: Implement Retry logic in Connectivity Monitoring (rdkcentral#5115)

* connect only logic added

* connectivity retry logic added

(cherry picked from commit 9a2caf5)

* update getInternetState to connectOnly logic

* CHANGELOG.md updated

* updated restart timeout

* remove config class instance

(cherry picked from commit 9c5593b)

* RDKTV-29964/DELIA-64899 Implement Retry logic in Connectivity Monitoring (rdkcentral#5176)

* DELIA-64899 Implement Retry logic in Connectivity Monitoring
* Increase the timeout to 10s as same as OTA8 release

(cherry picked from commit ca3113e)

* DELIA-65238 - Network failure retry logic timeout remains as 5 sec

Reason for change: Added logic to change the notification count and timeout
to default value, when the global internet state is equal to InternetConnectionState
Test Procedure: Build and verified
Risks: Low
Priority: P1
Signed-off-by: Gururaaja ESR <[email protected]>

* DELIA-65238 - Network failure retry logic timeout remains as 5 sec

Reason for change: Added logic to change the notification count and timeout
to default value, when the global internet state is equal to InternetConnectionState
Test Procedure: Build and verified
Risks: Low
Priority: P1
Signed-off-by: Gururaaja ESR <[email protected]>

---------

Co-authored-by: RAFI <[email protected]>
  • Loading branch information
gururaajar and cmuhammedrafi authored May 13, 2024
1 parent 696f725 commit 229649e
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 63 deletions.
4 changes: 4 additions & 0 deletions Network/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ All notable changes to this RDK Service will be documented in this file.

* For more details, refer to [versioning](https://github.com/rdkcentral/rdkservices#versioning) section under Main README.

## [1.3.10] - 2024-04-17
### Added
- added retry logic for connectivity monitor

## [1.3.9] - 2024-03-29
### Security
- Resolved security vulnerabilities
Expand Down
2 changes: 1 addition & 1 deletion Network/Network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ using namespace std;

#define API_VERSION_NUMBER_MAJOR 1
#define API_VERSION_NUMBER_MINOR 3
#define API_VERSION_NUMBER_PATCH 9
#define API_VERSION_NUMBER_PATCH 10

/* Netsrvmgr Based Macros & Structures */
#define IARM_BUS_NM_SRV_MGR_NAME "NET_SRV_MGR"
Expand Down
1 change: 0 additions & 1 deletion Network/Network.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,6 @@ namespace WPEFramework {
public:
static Network *_instance;
static Network *getInstance() {return _instance;}
Config config;
ConnectivityMonitor connectivityMonitor;

private:
Expand Down
139 changes: 82 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, true);
else
internetState = testConnectivity(getConnectivityDefaultEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, ipversion);
internetState = testConnectivity(getConnectivityDefaultEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, ipversion, true);
}

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 All @@ -273,6 +273,7 @@ namespace WPEFramework {
std::vector<int> http_responses;
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Cache-Control: no-cache, no-store");
chunk = curl_slist_append(chunk, "Connection: close");
for (const auto& endpoint : endpoints)
{
CURL *curl_easy_handle = curl_easy_init();
Expand All @@ -287,7 +288,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 +326,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 +444,6 @@ namespace WPEFramework {
break;
}
}

return InternetConnectionState;
}

Expand All @@ -452,12 +457,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 +476,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 +490,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 +508,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 +516,130 @@ 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);
}
}
else
{
notifyWaitCount = DEFAULT_MONITOR_RETRY_COUNT;
tempTimeout = timeout.load();
}


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());
tempTimeout = 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
8 changes: 4 additions & 4 deletions Network/NetworkConnectivity.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define DEFAULT_MONITOR_TIMEOUT 60 // in seconds
#define MONITOR_TIMEOUT_INTERVAL_MIN 5
#define TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS 10000
#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 229649e

Please sign in to comment.