From f8114de22069e1c38b6affea7f40edc5dc3332d5 Mon Sep 17 00:00:00 2001 From: tabbas651 <74683978+tabbas651@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:05:58 -0400 Subject: [PATCH 1/9] RDKB-63722:Analyze and fix/mitigate memory leaks from curl_easy_perform calls (#287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * RDKB-63722:Analyze and fix/mitigate memory leaks from curl_easy_perform calls Reason for change: Three compounding sources of unbounded internal state in OpenSSL / libcurl that code failed to constrain: 1] Unbounded connection cache per handle — CURLOPT_MAXCONNECTS was never set. libcurl defaults to 5 cached connection objects per handle. Each cached entry retains a live SSL object (TLS state, session ticket, handshake records). On devices with 180-day uptime where the server resets connections every 30s + each connection having probability of hitting different load balancers, this cache churns and accumulates stale SSL objects over time. 2] SSL session ticket accumulation — CURLOPT_SSL_SESSIONID_CACHE was never disabled. libcurl maintains a session-ticket cache inside each handle's SSL_CTX. Stale tickets from rotated or expired server certs or load balancers remain cached until OpenSSL's 300s session timeout. Across days of uptime with endpoint or cert changes, this accumulates visibly in VmRSS. 3] OpenSSL per-thread error queue not drained— OpenSSL uses a per-thread ERR_STATE list. Every TLS operation that encounters an error (connection reset, cert verify failure, network timeout) pushes records onto this list. The libcurl code never called ERR_clear_error() explicitly, so on any error path the queue has chances to grow indefinitely 4] set CURLOPT_DNS_CACHE_TIMEOUT=30 to bound DNS cache lifetime to the server reset interval, preventing stale IP->hostname mappings from accumulating as load balancer IPs rotate. Test Procedure: please refer the ticket comments Risks: Medium * Addressed the L1 Testcases Compilation Error with respect to multicurlinterface.c * Added the OPENSSL_thread_stop() at the end of worker thread * Reduce Memory Fragmentation to limit the send/receive buffer to 8KB --- source/protocol/http/Makefile.am | 2 +- source/protocol/http/multicurlinterface.c | 41 +++++++++++++++++++++++ source/test/bulkdata/Makefile.am | 4 +-- source/test/dcautils/Makefile.am | 2 +- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/source/protocol/http/Makefile.am b/source/protocol/http/Makefile.am index 460bfa2a..086ec630 100644 --- a/source/protocol/http/Makefile.am +++ b/source/protocol/http/Makefile.am @@ -21,7 +21,7 @@ AM_CFLAGS = lib_LTLIBRARIES = libhttp.la libhttp_la_SOURCES = curlinterface.c multicurlinterface.c -libhttp_la_LDFLAGS = -shared -fPIC -lcurl +libhttp_la_LDFLAGS = -shared -fPIC -lcurl -lcrypto if IS_LIBRDKCERTSEL_ENABLED libhttp_la_CFLAGS = $(LIBRDKCERTSEL_FLAG) libhttp_la_LDFLAGS += -lRdkCertSelector -lrdkconfig diff --git a/source/protocol/http/multicurlinterface.c b/source/protocol/http/multicurlinterface.c index 2d0113dc..bb2c26d8 100644 --- a/source/protocol/http/multicurlinterface.c +++ b/source/protocol/http/multicurlinterface.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "multicurlinterface.h" #include "busInterface.h" #include "t2log_wrapper.h" @@ -279,6 +280,27 @@ T2ERROR init_connection_pool() CURL_SETOPT_CHECK(pool_entries[i].easy_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT); CURL_SETOPT_CHECK(pool_entries[i].easy_handle, CURLOPT_SSL_VERIFYPEER, 1L); + // Memory-bounding options for long-running daemon. + // MAXCONNECTS=1: limits cached connections per handle to one entry + // without this the internal connection cache silently accumulates SSL + // session objects whenever the target IP or cert rotates. + CURL_SETOPT_CHECK(pool_entries[i].easy_handle, CURLOPT_MAXCONNECTS, 1L); + // SSL_SESSIONID_CACHE=0: disables the SSL session-ticket cache in the + // handle's SSL_CTX. + CURL_SETOPT_CHECK(pool_entries[i].easy_handle, CURLOPT_SSL_SESSIONID_CACHE, 0L); + + // Bound DNS cache lifetime to match server reset interval. + // Load balancer IPs rotate; without this limit, stale IP->hostname + // mappings accumulate in the handle's DNS cache alongside stale + // connection objects — same class of problem as MAXCONNECTS. + CURL_SETOPT_CHECK(pool_entries[i].easy_handle, CURLOPT_DNS_CACHE_TIMEOUT, 30L); + + // Limit the receive buffer to 8KB + CURL_SETOPT_CHECK(pool_entries[i].easy_handle, CURLOPT_BUFFERSIZE, 8192L); + + // Limit the send buffer to 8KB (Requires libcurl 7.62.0+) + CURL_SETOPT_CHECK(pool_entries[i].easy_handle, CURLOPT_UPLOAD_BUFFERSIZE, 8192L); + #ifdef LIBRDKCERTSEL_BUILD // Initialize certificate selectors for each easy handle bool state_red_enable = false; @@ -662,6 +684,13 @@ T2ERROR http_pool_get(const char *url, char **response_data, bool enable_file_ou free(pCertPC); } #endif + ERR_clear_error(); + + // Release all OpenSSL per-thread state (ERR stack, cached allocations). + // Called at the end of the worker thread's HTTP operation to prevent + // thread-local memory from accumulating across the daemon lifetime. + OPENSSL_thread_stop(); + release_pool_handle(idx); return T2ERROR_FAILURE; } @@ -784,6 +813,13 @@ T2ERROR http_pool_get(const char *url, char **response_data, bool enable_file_ou // Important Note: When using LIBRDKCERTSEL_BUILD, pCertURI and pCertPC are owned by the // cert selector object and are freed when rdkcertselector_free() is called + // Clear OpenSSL per-thread error queue. + // Every curl_easy_perform() may push records onto the per-thread ERR_STATE + // list on any TLS error (cert verify failure, connection reset, timeout). + // Without this call the list grows unboundedly over the daemon lifetime. + // ERR_clear_error() is thread-safe since OpenSSL 1.1.0. + ERR_clear_error(); + release_pool_handle(idx); T2Debug("%s ++out\n", __FUNCTION__); @@ -1059,6 +1095,11 @@ T2ERROR http_pool_post(const char *url, const char *payload) pCertPC = NULL; } #endif + + // Release all OpenSSL per-thread state at the end of the worker thread's + // HTTP operation (see http_pool_get for rationale) + OPENSSL_thread_stop(); + // Note: When using LIBRDKCERTSEL_BUILD, pCertURI and pCertPC are owned by the // cert selector object and are freed when rdkcertselector_free() is called release_pool_handle(idx); diff --git a/source/test/bulkdata/Makefile.am b/source/test/bulkdata/Makefile.am index b4413819..f89267d4 100644 --- a/source/test/bulkdata/Makefile.am +++ b/source/test/bulkdata/Makefile.am @@ -59,7 +59,7 @@ profile_gtest_bin_CPPFLAGS = -I$(PKG_CONFIG_SYSROOT_DIR)/usr/include/gtest -I$(P profile_gtest_bin_SOURCES = gtest_main.cpp ../mocks/SystemMock.cpp ../mocks/FileioMock.cpp ../mocks/rdklogMock.cpp ../mocks/rbusMock.cpp ../mocks/rdkconfigMock.cpp ../mocks/VectorMock.cpp SchedulerMock.cpp profileMock.cpp ../../bulkdata/profile.c profileTest.cpp ../../utils/persistence.c ../../utils/t2common.c ../../utils/t2collection.c ../../utils/t2MtlsUtils.c ../../utils/t2log_wrapper.c ../../dcautil/dcautil.c ../../dcautil/dca.c ../../dcautil/legacyutils.c ../../dcautil/dcaproc.c ../../xconf-client/xconfclient.c ../../protocol/rbusMethod/rbusmethodinterface.c ../../privacycontrol/rdkservices_privacyutils.c ../../reportgen/reportgen.c ../../bulkdata/t2eventreceiver.c ../../bulkdata/t2markers.c ../../t2parser/t2parser.c ../../bulkdata/datamodel.c ../../t2parser/t2parserxconf.c ../../bulkdata/reportprofiles.c ../../bulkdata/profilexconf.c ../../ccspinterface/rbusInterface.c ../../ccspinterface/busInterface.c ../../protocol/http/curlinterface.c ../../protocol/http/multicurlinterface.c -profile_gtest_bin_LDFLAGS = -L/usr/src/googletest/googletest/lib/.libs -lgcov -L/src/googletest/googlemock/lib -L/usr/src/googletest/googlemock/lib/.libs -L/usr/include/glib-2.0 -lgmock -lcjson -lcurl -lmsgpackc -lgtest -lgtest_main -lglib-2.0 +profile_gtest_bin_LDFLAGS = -L/usr/src/googletest/googletest/lib/.libs -lgcov -L/src/googletest/googlemock/lib -L/usr/src/googletest/googlemock/lib/.libs -L/usr/include/glib-2.0 -lgmock -lcjson -lcurl -lcrypto -lmsgpackc -lgtest -lgtest_main -lglib-2.0 profile_gtest_bin_LDFLAGS += -Wl,--wrap=sendReportOverHTTP -Wl,--wrap=sendCachedReportsOverHTTP @@ -69,7 +69,7 @@ reportprofiles_gtest_bin_CPPFLAGS = -I$(PKG_CONFIG_SYSROOT_DIR)/usr/include/gtes reportprofiles_gtest_bin_SOURCES = gtest_main.cpp ../mocks/SystemMock.cpp ../mocks/FileioMock.cpp ../mocks/rdklogMock.cpp ../mocks/rbusMock.cpp ../mocks/rdkconfigMock.cpp ../mocks/VectorMock.cpp SchedulerMock.cpp reportprofileMock.cpp ../../bulkdata/reportprofiles.c reportprofilesTest.cpp ../../utils/persistence.c ../../utils/t2common.c ../../utils/t2collection.c ../../utils/t2MtlsUtils.c ../../utils/t2log_wrapper.c ../../dcautil/dcautil.c ../../dcautil/dca.c ../../dcautil/legacyutils.c ../../dcautil/dcaproc.c ../../xconf-client/xconfclient.c ../../protocol/rbusMethod/rbusmethodinterface.c ../../privacycontrol/rdkservices_privacyutils.c ../../reportgen/reportgen.c ../../bulkdata/t2eventreceiver.c ../../bulkdata/t2markers.c ../../t2parser/t2parser.c ../../bulkdata/datamodel.c ../../t2parser/t2parserxconf.c ../../bulkdata/profile.c ../../bulkdata/profilexconf.c ../../ccspinterface/rbusInterface.c ../../ccspinterface/busInterface.c ../../protocol/http/curlinterface.c ../../protocol/http/multicurlinterface.c -reportprofiles_gtest_bin_LDFLAGS = -L/usr/src/googletest/googletest/lib/.libs -L/usr/src/googletest/googlemock/lib/.libs -lgmock -lgtest -lpthread -lcjson -lmsgpackc -lglib-2.0 -lrt -lcurl +reportprofiles_gtest_bin_LDFLAGS = -L/usr/src/googletest/googletest/lib/.libs -L/usr/src/googletest/googlemock/lib/.libs -lgmock -lgtest -lpthread -lcjson -lmsgpackc -lglib-2.0 -lrt -lcurl -lcrypto reportprofiles_gtest_bin_LDFLAGS += -Wl,--wrap=isRbusEnabled -Wl,--wrap=sendReportOverHTTP -Wl,--wrap=sendCachedReportsOverHTTP diff --git a/source/test/dcautils/Makefile.am b/source/test/dcautils/Makefile.am index 51c162cc..455e6779 100644 --- a/source/test/dcautils/Makefile.am +++ b/source/test/dcautils/Makefile.am @@ -33,4 +33,4 @@ dcautil_gtest_bin_SOURCES = gtest_main.cpp ../mocks/SystemMock.cpp ../mocks/File #dcautil_gtest_bin_SOURCES = gtest_main.cpp ../mocks/SystemMock.cpp ../mocks/FileioMock.cpp ../mocks/rdklogMock.cpp ../mocks/rbusMock.cpp ../xconf-client/xconfclientTest.cpp ../xconf-client/xconfclientMock.cpp ../mocks/rdkconfigMock.cpp ../../utils/persistence.c ../../utils/t2common.c ../../utils/t2collection.c ../../utils/vector.c ../../utils/t2MtlsUtils.c ../../utils/t2log_wrapper.c ../../dcautil/dcautil.c ../../dcautil/dca.c ../../dcautil/legacyutils.c ../../dcautil/dcaproc.c ../../commonlib/telemetry_busmessage_sender.c ../../xconf-client/xconfclient.c ../../protocol/http/curlinterface.c ../../protocol/rbusMethod/rbusmethodinterface.c ../../privacycontrol/rdkservices_privacyutils.c ../../reportgen/reportgen.c ../../t2parser/t2parser.c -dcautil_gtest_bin_LDFLAGS = -L/usr/src/googletest/googletest/lib/.libs -lgcov -L/src/googletest/googlemock/lib -L/usr/src/googletest/googlemock/lib/.libs -L/usr/include/glib-2.0 -lgmock -lcjson -lcurl -lmsgpackc -lgtest -lgtest_main -lglib-2.0 +dcautil_gtest_bin_LDFLAGS = -L/usr/src/googletest/googletest/lib/.libs -lgcov -L/src/googletest/googlemock/lib -L/usr/src/googletest/googlemock/lib/.libs -L/usr/include/glib-2.0 -lgmock -lcjson -lcurl -lcrypto -lmsgpackc -lgtest -lgtest_main -lglib-2.0 From 28b542668e814411234f0a0d594e5c5d35b98319 Mon Sep 17 00:00:00 2001 From: shibu-kv Date: Wed, 18 Mar 2026 16:33:47 -0700 Subject: [PATCH 2/9] Changelog updates for release 1.8.2 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e687f448..a006a076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,19 @@ 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.8.2](https://github.com/rdkcentral/telemetry/compare/1.8.1...1.8.2) + +- RDKB-63722:Analyze and fix/mitigate memory leaks from curl_easy_perform calls [`#287`](https://github.com/rdkcentral/telemetry/pull/287) +- Agentic development and maintenance support [`#278`](https://github.com/rdkcentral/telemetry/pull/278) +- RDKEMW-10467: Fix Invalid time values caused by drift [`#212`](https://github.com/rdkcentral/telemetry/pull/212) + #### [1.8.1](https://github.com/rdkcentral/telemetry/compare/1.8.0...1.8.1) +> 27 February 2026 + - RDK-60476: Reduce default connection pool size to 1 [`#260`](https://github.com/rdkcentral/telemetry/pull/260) - RDK-60805: Adding L1 unit test cases for reportprofiles [`#265`](https://github.com/rdkcentral/telemetry/pull/265) +- Changelog updates for 1.8.1 release [`074a1d3`](https://github.com/rdkcentral/telemetry/commit/074a1d32e33924ce0f39e7cd7aad5bd6750376d4) #### [1.8.0](https://github.com/rdkcentral/telemetry/compare/1.7.4...1.8.0) From fc678f5eb70cb427bb2760a51fd02d76b226bcb3 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Thu, 19 Mar 2026 20:28:48 +0530 Subject: [PATCH 3/9] RDKB-63722: Build fix for ssl crypto error in platforms with lower ssl version (#291) * RDKB-63722: Update multicurlinterface.c * RDKB-63722: Build fix * RDKB-63722: Build fix * astyle formatter error changes are addressed --------- Co-authored-by: tabbas651 --- source/protocol/http/multicurlinterface.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/source/protocol/http/multicurlinterface.c b/source/protocol/http/multicurlinterface.c index bb2c26d8..5e273a08 100644 --- a/source/protocol/http/multicurlinterface.c +++ b/source/protocol/http/multicurlinterface.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "multicurlinterface.h" #include "busInterface.h" #include "t2log_wrapper.h" @@ -689,8 +690,12 @@ T2ERROR http_pool_get(const char *url, char **response_data, bool enable_file_ou // Release all OpenSSL per-thread state (ERR stack, cached allocations). // Called at the end of the worker thread's HTTP operation to prevent // thread-local memory from accumulating across the daemon lifetime. - OPENSSL_thread_stop(); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + OPENSSL_thread_stop(); +#else + ERR_remove_thread_state(NULL); +#endif release_pool_handle(idx); return T2ERROR_FAILURE; } @@ -1097,9 +1102,12 @@ T2ERROR http_pool_post(const char *url, const char *payload) #endif // Release all OpenSSL per-thread state at the end of the worker thread's - // HTTP operation (see http_pool_get for rationale) + // HTTP operation +#if OPENSSL_VERSION_NUMBER >= 0x10100000L OPENSSL_thread_stop(); - +#else + ERR_remove_thread_state(NULL); +#endif // Note: When using LIBRDKCERTSEL_BUILD, pCertURI and pCertPC are owned by the // cert selector object and are freed when rdkcertselector_free() is called release_pool_handle(idx); From cac6d7f0182481bb1d1664bd0bc1afce9e429e25 Mon Sep 17 00:00:00 2001 From: shibu-kv Date: Thu, 19 Mar 2026 08:02:28 -0700 Subject: [PATCH 4/9] Changelog updates for 1.8.3 release --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a006a076..94130170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,18 @@ 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.8.3](https://github.com/rdkcentral/telemetry/compare/1.8.2...1.8.3) + +- RDKB-63722: Build fix for ssl crypto error in platforms with lower ssl version [`#291`](https://github.com/rdkcentral/telemetry/pull/291) + #### [1.8.2](https://github.com/rdkcentral/telemetry/compare/1.8.1...1.8.2) +> 18 March 2026 + - RDKB-63722:Analyze and fix/mitigate memory leaks from curl_easy_perform calls [`#287`](https://github.com/rdkcentral/telemetry/pull/287) - Agentic development and maintenance support [`#278`](https://github.com/rdkcentral/telemetry/pull/278) - RDKEMW-10467: Fix Invalid time values caused by drift [`#212`](https://github.com/rdkcentral/telemetry/pull/212) +- Changelog updates for release 1.8.2 [`28b5426`](https://github.com/rdkcentral/telemetry/commit/28b542668e814411234f0a0d594e5c5d35b98319) #### [1.8.1](https://github.com/rdkcentral/telemetry/compare/1.8.0...1.8.1) From 0f752617f4a15a30072da264b04eb125a6ec9fd9 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Sat, 21 Mar 2026 06:41:51 +0530 Subject: [PATCH 5/9] RDKB-63834: Reject and Remove Corrupted Config Files In Persistance (#284) * RDKB-63834: Reject and Remove Corrupted Config Files In Persistance Signed-off-by: Yogeswaran K * RDKB-63834: Add unit tests for empty config file detection and fprintf failure paths in persistence.c (#285) * Initial plan * Add unit tests for empty config file detection and fprintf failure in persistence.c Co-authored-by: shibu-kv <89052442+shibu-kv@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: shibu-kv <89052442+shibu-kv@users.noreply.github.com> --------- Signed-off-by: Yogeswaran K Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: shibu-kv <89052442+shibu-kv@users.noreply.github.com> --- .gitignore | 36 +++++++++++++ source/test/mocks/FileioMock.cpp | 16 ++++++ source/test/utils/UtilsTest.cpp | 92 ++++++++++++++++++++++++++------ source/utils/persistence.c | 16 +++++- 4 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..942913b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Build system generated files +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +compile +config.guess +config.log +config.status +config.sub +configure +configure~ +depcomp +install-sh +libtool +ltmain.sh +missing +m4/ + +# Build artifacts +*.o +*.lo +*.la +*.a +*.so +*.bin +*.deps/ +*.dirstamp +.deps/ +.libs/ + +# Source subdirectory build files +source/**/Makefile +source/**/Makefile.in +source/**/*.deps/ +source/**/.libs/ diff --git a/source/test/mocks/FileioMock.cpp b/source/test/mocks/FileioMock.cpp index 60e19aaf..59f33257 100644 --- a/source/test/mocks/FileioMock.cpp +++ b/source/test/mocks/FileioMock.cpp @@ -473,6 +473,22 @@ extern "C" int fprintf(FILE* stream, const char* format, ...) { va_end(args); return result; } + +/* Intercept the FORTIFY_SOURCE-hardened variant of fprintf */ +extern "C" int __fprintf_chk(FILE* stream, int /*flag*/, const char* format, ...) { + va_list args; + va_start(args, format); + int result = -1; + + if (g_fileIOMock) { + result = g_fileIOMock->fprintf(stream, format, args); + } + else { + result = vfprintf(stream, format, args); + } + va_end(args); + return result; +} /* extern "C" CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...) { diff --git a/source/test/utils/UtilsTest.cpp b/source/test/utils/UtilsTest.cpp index 2327539a..71d5a834 100644 --- a/source/test/utils/UtilsTest.cpp +++ b/source/test/utils/UtilsTest.cpp @@ -50,6 +50,7 @@ using namespace std; using ::testing::_; using ::testing::Return; using ::testing::StrEq; +using ::testing::Invoke; //Testing t2MtlsUtils TEST(GET_CERTS, MTLS_UTILS_NULL) @@ -770,6 +771,49 @@ TEST_F(utilsTestFixture, FETCHLOCALCONFIGS_FUNC4) Vector_Destroy(configlist, free); } +TEST_F(utilsTestFixture, FETCHLOCALCONFIGS_EMPTY_FILE) +{ + const char* path = "/opt/.t2persistentFolder/"; + DIR *dir = (DIR*)0xffffffff; + Vector* configlist = NULL; + Vector_Create(&configlist); + struct dirent *entry = NULL; + entry = (struct dirent *)malloc(sizeof(struct dirent)); + entry->d_type = DT_REG; + std::strncpy(entry->d_name, "TestProfile.json", sizeof(entry->d_name) - 1); + entry->d_name[sizeof(entry->d_name) - 1] = '\0'; + EXPECT_CALL(*g_fileIOMock, opendir(_)) + .Times(1) + .WillOnce(Return(dir)); + EXPECT_CALL(*g_fileIOMock, readdir(_)) + .Times(2) + .WillOnce(Return(entry)) + .WillOnce(Return((struct dirent *)NULL)); + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_fileIOMock, fstat(_,_)) + .Times(1) + .WillOnce(Invoke([](int /*fd*/, struct stat* buf) -> int { + memset(buf, 0, sizeof(struct stat)); + buf->st_size = 0; + return 0; + })); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, closedir(_)) + .Times(1) + .WillOnce(Return(0)); + ASSERT_EQ(T2ERROR_SUCCESS, fetchLocalConfigs(path, configlist)); + EXPECT_EQ(0, (int)Vector_Size(configlist)); + Vector_Destroy(configlist, free); + free(entry); +} + #if defined (MTLS_FROM_ENV) TEST(GetMtlsCertsTest, ReturnsDynamicCertsWhenEnvSet) { setenv("XPKI", "1", 1); @@ -915,28 +959,44 @@ TEST_F(utilsTestFixture, SAVECONFITOFILE1) .WillOnce(Return(mockfp)); ASSERT_EQ(T2ERROR_FAILURE, saveConfigToFile(filepath, profilename, config)); } -/* -TEST_F(utilsTestFixture, SAVECONFITOFILE2) +TEST_F(utilsTestFixture, SAVECONFITOFILE_FPRINTF_FAILURE) { - const char* filepath = "/nvram/.t2reportprofiles"; - const char* profilename = "Profile_1"; - const char* config = "This is a config string"; - FILE* mockfp = (FILE *)0xffffffff; - + const char* filepath = "/nvram/.t2reportprofiles/"; + const char* profilename = "Profile_1"; + const char* config = "This is a config string"; + FILE* mockfp = (FILE *)0xffffffff; EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(mockfp)); + .Times(1) + .WillOnce(Return(mockfp)); EXPECT_CALL(*g_fileIOMock, fprintf(_,_,_)) - .Times(1) - .WillOnce(Return(-1)); + .Times(1) + .WillOnce(Return(-1)); EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(saveConfigToFile(filepath, profilename, config), T2ERROR_SUCCESS); + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(1) + .WillOnce(Return(0)); + ASSERT_EQ(T2ERROR_FAILURE, saveConfigToFile(filepath, profilename, config)); +} +TEST_F(utilsTestFixture, SAVECONFITOFILE_SUCCESS) +{ + const char* filepath = "/nvram/.t2reportprofiles/"; + const char* profilename = "Profile_1"; + const char* config = "This is a config string"; + FILE* mockfp = (FILE *)0xffffffff; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(mockfp)); + EXPECT_CALL(*g_fileIOMock, fprintf(_,_,_)) + .Times(1) + .WillOnce(Return((int)strlen(config))); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + ASSERT_EQ(T2ERROR_SUCCESS, saveConfigToFile(filepath, profilename, config)); } -*/ TEST_F(utilsTestFixture, getDevicePropertyData) { diff --git a/source/utils/persistence.c b/source/utils/persistence.c index 253ec412..065983fa 100644 --- a/source/utils/persistence.c +++ b/source/utils/persistence.c @@ -112,6 +112,14 @@ T2ERROR fetchLocalConfigs(const char* path, Vector *configList) if(status == 0) { T2Info("Filename : %s Size : %ld\n", entry->d_name, (long int)filestat.st_size); + // Skip empty profile files + if(filestat.st_size == 0) + { + T2Warning("Skipping empty config file : %s\n", entry->d_name); + close(fp); + removeProfileFromDisk(path, entry->d_name); + continue; + } Config *config = (Config *)malloc(sizeof(Config)); memset(config, 0, sizeof(Config)); @@ -168,7 +176,13 @@ T2ERROR saveConfigToFile(const char* path, const char *profileName, const char* T2Error("Unable to write to file : %s\n", filePath); return T2ERROR_FAILURE; } - fprintf(fp, "%s", configuration); + if(fprintf(fp, "%s", configuration) < 0) + { + T2Error("Failed to write to file : %s\n", filePath); + fclose(fp); + removeProfileFromDisk(path, profileName); + return T2ERROR_FAILURE; + } if(fclose(fp) != 0) { T2Error("Unable to close file : %s\n", filePath); From 36848b6d3d0308518c1fba0e9e2171138476af14 Mon Sep 17 00:00:00 2001 From: Priya_Dharshini Date: Tue, 24 Mar 2026 02:45:13 +0530 Subject: [PATCH 6/9] RDKEMW-15233 [SERXIONE-8445/XIONE-18418] Develop Support Branch Integration (#295) * Modify the set_logdemand value as true for all scenarios except LOG_UPLOAD * Formatting the code changes * Modify the misleading function and variable names --- source/bulkdata/reportprofiles.c | 1 - source/scheduler/scheduler.c | 22 +++++++++++----------- source/scheduler/scheduler.h | 4 ++-- source/telemetry2_0.c | 3 +-- source/test/bulkdata/SchedulerMock.cpp | 8 ++++---- source/test/bulkdata/SchedulerMock.h | 4 ++-- source/test/bulkdata/profileTest.cpp | 4 ++-- source/test/scheduler/schedulerTest.cpp | 8 ++++---- 8 files changed, 26 insertions(+), 28 deletions(-) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index fc7b1205..c53abd19 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -428,7 +428,6 @@ static void* reportOnDemand(void *input) if(!strncmp(action, ON_DEMAND_ACTION_UPLOAD, MAX_PROFILENAMES_LENGTH)) { T2Info("Upload XCONF report on demand \n"); - set_logdemand(true); generateDcaReport(false, true); } else if(!strncmp(action, ON_DEMAND_ACTION_ABORT, MAX_PROFILENAMES_LENGTH)) diff --git a/source/scheduler/scheduler.c b/source/scheduler/scheduler.c index c6fdbf78..5c9d3195 100644 --- a/source/scheduler/scheduler.c +++ b/source/scheduler/scheduler.c @@ -44,21 +44,21 @@ static ActivationTimeoutCB activationTimeoutCb; static Vector *profileList = NULL; static pthread_mutex_t scMutex; static bool sc_initialized = false; -static bool islogdemand = false; +static bool isretainSeekmap = true; static bool signalrecived_and_executing = true; static bool is_activation_time_out = false; -bool get_logdemand () +bool get_retainseekmap () { - T2Info(("get_logdemand ++in\n")); - return islogdemand; + T2Info(("get_retainseekmap ++in\n")); + return isretainSeekmap; } -void set_logdemand (bool value) +void set_retainseekmap (bool value) { - T2Info(("set_logdemand ++in\n")); - islogdemand = value; + T2Info(("set_retainseekmap ++in\n")); + isretainSeekmap = value; } void freeSchedulerProfile(void *data) @@ -297,14 +297,14 @@ void* TimeoutThread(void *arg) if(minThresholdTime == 0) { - if (get_logdemand() == true) + if (get_retainseekmap() == true) { - set_logdemand(false); - timeoutNotificationCb(tProfile->name, false); + timeoutNotificationCb(tProfile->name, false); // Passing clearseekvalue as false } else { - timeoutNotificationCb(tProfile->name, true); + set_retainseekmap(true); //After triggering LOG upload resetting the retainseekmap value to true so the next report generation doesn't affect + timeoutNotificationCb(tProfile->name, true); //Passing clearseek value as true } if(tProfile->terminated) { diff --git a/source/scheduler/scheduler.h b/source/scheduler/scheduler.h index 5bee6b9d..356cf398 100644 --- a/source/scheduler/scheduler.h +++ b/source/scheduler/scheduler.h @@ -60,8 +60,8 @@ T2ERROR unregisterProfileFromScheduler(const char* profileName); T2ERROR SendInterruptToTimeoutThread(char* profileName); -bool get_logdemand(); +bool get_retainseekmap(); -void set_logdemand(bool value); +void set_retainseekmap(bool value); #endif /* _SCHEDULER_H_ */ diff --git a/source/telemetry2_0.c b/source/telemetry2_0.c index 9acd53ee..bb92e5a6 100644 --- a/source/telemetry2_0.c +++ b/source/telemetry2_0.c @@ -181,13 +181,12 @@ void sig_handler(int sig, siginfo_t* info, void* uc) else if ( sig == SIGUSR1 || sig == LOG_UPLOAD ) { T2Info(("LOG_UPLOAD received!\n")); - set_logdemand(false); + set_retainseekmap(false); ReportProfiles_Interrupt(); } else if (sig == LOG_UPLOAD_ONDEMAND || sig == SIGIO) { T2Info(("LOG_UPLOAD_ONDEMAND received!\n")); - set_logdemand(true); ReportProfiles_Interrupt(); } else if(sig == SIGUSR2 || sig == EXEC_RELOAD) diff --git a/source/test/bulkdata/SchedulerMock.cpp b/source/test/bulkdata/SchedulerMock.cpp index 49af8bfa..0611b642 100755 --- a/source/test/bulkdata/SchedulerMock.cpp +++ b/source/test/bulkdata/SchedulerMock.cpp @@ -85,22 +85,22 @@ T2ERROR SendInterruptToTimeoutThread(char* profileName) return T2ERROR_SUCCESS; } -bool get_logdemand() +bool get_retainseekmap() { if (g_schedulerMock) { - return g_schedulerMock->get_logdemand(); + return g_schedulerMock->get_retainseekmap(); } // Fallback implementation for when mock is not set return false; } -void set_logdemand(bool value) +void set_retainseekmap(bool value) { if (g_schedulerMock) { - g_schedulerMock->set_logdemand(value); + g_schedulerMock->set_retainseekmap(value); return; } diff --git a/source/test/bulkdata/SchedulerMock.h b/source/test/bulkdata/SchedulerMock.h index 42bd26b7..ad1c6d30 100755 --- a/source/test/bulkdata/SchedulerMock.h +++ b/source/test/bulkdata/SchedulerMock.h @@ -35,8 +35,8 @@ class SchedulerMock MOCK_METHOD(T2ERROR, registerProfileWithScheduler, (const char* profileName, unsigned int timeInterval, unsigned int activationTimeout, bool deleteonTimout, bool repeat, bool reportOnUpdate, unsigned int firstReportingInterval, char *timeRef), ()); MOCK_METHOD(T2ERROR, unregisterProfileFromScheduler, (const char* profileName), ()); MOCK_METHOD(T2ERROR, SendInterruptToTimeoutThread, (char* profileName), ()); - MOCK_METHOD(bool, get_logdemand, (), ()); - MOCK_METHOD(void, set_logdemand, (bool value), ()); + MOCK_METHOD(bool, get_retainseekmap, (), ()); + MOCK_METHOD(void, set_retainseekmap, (bool value), ()); MOCK_METHOD(int, getLapsedTime, (struct timespec *result, struct timespec *x, struct timespec *y), ()); }; diff --git a/source/test/bulkdata/profileTest.cpp b/source/test/bulkdata/profileTest.cpp index 09108f6d..f2b43205 100644 --- a/source/test/bulkdata/profileTest.cpp +++ b/source/test/bulkdata/profileTest.cpp @@ -823,8 +823,8 @@ TEST_F(ProfileTest, privacymode_do_not_share) { } TEST_F(ProfileTest, generateDcaReport) { - // generateDcaReport may call set_logdemand - EXPECT_CALL(*g_schedulerMock, set_logdemand(_)) + // generateDcaReport may call set_retainseekmap + EXPECT_CALL(*g_schedulerMock, set_retainseekmap(_)) .Times(::testing::AtMost(2)); // Allow up to 2 calls generateDcaReport(false, true); diff --git a/source/test/scheduler/schedulerTest.cpp b/source/test/scheduler/schedulerTest.cpp index 3f44961a..53ec7ada 100644 --- a/source/test/scheduler/schedulerTest.cpp +++ b/source/test/scheduler/schedulerTest.cpp @@ -123,14 +123,14 @@ class rdklogTestFixture : public ::testing::Test { }; -TEST(GET_LOGDEMAND, TEST1) +TEST(GET_RETAINSEEKMAP, TEST1) { - EXPECT_EQ( false, get_logdemand()); + EXPECT_EQ( true, get_retainseekmap()); } -TEST(SET_LOGDEMAND, TEST1) +TEST(SET_RETAINSEEKMAP, TEST1) { - set_logdemand(true); + set_retainseekmap(true); } TEST(GETLAPSEDTIME, T1_GT_T2) From a336d80cd23321dee1defba998cb6460b3474b31 Mon Sep 17 00:00:00 2001 From: shibu-kv Date: Mon, 23 Mar 2026 14:18:16 -0700 Subject: [PATCH 7/9] Changelog updates for 1.8.4 release --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94130170..6a08e351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,17 @@ 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.8.4](https://github.com/rdkcentral/telemetry/compare/1.8.3...1.8.4) + +- RDKEMW-15233 [SERXIONE-8445/XIONE-18418] Develop Support Branch Integration [`#295`](https://github.com/rdkcentral/telemetry/pull/295) +- RDKB-63834: Reject and Remove Corrupted Config Files In Persistance [`#284`](https://github.com/rdkcentral/telemetry/pull/284) + #### [1.8.3](https://github.com/rdkcentral/telemetry/compare/1.8.2...1.8.3) +> 19 March 2026 + - RDKB-63722: Build fix for ssl crypto error in platforms with lower ssl version [`#291`](https://github.com/rdkcentral/telemetry/pull/291) +- Changelog updates for 1.8.3 release [`cac6d7f`](https://github.com/rdkcentral/telemetry/commit/cac6d7f0182481bb1d1664bd0bc1afce9e429e25) #### [1.8.2](https://github.com/rdkcentral/telemetry/compare/1.8.1...1.8.2) From 2223703cca8eb5b73f5b4edbecca6c7ebb93bb88 Mon Sep 17 00:00:00 2001 From: Priya_Dharshini Date: Tue, 24 Mar 2026 20:56:42 +0530 Subject: [PATCH 8/9] =?UTF-8?q?RDKEMW-15233:[SERXIONE-8445/XIONE-18418]=20?= =?UTF-8?q?Develop=20Support=20Branch=20Integ=E2=80=A6=20(#299)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * RDKEMW-15233:[SERXIONE-8445/XIONE-18418] Develop Support Branch Integration Signed-off-by: PriyaDharshini_Kathiravan * Update source/bulkdata/reportprofiles.c Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add debug messages for seekmap and marker values --------- Signed-off-by: PriyaDharshini_Kathiravan Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- source/bulkdata/reportprofiles.c | 7 ++++--- source/dcautil/dca.c | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index c53abd19..ce64989e 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -485,6 +485,10 @@ T2ERROR initReportProfiles() drop_root(); #endif + //Initialise the properties file RDK-58222 + T2InitProperties(); + T2Info("Initializing properties\n"); + #if defined (PRIVACYMODES_CONTROL) // Define scope { @@ -639,9 +643,6 @@ T2ERROR initReportProfiles() } - //Initialise the properties file RDK-58222 - T2InitProperties(); - T2Info("InitProperties is successful\n"); // This indicates telemetry has started FILE* bootFlag = NULL ; diff --git a/source/dcautil/dca.c b/source/dcautil/dca.c index 581a7832..8975f2ce 100644 --- a/source/dcautil/dca.c +++ b/source/dcautil/dca.c @@ -379,7 +379,7 @@ static int getLogSeekValue(hash_map_t *logSeekMap, const char *name, long *seek_ T2Debug("logSeekMap is null .. Setting seek value to 0 \n"); *seek_value = 0 ; } - + T2Debug("seekvalue for file %s is %ld\n", name, *seek_value); T2Debug("%s --out \n", __FUNCTION__); return rc; } @@ -524,6 +524,7 @@ static int getCountPatternMatch(FileDescriptor* fileDescriptor, GrepMarker* mark // Using the union for efficient memory handling marker->u.count = count; + T2Debug("Count Marker: Marker = %s Value %d\n", marker->markerName, marker->u.count); T2Debug("%s --out\n", __FUNCTION__); return 0; } @@ -634,7 +635,7 @@ static int getAbsolutePatternMatch(FileDescriptor* fileDescriptor, GrepMarker* m { marker->u.markerValue = result; } - + T2Debug("Absolute Marker: Marker = %s Value %s\n", marker->markerName, marker->u.markerValue); T2Debug("%s --out\n", __FUNCTION__); return 0; } From 3d2397047795a728ab1a22ce439c4743cf8a84e1 Mon Sep 17 00:00:00 2001 From: shibu-kv Date: Tue, 24 Mar 2026 08:29:47 -0700 Subject: [PATCH 9/9] Changelog updates for release 1.8.5 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a08e351..bf748f13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,17 @@ 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.8.5](https://github.com/rdkcentral/telemetry/compare/1.8.4...1.8.5) + +- RDKEMW-15233: Previous log look up initialiation corrections [`#299`](https://github.com/rdkcentral/telemetry/pull/299) + #### [1.8.4](https://github.com/rdkcentral/telemetry/compare/1.8.3...1.8.4) +> 23 March 2026 + - RDKEMW-15233 [SERXIONE-8445/XIONE-18418] Develop Support Branch Integration [`#295`](https://github.com/rdkcentral/telemetry/pull/295) - RDKB-63834: Reject and Remove Corrupted Config Files In Persistance [`#284`](https://github.com/rdkcentral/telemetry/pull/284) +- Changelog updates for 1.8.4 release [`a336d80`](https://github.com/rdkcentral/telemetry/commit/a336d80cd23321dee1defba998cb6460b3474b31) #### [1.8.3](https://github.com/rdkcentral/telemetry/compare/1.8.2...1.8.3)