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/CHANGELOG.md b/CHANGELOG.md index e687f448..bf748f13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,41 @@ 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) + +> 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) + +> 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) +> 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) diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index fc7b1205..ce64989e 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)) @@ -486,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 { @@ -640,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; } 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..5e273a08 100644 --- a/source/protocol/http/multicurlinterface.c +++ b/source/protocol/http/multicurlinterface.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "multicurlinterface.h" #include "busInterface.h" #include "t2log_wrapper.h" @@ -279,6 +281,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; @@ -661,6 +684,17 @@ 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. + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + OPENSSL_thread_stop(); +#else + ERR_remove_thread_state(NULL); #endif release_pool_handle(idx); return T2ERROR_FAILURE; @@ -784,6 +818,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 +1100,14 @@ 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 +#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); 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/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/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/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 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/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) 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);