Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@ All notable changes to this project will be documented in this file. Dates are d

Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [1.1.3](https://github.com/rdkcentral/rfc/compare/1.1.2...1.1.3)

- RDK-57302 : Add support for URL Encoding [`#66`](https://github.com/rdkcentral/rfc/pull/66)
- RDKB-60919: Port Optimized RFCMGR source code to RDKB [`#64`](https://github.com/rdkcentral/rfc/pull/64)
- RDKB-60919: Port Optimized RFCMGR source code to RDKB [`#62`](https://github.com/rdkcentral/rfc/pull/62)
- RDK-57736 [ RFC ] : Increase L1 Test Coverage For RFC above 80% [`#45`](https://github.com/rdkcentral/rfc/pull/45)
- RDKB-60919: Review and cleanup RFC scripts [`13a9c0d`](https://github.com/rdkcentral/rfc/commit/13a9c0d7e4030501e64d2f8d6c8347e1dac6b3aa)
- Update rfc_xconf_handler.cpp [`43c3ccb`](https://github.com/rdkcentral/rfc/commit/43c3ccb8b058838bded67663de543d8c71191023)
- Update rfc_xconf_handler.cpp [`d6ca6b3`](https://github.com/rdkcentral/rfc/commit/d6ca6b328bb3aa38defa5db26dec0c07343bc634)

#### [1.1.2](https://github.com/rdkcentral/rfc/compare/1.1.1...1.1.2)

> 17 July 2025

- RDKEMW-5971: Review and cleanup RFC scripts [`#55`](https://github.com/rdkcentral/rfc/pull/55)
- RDKEMW-5675 [RDKE] onDeviceMgtUpdate sent slightly before RFC processing is complete [`#52`](https://github.com/rdkcentral/rfc/pull/52)
- RDKEMW-5593 [RDKE] Excessive Logging in rfcscript.log curl response [`#51`](https://github.com/rdkcentral/rfc/pull/51)
- 1.1.2 release changelog updates [`5aff2b4`](https://github.com/rdkcentral/rfc/commit/5aff2b469f92859affaa670234017c6983d52516)
- Merge tag '1.1.1' into develop [`77b8f1f`](https://github.com/rdkcentral/rfc/commit/77b8f1f00a13e231cb0e8a13f526809425a1e362)

#### [1.1.1](https://github.com/rdkcentral/rfc/compare/1.1.0...1.1.1)
Expand Down
6 changes: 3 additions & 3 deletions rfcMgr/gtest/gtest_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,18 +515,18 @@ TEST(rfcMgrTest, GetValidPartnerId) {

TEST(rfcMgrTest, CreateXconfHTTPUrl) {
writeToTr181storeFile("WHOAMI_SUPPORT", "true", "/tmp/device.properties", Plain);
writeToTr181storeFile("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.OsClass", "TestOsClass", "/opt/secure/RFC/tr181store.ini", Quoted);
writeToTr181storeFile("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.OsClass", "TestOs Class", "/opt/secure/RFC/tr181store.ini", Quoted);
writeToTr181storeFile("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.AccountInfo.AccountID", "4123705941507160514", "/opt/secure/RFC/tr181store.ini", Quoted);
RuntimeFeatureControlProcessor *rfcObj = new RuntimeFeatureControlProcessor();
rfcObj->_RFCKeyAndValueMap[RFC_PARNER_ID_KEY_STR] = "sky";
rfcObj->_RFCKeyAndValueMap[RFC_PARTNER_ID_KEY_STR] = "sky";
rfcObj->_RFCKeyAndValueMap[XCONF_URL_KEY_STR] = "https://xconf.xdp.eu-1.xcal.tv";
rfcObj->PreProcessJsonResponse(xconfResp);
rfcObj->GetValidPartnerId();
rfcObj->GetOsClass();
rfcObj->GetAccountID();
rfcObj->GetXconfSelect();
std:stringstream url = rfcObj->CreateXconfHTTPUrl();
EXPECT_EQ(url.str(), "https://xconf.xdp.eu-1.xcal.tv?estbMacAddress=&firmwareVersion=&env=&model=&manufacturer=&controllerId=2504&channelMapId=2345&VodId=15660&partnerId=sky&osClass=TestOsClass&accountId=4123705941507160514&Experience=&version=2");
EXPECT_EQ(url.str(), "https://xconf.xdp.eu-1.xcal.tv?estbMacAddress=&firmwareVersion=&env=&model=&manufacturer=&controllerId=2504&channelMapId=2345&VodId=15660&partnerId=sky&osClass=TestOs%20Class&accountId=4123705941507160514&Experience=&version=2");
delete rfcObj;
}

Expand Down
26 changes: 26 additions & 0 deletions rfcMgr/gtest/mocks/urlHelper.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,32 @@ bool checkDeviceInternetConnection(long timeout_ms)
return status;
}

char* urlEncodeString(const char* inputString)
{
if (!inputString) {
SWLOG_ERROR("Input string is NULL in Function %s\n", __FUNCTION__);
return NULL;
}
char* encodedString = NULL;
CURL *curl = curl_easy_init();
if (curl)
{
char *output = curl_easy_escape(curl, inputString, 0);
if (output) {
encodedString = strdup(output);
curl_free(output);
} else {
SWLOG_ERROR("curl_easy_escape failed in Function %s\n", __FUNCTION__);
}
curl_easy_cleanup(curl);
}
else
{
SWLOG_ERROR("Error in curl_easy_init in Function %s\n", __FUNCTION__);
}
return encodedString;
}

// Define your write callback function
size_t writeFunction(void *contents, size_t size, size_t nmemb, void *userp)
{
Expand Down
1 change: 1 addition & 0 deletions rfcMgr/gtest/mocks/urlHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ int allocDowndLoadDataMem( DownloadData *pDwnData, int szDataSize );
bool checkDeviceInternetConnection(long);
size_t writeFunction(void *contents, size_t size, size_t nmemb, void *userp);
void closeFile(DownloadData *data, struct curlprogress *prog, FILE *fp);
char* urlEncodeString(const char* inputString);
#if CURL_DEBUG
CURLcode setCurlDebugOpt(CURL *curl, DbgData_t *debug);
#endif
Expand Down
1 change: 1 addition & 0 deletions rfcMgr/rfc_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#define RFC_MAX_LEN 64

#define RFC_TMP_PATH "/tmp/RFC/tmp"
#define SECURE_RFC_PATH "/opt/secure/RFC"

#define DEFAULT_DL_ALLOC 1024

Expand Down
27 changes: 27 additions & 0 deletions rfcMgr/rfc_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,28 @@ void signal_handler(int sig)
exit(0);
}

bool createDirectoryIfNotExists(const char* path) {
if (!path || *path == '\0') {
RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Invalid path\n", __FUNCTION__, __LINE__);
return false;
}

if (mkdir(path, 0755) == 0) {
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Directory created: %s\n", __FUNCTION__, __LINE__, path);
return true;
}

if (errno == EEXIST) {
struct stat st;
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
return true;
}
}

RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Failed to create directory: %s (%s)\n", __FUNCTION__, __LINE__, path, strerror(errno));
return false;
}

int main()
{
pid_t pid;
Expand All @@ -68,6 +90,11 @@ int main()

rfc::RFCManager* rfcMgr = new rfc::RFCManager();

if (!createDirectoryIfNotExists(SECURE_RFC_PATH)) {
RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] RFC: Failed to create RFC directory\n", __FUNCTION__, __LINE__);
exit(EXIT_FAILURE);
}

RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC: Starting service, creating lock \n", __FUNCTION__, __LINE__);

#if defined(RDKB_SUPPORT)
Expand Down
9 changes: 7 additions & 2 deletions rfcMgr/rfc_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,11 +498,16 @@ namespace rfc {
cronValues[1] = (cronValues[1] == 0) ? 23 : cronValues[1] - 1;
}

// Build adjusted cron string
std::string adjustedCron;
for (size_t i = 0; i < 5; i++) {
if (i > 0) adjustedCron += " ";
adjustedCron += std::to_string(cronValues[i]);

// Use original cronParts if it was a wildcard, otherwise use adjusted cronValues
if (cronParts[i] == "*") {
adjustedCron += "*";
} else {
adjustedCron += std::to_string(cronValues[i]);
}
}

RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Configuring cron job: %s\n", __FUNCTION__, __LINE__, adjustedCron.c_str());
Expand Down
2 changes: 1 addition & 1 deletion rfcMgr/rfc_mgr_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#define BOOTSTRAP_XCONF_URL_KEY_STR "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.XconfUrl"
#endif
#define RFC_ACCOUNT_ID_KEY_STR "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.AccountInfo.AccountID"
#define RFC_PARNER_ID_KEY_STR "Device.DeviceInfo.X_RDKCENTRAL-COM_Syndication.PartnerId"
#define RFC_PARTNER_ID_KEY_STR "Device.DeviceInfo.X_RDKCENTRAL-COM_Syndication.PartnerId"
#define RFC_OSCLASS_KEY_STR "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.OsClass"
#define RFC_PARTNERNAME_KEY_STR "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.PartnerName"
#define RFC_CONFIG_SET_HASH "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Control.ConfigSetHash"
Expand Down
55 changes: 51 additions & 4 deletions rfcMgr/rfc_xconf_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extern "C" {
#include <common_device_api.h>
#include <system_utils.h>
#include <urlHelper.h>

int RuntimeFeatureControlProcessor:: InitializeRuntimeFeatureControlProcessor(void)
{
std::string rfc_file;
Expand Down Expand Up @@ -705,7 +705,7 @@ void RuntimeFeatureControlProcessor::GetAccountID()
RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR, "GetAccountID: AccountID = %s\n", tempbuf);
_accountId = tempbuf;
#ifdef RDKB_SUPPORT
if (access("/tmp/.timeValue", F_OK) != 0)
if (access("/tmp/RFC/.timeValue", F_OK) != 0)
{
// Time file doesn't exist, set AccountID to Unknown
_accountId = "Unknown";
Expand Down Expand Up @@ -1480,6 +1480,28 @@ int RuntimeFeatureControlProcessor::ProcessRuntimeFeatureControlReq()
return result;
}

bool urlencodingInterface(const std::string& input, std::stringstream& output) {
char* temp = urlEncodeString(input.c_str());
if (temp) {
output << temp;
free(temp);
return true;
}
return false;
}

void EncodeString(const std::string& key, const std::string& value, std::stringstream& output, const std::string& appender = "") {
if (!key.empty()) {
output << key;
if (!value.empty()) {
urlencodingInterface(value, output);
}
if (!appender.empty()) {
output << appender;
}
}
}

std::stringstream RuntimeFeatureControlProcessor::CreateXconfHTTPUrl()
{
std::stringstream url;
Expand All @@ -1497,8 +1519,33 @@ std::stringstream RuntimeFeatureControlProcessor::CreateXconfHTTPUrl()
url << "accountId=" << _accountId << "&";
url << "Experience=" << _experience << "&";
url << "version=" << 2;


#ifndef URLENCODING_DISABLED
std::stringstream encodedUrl;
encodedUrl << _xconf_server_url << "?";

EncodeString("estbMacAddress=", _estb_mac_address, encodedUrl, "&");
EncodeString("firmwareVersion=", _firmware_version, encodedUrl, "&");
EncodeString("env=", _build_type_str, encodedUrl, "&");
EncodeString("model=", _model_number, encodedUrl, "&");
EncodeString("manufacturer=", _manufacturer, encodedUrl, "&");

encodedUrl << "controllerId=" << RFC_VIDEO_CONTROL_ID << "&";
encodedUrl << "channelMapId=" << RFC_CHANNEL_MAP_ID << "&";
encodedUrl << "VodId=" << RFC_VIDEO_VOD_ID << "&";

EncodeString("partnerId=", _partner_id, encodedUrl, "&");
EncodeString("osClass=", _osclass, encodedUrl, "&");
EncodeString("accountId=", _accountId, encodedUrl, "&");
EncodeString("Experience=", _experience, encodedUrl, "&");
encodedUrl << "version=2";

RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Encoding is enabled plain URL: %s\n", __FUNCTION__, __LINE__, url.str().c_str());

return encodedUrl; // Use encoded URL
#else
return url;
#endif
}

void RuntimeFeatureControlProcessor::GetStoredHashAndTime( std ::string &valueHash, std::string &valueTime )
Expand Down Expand Up @@ -1873,7 +1920,7 @@ void RuntimeFeatureControlProcessor::GetValidPartnerId()
{
/* Get Valid Partner ID*/

std::string value = _RFCKeyAndValueMap[RFC_PARNER_ID_KEY_STR];
std::string value = _RFCKeyAndValueMap[RFC_PARTNER_ID_KEY_STR];

if(value.empty())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ Feature: RFC Manager XCONF Communication and Error Handling
When the RFC manager binary is run
Then an error message "cURL Return : 0 HTTP Code : 404" should be logged


Scenario: URL Encoding
Given all the properties to run RFC manager is available and running
When RFC manager binary is communicating with XCONF server
Then the URL should be percentage encoded
13 changes: 13 additions & 0 deletions test/functional-tests/tests/rfc_test_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,19 @@ def grep_log_file(log_file: str, search_string: str) -> bool:
print(f"An error occurred while running grep: {e}")
return False

def search_log_file(log_file: str, search_string: str) -> str:
result = subprocess.run(
f'grep -r "{search_string}" {log_file}* | tail -n 1',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
if result.returncode == 0:
return result.stdout
else :
return result.stderr


def rfc_run_binary() -> None:
"""
Expand Down
20 changes: 19 additions & 1 deletion test/functional-tests/tests/test_rfc_xconf_communication.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import os
from rfc_test_helper import *
import urllib.parse



def get_rfc_old_FW() -> str | None:
Expand Down Expand Up @@ -165,12 +167,28 @@ def test_rfcMgr_xconf_communication() -> None:
post_rfc_run_rfc_version = get_rfc_old_FW()
rfc_key1, rfc_value1 = get_tr181_file_key_value()
ERROR_MSG1 = f"COMPLETED RFC PASS"

assert grep_log_file(RFC_LOG_FILE, ERROR_MSG1), f"Expected '{ERROR_MSG1}' in log file."
assert (post_rfc_run_tr181_File != pre_rfc_run_tr181_File), f"'{TR181_INI_FILE}' creation success on rfc run."
assert (pre_rfc_run_rfc_version != post_rfc_run_rfc_version) and (device_fw_version == post_rfc_run_rfc_version), f"'{device_fw_version}' updated in '{TR181_INI_FILE}'"
assert (rfc_key1 == TEST_RFC_PARAM_KEY1) and (rfc_value1 == TEST_RFC_PARAM_VAL1), f"'{TEST_RFC_PARAM_KEY1}' key is set with '{TEST_RFC_PARAM_VAL1} in {TR181_INI_FILE}'"

SEARCH_MSG = f"Encoding is enabled plain URL: "
plain_url = search_log_file(RFC_LOG_FILE,SEARCH_MSG)
SEARCH_MSG_ENCODED = f"Xconf Request : "
encoded_url = search_log_file(RFC_LOG_FILE,SEARCH_MSG_ENCODED)
try:
url = plain_url.split(SEARCH_MSG,1)[1].strip().strip("[]")
print(f"Plain url : {url}")
coded_url = encoded_url.split(SEARCH_MSG_ENCODED,1)[1].strip().strip("[]")
print(f"Encoded url : {coded_url}")
decoded_url = urllib.parse.unquote(coded_url)
print(f"Decoded url : {decoded_url}")
assert url == decoded_url, f"Decoded URL does not match plain URL!\nDecoded: {decoded_url}\nPlain: {url}"
except Exception as e:
print(f"Exception during URL encoding check: {e}")
assert False, f"Exception during URL encoding check: {e}"

finally:
if os.path.exists(RFC_OLD_FW_FILE + "_bak"):
rename_file(RFC_OLD_FW_FILE + "_bak", RFC_OLD_FW_FILE)
Expand Down