Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds RBUS-facing support for “profile data” in the Remote Debugger component, allowing a client to select a profile category (persisted locally) and retrieve profile information derived from a JSON configuration file.
Changes:
- Adds new TR-181/RBUS parameter names and handler prototypes for setting/getting profile data.
- Registers/unregisters new RBUS data elements and persists the selected category to a local file.
- Implements RBUS set/get handlers that parse
/etc/rrd/remote_debugger.jsonand return category-filtered results.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
src/rrdInterface.h |
Adds profile-related TR-181 constant definitions and RBUS handler prototypes; introduces a new cJSON include. |
src/rrdInterface.c |
Implements category persistence, registers RBUS data elements, and adds RBUS set/get handlers that parse/format JSON responses. |
| // Data elements for profile data RBUS provider | ||
| rbusDataElement_t profileDataElements[2] = { | ||
| { | ||
| RRD_SET_PROFILE_EVENT, | ||
| RBUS_ELEMENT_TYPE_PROPERTY, | ||
| DATA_HANDLER_SET_MACRO | ||
| }, |
There was a problem hiding this comment.
New RBUS provider globals (profileDataElements / handler macros) are compiled even when GTEST_ENABLE is defined, but the unit test build includes rrdInterface.c with -DGTEST_ENABLE and the mock RBUS headers don’t define rbusDataElement_t / rbus_regDataElements / rbusProperty_t APIs. This will break the gtest build; wrap the provider registration + handlers + data element definitions in #if !defined(GTEST_ENABLE) or extend the mocks to cover the required RBUS types/APIs.
| // Global storage for profile category | ||
| char RRDProfileCategory[256] = "all"; | ||
|
|
||
| // Helper functions for profile category file-based storage | ||
| int load_profile_category(void) { | ||
| FILE *fp = fopen(RRD_PROFILE_CATEGORY_FILE, "r"); | ||
| if (fp) { |
There was a problem hiding this comment.
RRDProfileCategory and the helper functions load_profile_category/save_profile_category are not file-local, so they export new global symbols from rrdInterface.c. Make these static (and consider making the buffer static too) to avoid symbol collisions and accidental external use.
| int save_profile_category(void) { | ||
| FILE *fp = fopen(RRD_PROFILE_CATEGORY_FILE, "w"); | ||
| if (fp) { | ||
| fprintf(fp, "%s\n", RRDProfileCategory); | ||
| fclose(fp); | ||
| return 0; | ||
| } | ||
| return -1; |
There was a problem hiding this comment.
save_profile_category writes to a predictable path under /tmp using plain fopen(...,"w"), which is vulnerable to symlink/hardlink attacks (can overwrite arbitrary files if the process has privileges). Prefer using open() with O_NOFOLLOW|O_CREAT|O_TRUNC and restrictive permissions (e.g., 0600), then fdopen(), or store this state in a non-world-writable directory.
| ret = rbus_regDataElements(rrdRbusHandle, 2, profileDataElements); | ||
| if (ret != RBUS_ERROR_SUCCESS) { | ||
| RDK_LOG(RDK_LOG_ERROR, LOG_REMDEBUG, "[%s:%d]: RBUS regDataElements failed with error: %d\n", __FUNCTION__, __LINE__, ret); | ||
| } else { | ||
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: SUCCESS: RBUS profile data elements registered\n", __FUNCTION__, __LINE__); |
There was a problem hiding this comment.
RRD_subscribe now overwrites ret with the result of rbus_regDataElements, which can mask a prior failure from rbusEvent_SubscribeEx (function may return success even though event subscription failed). Preserve the earlier error (e.g., only register data elements when ret == RBUS_ERROR_SUCCESS, or use a separate variable).
| ret = rbus_regDataElements(rrdRbusHandle, 2, profileDataElements); | |
| if (ret != RBUS_ERROR_SUCCESS) { | |
| RDK_LOG(RDK_LOG_ERROR, LOG_REMDEBUG, "[%s:%d]: RBUS regDataElements failed with error: %d\n", __FUNCTION__, __LINE__, ret); | |
| } else { | |
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: SUCCESS: RBUS profile data elements registered\n", __FUNCTION__, __LINE__); | |
| { | |
| rbusError_t regRet = rbus_regDataElements(rrdRbusHandle, 2, profileDataElements); | |
| if (regRet != RBUS_ERROR_SUCCESS) { | |
| RDK_LOG(RDK_LOG_ERROR, LOG_REMDEBUG, "[%s:%d]: RBUS regDataElements failed with error: %d\n", __FUNCTION__, __LINE__, regRet); | |
| } else { | |
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: SUCCESS: RBUS profile data elements registered\n", __FUNCTION__, __LINE__); | |
| } | |
| if (ret == RBUS_ERROR_SUCCESS) { | |
| ret = regRet; | |
| } |
| // Unregister RBUS data elements for profile data provider | ||
| ret = rbus_unregDataElements(rrdRbusHandle, 2, profileDataElements); | ||
| if (ret != 0) { | ||
| RDK_LOG(RDK_LOG_ERROR, LOG_REMDEBUG, "[%s:%d]: RBUS unregDataElements failed with error: %d\n", __FUNCTION__, __LINE__, ret); | ||
| } else { |
There was a problem hiding this comment.
RRD_unsubscribe assigns ret from rbus_unregDataElements and then immediately overwrites it with rbus_close’s result, so unregistration failures can be lost (function may return success even though unreg failed). Consider preserving the first failure and/or returning a combined error status.
| FILE *fp = fopen(filename, "rb"); | ||
| if (fp) { | ||
| fseek(fp, 0L, SEEK_END); | ||
| long fileSz = ftell(fp); | ||
| rewind(fp); | ||
|
|
||
| if (fileSz > 0 && fileSz < 32768) { | ||
| char *jsonBuffer = malloc(fileSz + 1); | ||
| if (jsonBuffer) { |
There was a problem hiding this comment.
rrd_GetHandler returns RBUS_ERROR_SUCCESS even when file size is out of bounds, malloc fails, fread is short, or JSON parsing fails (and may leave the property unset). Return an appropriate RBUS error and/or set a deterministic empty JSON value on these failure paths.
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: Category %s has nested structure, returning empty\n", | ||
| __FUNCTION__, __LINE__, RRDProfileCategory); | ||
| result_str = cJSON_Print(cJSON_CreateArray()); | ||
| } | ||
| } else { | ||
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: Category %s not found\n", | ||
| __FUNCTION__, __LINE__, RRDProfileCategory); | ||
| result_str = cJSON_Print(cJSON_CreateArray()); |
There was a problem hiding this comment.
Memory leak: cJSON_Print(cJSON_CreateArray()) allocates a cJSON array that is never freed (same pattern appears in both the nested-structure and not-found branches). Create the array in a variable, print it, then cJSON_Delete it after printing.
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: Category %s has nested structure, returning empty\n", | |
| __FUNCTION__, __LINE__, RRDProfileCategory); | |
| result_str = cJSON_Print(cJSON_CreateArray()); | |
| } | |
| } else { | |
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: Category %s not found\n", | |
| __FUNCTION__, __LINE__, RRDProfileCategory); | |
| result_str = cJSON_Print(cJSON_CreateArray()); | |
| cJSON *emptyArray = NULL; | |
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: Category %s has nested structure, returning empty\n", | |
| __FUNCTION__, __LINE__, RRDProfileCategory); | |
| emptyArray = cJSON_CreateArray(); | |
| result_str = cJSON_Print(emptyArray); | |
| cJSON_Delete(emptyArray); | |
| } | |
| } else { | |
| cJSON *emptyArray = NULL; | |
| RDK_LOG(RDK_LOG_DEBUG, LOG_REMDEBUG, "[%s:%d]: Category %s not found\n", | |
| __FUNCTION__, __LINE__, RRDProfileCategory); | |
| emptyArray = cJSON_CreateArray(); | |
| result_str = cJSON_Print(emptyArray); | |
| cJSON_Delete(emptyArray); |
| rbusError_t rrd_SetHandler(rbusHandle_t handle, rbusProperty_t prop, rbusSetHandlerOptions_t* opts) | ||
| { | ||
| (void)handle; | ||
| (void)opts; | ||
|
|
||
| char const* propertyName = rbusProperty_GetName(prop); | ||
| rbusValue_t value = rbusProperty_GetValue(prop); | ||
| rbusValueType_t type = rbusValue_GetType(value); |
There was a problem hiding this comment.
The new RBUS set/get handler behavior (category persistence and JSON response construction) isn’t covered by the existing gtest suite that includes rrdInterface.c. Add unit tests for rrd_SetHandler/rrd_GetHandler covering valid category set, invalid type/oversize input, missing/unreadable JSON file, and category-not-found/nested-category cases.
| #include "rrdCommon.h" | ||
| #if !defined(GTEST_ENABLE) | ||
| #include "rbus.h" | ||
| #include <cjson/cJSON.h> |
There was a problem hiding this comment.
#include <cjson/cJSON.h> in this public header is inconsistent with the rest of the codebase (other headers include "cJSON.h") and may not match the project’s include paths (often -I.../cjson expects "cJSON.h"). Since this header doesn’t expose cJSON types, move the include to the .c file (or switch to the project’s standard include form).
| #include <cjson/cJSON.h> | |
| #include "cJSON.h" |
No description provided.