diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d44975fd..2f2c89fe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1,84 @@ -If you would like to contribute code to this project you can do so through GitHub by forking the repository and sending a pull request. Before RDK accepts your code into the project you must sign the RDK Contributor License Agreement (CLA). +# Contributing to RFC + +Thank you for your interest in contributing to the Remote Feature Control (RFC) project! + +--- + +## Getting Started + +1. **Fork** the repository on GitHub +2. **Clone** your fork locally +3. **Create** a feature branch from `develop`: + ```bash + git checkout -b feature/JIRA-XXXX-description develop + ``` +4. **Build** and verify your changes: + ```bash + autoreconf -i + ./configure --enable-gtestapp + make && make check + ``` +5. **Commit** with a clear message referencing the JIRA ticket +6. **Push** your branch and open a Pull Request against `develop` + +--- + +## Branch Naming + +| Type | Pattern | Example | +|------|---------|---------| +| Feature | `feature/JIRA-XXXX-short-desc` | `feature/RDKC-15902-camera-support` | +| Bugfix | `bugfix/JIRA-XXXX-short-desc` | `bugfix/DELIA-69554-cert-retry` | +| Release | `release/X.Y.Z` | `release/1.2.3` | + +--- + +## Coding Standards + +- **C++ Standard:** C++11 minimum +- **Platform guards:** Use `#ifdef RDKC`, `#ifdef RDKB_SUPPORT`, or `#ifndef` blocks for platform-specific code +- **Comments:** Use Doxygen-style documentation (`/** @brief ... */`, `@param`, `@return`) +- **Logging:** Use `RDK_LOG_*` macros with appropriate log levels +- **Security:** Use `v_secure_system()` / `v_secure_popen()` instead of raw `system()` / `popen()` + +--- + +## Pull Request Checklist + +- [ ] Code compiles for all target platforms (STB, RDKB, RDKC) +- [ ] Unit tests pass (`make check`) +- [ ] New functionality includes corresponding tests +- [ ] No Coverity or static analysis warnings introduced +- [ ] Platform-specific code is properly guarded with `#ifdef` +- [ ] Documentation updated if architecture changes were made + +--- + +## Testing + +```bash +# Unit tests (L1) +./run_ut.sh + +# Integration tests (L2) +./run_l2.sh + +# Reboot trigger tests +./run_l2_reboot_trigger.sh +``` + +--- + +## Contributor License Agreement + +Before RDK accepts your code into the project you must sign the [RDK Contributor License Agreement (CLA)](https://wiki.rdkcentral.com/display/DOC/Contributor+License+Agreement). + +--- + +## Repository Documentation + +For architecture details, diagrams, and data flow documentation, see the [documentation/](documentation/) folder: + +- [Architecture](documentation/architecture.md) — Component architecture, class hierarchy, build system +- [Sequence Diagrams](documentation/sequence-diagrams.md) — End-to-end execution flows +- [Data Processing Flow](documentation/data-processing-flow.md) — Parameter lifecycle and storage strategies diff --git a/Makefile.am b/Makefile.am index ccd9619c..ee691f19 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # limitations under the License. ########################################################################## if ENABLE_RDKC -SUBDIRS = rfcapi +SUBDIRS = rfcapi rfcMgr else if ENABLE_RDKB SUBDIRS = rfcMgr diff --git a/README.md b/README.md index b1e0ea93..b27efa31 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,28 @@ -# RFC — Remote Feature Control Module +# RFC — Remote Feature Control + +[![Build](https://img.shields.io/badge/build-autotools-blue)](#building) +[![License](https://img.shields.io/badge/license-Apache%202.0-green)](LICENSE) +[![Platform](https://img.shields.io/badge/platform-STB%20%7C%20RDKB%20%7C%20RDKC-orange)](#platform-support) + +> C++ daemon and API library for fetching, applying, and managing Remote Feature Control (RFC) settings from an Xconf configuration server across RDK device platforms. + +--- + +## Table of Contents + +- [Overview](#overview) +- [Platform Support](#platform-support) +- [Repository Structure](#repository-structure) +- [Architecture Overview](#architecture-overview) +- [Building](#building) +- [Configuration](#configuration) +- [Usage](#usage) +- [Testing](#testing) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [License](#license) + +--- ## Overview @@ -6,6 +30,29 @@ The RFC (Remote Feature Control) module enables dynamic configuration of RDK dev Licensed under the Apache License 2.0. Copyright 2016–2024 RDK Management. +**rfcMgr** is a C++ daemon that replaces the legacy shell-based `RFCbase.sh` for Remote Feature Control. It: + +1. **Detects** when the device is online +2. **Collects** device identity (MAC, firmware, model, partner ID, account ID) +3. **Queries** the Xconf server for feature-control configuration +4. **Applies** RFC parameters to the local device +5. **Evaluates** whether a reboot is needed for `effectiveImmediate` features +6. **Schedules** periodic re-checks via cron + +The **rfcapi** library provides a public C API (`getRFCParameter`, `setRFCParameter`, `isRFCEnabled`) for other RDK components to read/write RFC parameters. + +--- + +## Platform Support + +| Platform | Define Flag | Description | +|----------|-------------|-------------| +| **STB** | *(default)* | Set-Top Box — uses hostif/WDMP APIs, TR-181 data model | +| **RDKB** | `-DRDKB_SUPPORT` | RDK Broadband — uses rbus for TR-181 access | +| **RDKC** | `-DRDKC` | RDK Camera (XHC1/XCAM2) — flat-file parameter storage, mfrApi for device identity | + +All platform-specific code is behind `#ifdef` guards, ensuring a single codebase builds cleanly for all targets. + --- ## Quick Start @@ -29,153 +76,164 @@ sh run_l2_reboot_trigger.sh ## Repository Structure ``` -rfc/ -├── configure.ac # Autoconf build configuration -├── Makefile.am # Top-level automake -├── rfc.properties # Default RFC server properties -├── rfcMgr/ # RFC manager daemon -│ ├── rfc_main.cpp # Entry point, fork, signal handling -│ ├── rfc_manager.cpp/.h # RFCManager class — orchestrates fetch/apply -│ ├── rfc_common.cpp/.h # Shared utilities, macros, error codes -│ ├── rfc_xconf_handler.cpp/.h # RuntimeFeatureControlProcessor -│ ├── xconf_handler.cpp/.h # XconfHandler — HTTP device metadata -│ ├── mtlsUtils.cpp/.h # mTLS certificate selection -│ ├── rfc_mgr_key.h # TR181 key string constants -│ ├── rfc_mgr_json.h # JSON payload processing -│ ├── rfc_mgr_iarm.h # IARM bus definitions -│ └── gtest/ # Unit tests + mocks -├── rfcapi/ # Public RFC get/set API library -│ ├── rfcapi.cpp/.h # getRFCParameter / setRFCParameter -│ └── docs/ # rfcapi documentation -├── tr181api/ # TR181 parameter store API library -│ ├── tr181api.cpp/.h # getParam / setParam / clearParam -│ └── docs/ # tr181api documentation -├── utils/ # Shared JSON and TR181 utilities -│ ├── jsonhandler.cpp/.h -│ ├── tr181utils.cpp -│ └── trsetutils.cpp/.h -└── test/ # L2 functional tests - └── functional-tests/ +rfc-fork/ +├── rfcMgr/ # RFC Manager daemon (core component) +│ ├── rfc_main.cpp # Entry point — daemonize, init directories +│ ├── rfc_manager.h/cpp # Lifecycle orchestrator +│ ├── xconf_handler.h/cpp # Base device-identity collector +│ ├── rfc_xconf_handler.h/cpp # Core RFC state machine & Xconf logic +│ ├── rdkc_rfc_xconf_handler.h/cpp # RDKC camera-specific overrides +│ ├── mtlsUtils.h/cpp # mTLS certificate handling +│ ├── rfc_common.h/cpp # Shared utilities +│ ├── rfc_mgr_iarm.h # IARM bus integration +│ ├── rfc_mgr_json.h # JSON field constants +│ ├── rfc_mgr_key.h # Configuration key constants +│ └── gtest/ # Unit & L2 integration tests +│ └── mocks/ # Test doubles +├── rfcapi/ # Public RFC parameter API library +│ ├── rfcapi.h # C API header +│ └── rfcapi.cpp # Implementation +├── tr181api/ # TR-181 data model API +│ ├── tr181api.h +│ └── tr181api.cpp +├── utils/ # Utility libraries +│ ├── jsonhandler.h/cpp # JSON parsing helpers +│ ├── trsetutils.h/cpp # TR-181 set utilities +│ └── tr181utils.cpp # TR-181 access utilities +├── test/ # Functional test suite +│ └── functional-tests/ +├── documentation/ # Architecture & design docs +│ ├── architecture.md # Component architecture & class diagrams +│ ├── sequence-diagrams.md # End-to-end sequence flows +│ └── data-processing-flow.md # Data processing & parameter flow +├── .github/ # CI/CD workflows +│ ├── workflows/ +│ └── CODEOWNERS +├── configure.ac # Autotools build configuration +├── Makefile.am # Top-level Automake +├── rfc.properties # Runtime configuration +├── getRFC.sh # Legacy shell wrapper +├── isFeatureEnabled.sh # Feature check script +├── CHANGELOG.md # Release history +├── CONTRIBUTING.md # Contribution guidelines +├── LICENSE / COPYING / NOTICE # Legal +└── run_ut.sh / run_l2.sh # Test runners ``` --- -## System Architecture +## Architecture Overview ```mermaid graph TB - subgraph Device - main["rfc_main.cpp\n(fork + signals)"] - mgr["RFCManager\n(rfc_manager.cpp)"] - rfcp["RuntimeFeatureControlProcessor\n(rfc_xconf_handler.cpp)"] - xconf["XconfHandler\n(xconf_handler.cpp)"] - mtls["mtlsUtils\n(cert selection)"] - rfcapi["librfcapi\n(rfcapi.cpp)"] - tr181api["libtr181api\n(tr181api.cpp)"] - store["/opt/secure/RFC/\ntr181store.ini\nrfcVariable.ini\nbootstrap.ini"] - iarm["IARM Bus\n(optional)"] + subgraph "rfcMgr Daemon" + MAIN["rfc_main.cpp
Daemonize & Init"] + MGR["RFCManager
Orchestrator"] + XCONF["XconfHandler
Device Identity"] + RFC["RuntimeFeatureControl
Processor"] + CAM["RdkcRuntimeFeatureControl
Processor"] + MTLS["mtlsUtils
Certificate Handling"] end - XConfServer["XConf Server\n(HTTPS + mTLS)"] - RDKComponent["RDK Component\n(consumer)"] - - main --> mgr - mgr --> rfcp - rfcp --> xconf - xconf --> mtls - xconf -->|"HTTP GET (mTLS)"| XConfServer - XConfServer -->|"JSON response"| rfcp - rfcp --> rfcapi - rfcapi --> store - rfcp --> tr181api - tr181api --> store - mgr --> iarm - RDKComponent --> rfcapi - RDKComponent --> tr181api + subgraph "Libraries" + API["rfcapi
Public C API"] + TR181["tr181api
TR-181 Access"] + UTILS["utils
JSON & Set Helpers"] + end + + subgraph "External" + SERVER["Xconf Server"] + FS["File System
tr181store.ini"] + end + + MAIN --> MGR + MGR --> RFC + RFC --> XCONF + RFC -.->|RDKC| CAM + RFC --> MTLS + RFC --> SERVER + RFC --> API + API --> FS + API --> TR181 + TR181 --> UTILS +``` + +**Class Hierarchy:** + +``` +XconfHandler (device identity collection) + └── RuntimeFeatureControlProcessor (Xconf query, parse, apply) + └── RdkcRuntimeFeatureControlProcessor (camera-specific overrides) ``` +For detailed architecture diagrams, see [documentation/architecture.md](documentation/architecture.md). + --- -## Key Workflows +## Building -### RFC Fetch and Apply Workflow +### Prerequisites -```mermaid -sequenceDiagram - participant main as rfc_main.cpp - participant mgr as RFCManager - participant rfcp as RuntimeFeatureControlProcessor - participant xconf as XconfHandler - participant mtls as mtlsUtils - participant server as XConf Server - participant store as /opt/secure/RFC/ - - main->>mgr: new RFCManager() - main->>mgr: CheckDeviceIsOnline() - mgr-->>main: RFCMGR_DEVICE_ONLINE - main->>mgr: RFCManagerProcessXconfRequest() - mgr->>rfcp: InitializeRuntimeFeatureControlProcessor() - rfcp->>rfcp: GetAccountID(), GetRFCPartnerID() - rfcp->>xconf: initializeXconfHandler() - xconf->>xconf: Populate device metadata\n(MAC, firmware, model, partner) - rfcp->>mtls: getMtlscert() - mtls-->>rfcp: MtlsAuth_t (cert + key paths) - rfcp->>xconf: ExecuteRequest(FileDwnl_t, MtlsAuth_t) - xconf->>server: HTTPS GET /featureControl/settings?... - server-->>xconf: HTTP 200 + JSON payload - rfcp->>rfcp: ProcessRuntimeFeatureControlReq() - rfcp->>store: Write rfcVariable.ini / tr181store.ini - rfcp-->>mgr: SUCCESS / rebootRequired -``` +- GNU Autotools (`autoconf`, `automake`, `libtool`) +- C++11 compiler +- `libcurl`, `libcjson` +- Platform-specific: `librbus` (RDKB), `libhostif` (STB), `libmfrapi` (RDKC) -### RFC State Machine +### Build Commands -```mermaid -stateDiagram-v2 - [*] --> Init : daemon start - Init --> Local : check ConfigSetHash\n(no change needed) - Init --> Redo : new firmware detected - Init --> Redo_With_Valid_Data : accountId valid - Local --> Finish : settings already current - Redo --> Redo_With_Valid_Data : XConf fetch OK - Redo --> Finish : fetch failed (offline) - Redo_With_Valid_Data --> Finish : parameters applied - Finish --> [*] : cleanup + optional reboot -``` +```bash +# Generate build system +autoreconf -i ---- +# Configure for target platform +./configure # STB (default) +./configure --enable-rdkc # RDK Camera +./configure --enable-rdkb # RDK Broadband -## Component Descriptions +# Build +make -| Component | Location | Role | -|-----------|----------|------| -| `rfc_main.cpp` | `rfcMgr/` | Entry point — forks daemon, manages PID lock, handles SIGTERM | -| `RFCManager` | `rfcMgr/rfc_manager.cpp` | Orchestrates online-check, IARM init, XConf request cycle | -| `RuntimeFeatureControlProcessor` | `rfcMgr/rfc_xconf_handler.cpp` | Extends XconfHandler; owns RFC state machine and parameter apply | -| `XconfHandler` | `rfcMgr/xconf_handler.cpp` | Populates device metadata; executes HTTPS request via libcurl | -| `mtlsUtils` | `rfcMgr/mtlsUtils.cpp` | Selects dynamic or static mTLS certificate; optionally uses librdkcertselector | -| `librfcapi` | `rfcapi/rfcapi.cpp` | Public C API for RFC parameter get/set used by all RDK components | -| `libtr181api` | `tr181api/tr181api.cpp` | Higher-level TR181 API with typed parameters, local store, and defaults | -| `jsonhandler` | `utils/jsonhandler.cpp` | Parses XConf JSON response payloads | -| `tr181utils` | `utils/tr181utils.cpp` | TR181 store manipulation utilities | +# Install +make install # Installs /usr/bin/rfcMgr and librfcapi ---- +# Unit tests +./configure --enable-gtestapp +make check +``` -## Build Options +### Build Flags -| `configure` flag | Effect | -|-----------------|--------| +| Option | Description | +|--------|-------------| +| `--enable-rdkc` | Enable RDKC camera platform support | +| `--enable-rdkb` | Enable RDKB broadband platform support | +| `--enable-gtestapp` | Enable Google Test unit tests | +| `--enable-rdkcertselector` | Use `librdkcertselector` for mTLS | +| `--enable-mountutils` | Use `librdkconfig` for configuration | | `--enable-rfctool=yes` | Build `librfcapi` (default: yes) | | `--enable-tr181set=yes` | Build `libtr181api` | -| `--enable-gtestapp=yes` | Build gtest binaries in `rfcMgr/gtest/` | | `--enable-rdkcertselector=yes` | Enable `librdkcertselector` for dynamic mTLS cert selection | -| `--enable-mountutils=yes` | Enable `librdkconfig` for config mount utilities | -| `--enable-rdkb=yes` | Enable RDK-B (broadband) platform adaptations | -| `--enable-rdkc=yes` | Enable RDK-C (camera) platform adaptations | | `--enable-iarmbus=yes` | Enable IARM bus integration | --- +## Configuration + +### rfc.properties + +Runtime configuration is read from `rfc.properties`: + +| Property | Description | +|----------|-------------| +| `RFC_CONFIG_SERVER_URL` | Primary Xconf server endpoint | +| `RFC_CONFIG_SERVER_URL_EU` | EU region Xconf server endpoint | +| `RFC_RAM_PATH` | Temporary storage path (`/tmp/RFC`) | +| `TR181_STORE_FILENAME` | Persistent parameter storage file | +| `RFC_POSTPROCESS` | Post-processing script path | +| `RFC_SERVICE_LOCK` | Lock file to prevent concurrent runs | + +--- + ## Platform Notes ### RDK-V (Video — default) @@ -214,6 +272,56 @@ stateDiagram-v2 --- +### RDKC Device Files + +| File | Purpose | +|------|---------| +| `/opt/usr_config/partnerid.txt` | Syndication partner ID | +| `/opt/usr_config/service_number.txt` | Account ID | +| `/opt/usr_config/accounthash.txt` | MD5 account hash | +| `/opt/secure/RFC/tr181store.ini` | Persisted RFC parameters | +| `/tmp/RFC/.hashValue` | Configuration hash (RAM) | +| `/tmp/RFC/.timeValue` | Last update timestamp (RAM) | + +--- + +## Usage + +```bash +# Run the RFC manager daemon +/usr/bin/rfcMgr + +# Check if a feature is enabled +./isFeatureEnabled.sh + +# Query RFC settings (legacy shell) +./getRFC.sh +``` + +### rfcapi Library + +```c +#include "rfcapi.h" + +// Read a parameter +RFC_ParamData_t param; +int ret = getRFCParameter("module", "Device.X_RDK.Feature.Enable", ¶m); +if (ret == 0) { + printf("Value: %s, Type: %d\n", param.value, param.type); +} + +// Check feature status +if (isRFCEnabled("AccountInfo")) { + // Feature is active +} +``` +| `librfcapi` | `rfcapi/rfcapi.cpp` | Public C API for RFC parameter get/set used by all RDK components | +| `libtr181api` | `tr181api/tr181api.cpp` | Higher-level TR181 API with typed parameters, local store, and defaults | +| `jsonhandler` | `utils/jsonhandler.cpp` | Parses XConf JSON response payloads | +| `tr181utils` | `utils/tr181utils.cpp` | TR181 store manipulation utilities | + +--- + ## Error Codes | Code | Value | Meaning | @@ -230,28 +338,59 @@ stateDiagram-v2 ## Testing -### Unit Tests (`rfcMgr/gtest/`) - ```bash -# Build and run all unit tests -sh run_ut.sh +# Unit tests (L1) +./run_ut.sh + +# L2 integration tests +./run_l2.sh + +# L2 reboot trigger tests +./run_l2_reboot_trigger.sh +``` + +Test coverage is tracked via GitHub Actions workflows: +- `L1-Test.yaml` — Unit test execution +- `L2-tests.yml` — Integration test execution +- `code-coverage.yml` — Coverage reporting # Individual binaries ./rfcMgr/gtest/rfcMgr_gtest # RFCManager / XConf handler tests ./rfcMgr/gtest/rfcapi_gtest # RFC API get/set tests ./rfcMgr/gtest/tr181api_gtest # TR181 API tests ./rfcMgr/gtest/utils_gtest # JSON handler / TR181 utils tests -``` -### L2 Functional Tests (`test/functional-tests/`) +--- -```bash -sh run_l2.sh # Main L2 test suite (XConf, TR181, feature flags) -sh run_l2_reboot_trigger.sh # Reboot trigger / unknown-accountId flow -``` +## Documentation + +| Document | Description | +|----------|-------------| +| [Architecture](documentation/architecture.md) | Component architecture, class hierarchy, build system | +| [Sequence Diagrams](documentation/sequence-diagrams.md) | End-to-end execution flows with Mermaid diagrams | +| [Data Processing Flow](documentation/data-processing-flow.md) | Parameter lifecycle, storage strategies, data transformations | +| [Changelog](CHANGELOG.md) | Release history and version changes | +| [Contributing](CONTRIBUTING.md) | How to contribute to this project | -Results land in `/tmp/rfc_test_report/` as JSON files. +--- + +## Contributing + +Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the contribution process, coding standards, and how to submit pull requests. + +Before RDK accepts your code, you must sign the [RDK Contributor License Agreement (CLA)](https://wiki.rdkcentral.com/display/DOC/Contributor+License+Agreement). + +--- +## License + +This project is licensed under the Apache License, Version 2.0 — see the [LICENSE](LICENSE) file for details. + +``` +Copyright 2018-2026 RDK Management + +Licensed under the Apache License, Version 2.0 +``` --- ## See Also diff --git a/configure.ac b/configure.ac index 5db15087..2531f383 100644 --- a/configure.ac +++ b/configure.ac @@ -158,6 +158,19 @@ AC_ARG_ENABLE([rdkc], AM_CONDITIONAL([ENABLE_RDKC], [test x$ENABLE_RDKC = xtrue]) +AC_ARG_ENABLE([xcam2], + AS_HELP_STRING([--enable-xcam2],[enable xcam2 (default is no)]), + [ + case "${enableval}" in + yes) ENABLE_XCAM2=true;; + no) AC_MSG_ERROR([XCAM2 is disabled]) ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-xcam2]) ;; + esac + ], + [echo "xcam2 is disabled"]) + +AM_CONDITIONAL([ENABLE_XCAM2], [test x$ENABLE_XCAM2 = xtrue]) + AC_ARG_ENABLE([rdkb], AS_HELP_STRING([--enable-rdkb],[enable rdkb (default is no)]), [ diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 00000000..cef42023 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,386 @@ +# Architecture + +> Component architecture, class hierarchy, and build system design for the RFC (Remote Feature Control) daemon. + +--- + +## Table of Contents + +- [1. High-Level Architecture](#1-high-level-architecture) +- [2. Component Diagram](#2-component-diagram) +- [3. Class Hierarchy](#3-class-hierarchy) +- [4. Build System Architecture](#4-build-system-architecture) +- [5. Platform Abstraction Strategy](#5-platform-abstraction-strategy) +- [6. File Responsibilities](#6-file-responsibilities) +- [7. Dependency Graph](#7-dependency-graph) +- [8. External Integrations](#8-external-integrations) + +--- + +## 1. High-Level Architecture + +The `rfcMgr` daemon is a multi-platform C++ application that replaces the legacy `RFCbase.sh` shell script. It uses a polymorphic class hierarchy with `#ifdef` conditional compilation to support STB, RDKB, and RDKC platforms from a single codebase. + +```mermaid +graph TD + subgraph "Entry & Lifecycle" + A["rfc_main.cpp
fork() • signal handlers • directory setup"] + end + + subgraph "Orchestration" + B["RFCManager
Device online check • processor lifecycle
post-processing • cron scheduling"] + end + + subgraph "RFC Processing Engine" + C["XconfHandler
Device identity collection
MAC • FW • model • partner ID"] + D["RuntimeFeatureControlProcessor
Xconf query • JSON parse • param apply
hash/time management • reboot eval"] + E["RdkcRuntimeFeatureControl
Processor
Camera URL • RAM hash/time • no-op metadata"] + end + + subgraph "Security" + F["mtlsUtils
Dynamic XPKI • Static XPKI • cert selector"] + end + + subgraph "Public API" + G["rfcapi (librfcapi)
getRFCParameter() • setRFCParameter()
isRFCEnabled()"] + end + + subgraph "Data Model Layer" + H["tr181api / utils
TR-181 access • JSON handler • set utilities"] + end + + subgraph "External Systems" + I["Xconf Server
HTTP REST API"] + J["File System
tr181store.ini • hash/time files"] + K["Platform APIs
hostif • rbus • mfrApi"] + end + + A --> B + B --> D + D --> C + D -.->|"#ifdef RDKC"| E + D --> F + D --> I + D --> G + G --> J + G --> H + H --> K + + style E fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px + style F fill:#fff9c4,stroke:#f9a825,stroke-width:2px + style G fill:#bbdefb,stroke:#1565c0,stroke-width:2px +``` + +--- + +## 2. Component Diagram + +```mermaid +graph LR + subgraph "rfcMgr Binary" + direction TB + MAIN[rfc_main] + MGR[rfc_manager] + XCONF[xconf_handler] + RFCX[rfc_xconf_handler] + RDKC_X[rdkc_rfc_xconf_handler] + COMMON[rfc_common] + MTLS[mtlsUtils] + IARM[rfc_mgr_iarm] + JSON_H[rfc_mgr_json] + KEY_H[rfc_mgr_key] + + MAIN --> MGR + MGR --> RFCX + RFCX --> XCONF + RFCX -.-> RDKC_X + RFCX --> COMMON + RFCX --> MTLS + MGR --> IARM + RFCX --> JSON_H + RFCX --> KEY_H + end + + subgraph "librfcapi.so" + RFCAPI[rfcapi] + end + + subgraph "libtr181api.so" + TR181[tr181api] + end + + subgraph "libutils" + JSONUTIL[jsonhandler] + TRSET[trsetutils] + TR181U[tr181utils] + end + + RFCX --> RFCAPI + RFCAPI --> TR181 + TR181 --> JSONUTIL + TR181 --> TRSET + + style RDKC_X fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px +``` + +--- + +## 3. Class Hierarchy + +```mermaid +classDiagram + class XconfHandler { + #string _estb_mac_address + #string _firmware_version + #EBuildType _ebuild_type + #string _build_type_str + #string _model_number + #string _ecm_mac_address + #string _manufacturer + #string _partner_id + +initializeXconfHandler() int + +ExecuteRequest(FileDownload*, MtlsAuth_t*, int*) int + } + + class RuntimeFeatureControlProcessor { + #string _accountId + #string _experience + #string _xconf_server_url + #bool _rfcRebootCronNeeded + #set~string~ _effectiveImmediateParams + +InitializeRuntimeFeatureControlProcessor() int + +ProcessRuntimeFeatureControlReq() int + +GetAccountID() void + +getRfcRebootCronNeeded() bool + #CreateXconfHTTPUrl()* stringstream + #RetrieveHashAndTimeFromPreviousDataSet()* void + #StoreXconfEndpointMetadata()* void + #set_RFCProperty(char*, char*, char*) WDMP_STATUS + #clearDB() void + #updateHashInDB(string) void + #updateTimeInDB(string) void + } + + class RdkcRuntimeFeatureControlProcessor { + -string _accountHash + -GetAccountHash() void + #CreateXconfHTTPUrl() stringstream + #RetrieveHashAndTimeFromPreviousDataSet() void + #StoreXconfEndpointMetadata() void + } + + class RFCManager { + -RuntimeFeatureControlProcessor* _rfcProcessor + +CheckDeviceIsOnline() DeviceStatus + +RFCManagerProcess() int + +RFCManagerProcessXconfRequest() int + +RFCManagerPostProcess() void + } + + XconfHandler <|-- RuntimeFeatureControlProcessor : inherits + RuntimeFeatureControlProcessor <|-- RdkcRuntimeFeatureControlProcessor : inherits + RFCManager --> RuntimeFeatureControlProcessor : creates & uses + + note for RdkcRuntimeFeatureControlProcessor "Compiled only with -DRDKC flag.\nOverrides 3 virtual methods for\ncamera-specific behavior." +``` + +### Inheritance Design Rationale + +The class hierarchy follows the **Template Method Pattern**: + +- **`XconfHandler`** — Collects device identity. Platform differences are behind `#ifdef` blocks within methods. +- **`RuntimeFeatureControlProcessor`** — Implements the full RFC workflow. Declares `virtual` methods for steps that vary by platform. +- **`RdkcRuntimeFeatureControlProcessor`** — Overrides only 3 methods, keeping the camera delta minimal: + - `CreateXconfHTTPUrl()` — Camera-specific URL parameters + - `RetrieveHashAndTimeFromPreviousDataSet()` — RAM-file storage + - `StoreXconfEndpointMetadata()` — No-op (camera must not persist Xconf metadata) + +--- + +## 4. Build System Architecture + +### Configure Options Flow + +```mermaid +flowchart TD + A["./configure"] --> B{"--enable-rdkc?"} + B -- Yes --> C["AM_CONDITIONAL ENABLE_RDKC = true
-DRDKC added to CPPFLAGS"] + B -- No --> D{"--enable-rdkb?"} + D -- Yes --> E["AM_CONDITIONAL ENABLE_RDKB = true
-DRDKB_SUPPORT added"] + D -- No --> F["Default STB build"] + + C --> G["SUBDIRS = rfcapi rfcMgr"] + E --> H["SUBDIRS = rfcMgr"] + F --> I["SUBDIRS = rfcapi tr181api utils rfcMgr"] + + G --> J["rfcMgr sources += rdkc_rfc_xconf_handler.cpp
Links: -lrfcapi -ldwnlutil -lfwutils -lcurl"] + H --> K["Links: -lrbus"] + I --> L["Links: ../rfcapi/.libs/librfcapi.la"] + + style C fill:#c8e6c9,stroke:#2e7d32 + style G fill:#c8e6c9,stroke:#2e7d32 + style J fill:#c8e6c9,stroke:#2e7d32 +``` + +### Build Outputs + +| Platform | Subdirectories Built | Binary | Libraries | +|----------|---------------------|--------|-----------| +| **STB** | rfcapi, tr181api, utils, rfcMgr | `/usr/bin/rfcMgr` | librfcapi.so, libtr181api.so | +| **RDKB** | rfcMgr | `/usr/bin/rfcMgr` | *(links external rbus)* | +| **RDKC** | rfcapi, rfcMgr | `/usr/bin/rfcMgr` | librfcapi.so | + +--- + +## 5. Platform Abstraction Strategy + +The codebase uses two complementary strategies: + +### Strategy 1: Preprocessor Guards (`#ifdef`) + +Used within shared source files for small, inline platform differences: + +``` +┌──────────────────────────────────────────────┐ +│ #ifdef RDKC │ +│ // Camera-specific implementation │ +│ #elif defined(RDKB_SUPPORT) │ +│ // Broadband-specific implementation │ +│ #else │ +│ // STB default implementation │ +│ #endif │ +└──────────────────────────────────────────────┘ +``` + +**Used in:** `rfc_manager.cpp`, `xconf_handler.cpp`, `rfc_xconf_handler.cpp`, `mtlsUtils.cpp`, `rfcapi.cpp` + +### Strategy 2: Polymorphic Override + +Used for larger behavioral differences via virtual method dispatch: + +```mermaid +flowchart LR + A["RFCManager"] --> B{"Platform?"} + B -- RDKC --> C["new RdkcRuntimeFeature
ControlProcessor()"] + B -- Other --> D["new RuntimeFeature
ControlProcessor()"] + C --> E["Virtual dispatch for
CreateXconfHTTPUrl()
RetrieveHashAndTime...
StoreXconfEndpoint..."] + D --> E +``` + +--- + +## 6. File Responsibilities + +### Core Daemon (`rfcMgr/`) + +| File | Responsibility | Key Functions | +|------|---------------|---------------| +| `rfc_main.cpp` | Process entry point | `main()`, `cleanup_lock_file()`, `signal_handler()`, `createDirectoryIfNotExists()` | +| `rfc_manager.h/cpp` | Lifecycle orchestrator | `CheckDeviceIsOnline()`, `RFCManagerProcess()`, `RFCManagerPostProcess()`, `SendEventToMaintenanceManager()` | +| `xconf_handler.h/cpp` | Device identity | `initializeXconfHandler()`, `ExecuteRequest()` | +| `rfc_xconf_handler.h/cpp` | Core RFC logic | `InitializeRuntimeFeatureControlProcessor()`, `ProcessRuntimeFeatureControlReq()`, `set_RFCProperty()`, `clearDB()` | +| `rdkc_rfc_xconf_handler.h/cpp` | Camera overrides | `CreateXconfHTTPUrl()`, `RetrieveHashAndTimeFromPreviousDataSet()`, `StoreXconfEndpointMetadata()` | +| `mtlsUtils.h/cpp` | Certificate management | `getMtlscert()`, `isStateRedSupported()`, `isInStateRed()` | +| `rfc_common.h/cpp` | Shared utilities | `read_RFCProperty()`, `getSyseventValue()`, `waitForRfcCompletion()` | +| `rfc_mgr_iarm.h` | IARM bus integration | Event handler registration constants | +| `rfc_mgr_json.h` | JSON field names | Feature/parameter key string constants | +| `rfc_mgr_key.h` | Config keys | TR-181 parameter name constants | + +### Public API (`rfcapi/`) + +| File | Responsibility | Key Functions | +|------|---------------|---------------| +| `rfcapi.h/cpp` | RFC parameter access | `getRFCParameter()`, `setRFCParameter()`, `isRFCEnabled()`, `getRFCErrorString()` | + +### Data Model (`tr181api/`, `utils/`) + +| File | Responsibility | +|------|---------------| +| `tr181api.h/cpp` | TR-181 data model read/write | +| `jsonhandler.h/cpp` | JSON parse/build helpers | +| `trsetutils.h/cpp` | TR-181 set operation utilities | +| `tr181utils.cpp` | TR-181 access layer | + +--- + +## 7. Dependency Graph + +```mermaid +graph TD + subgraph "System Libraries" + CURL[libcurl] + CJSON[libcjson] + PTHREAD[libpthread] + end + + subgraph "RDK Platform Libraries" + HOSTIF[libhostif
STB only] + RBUS[librbus
RDKB only] + MFRAPI[mfrApi_test
RDKC only] + CERTSELECTOR[librdkcertselector
optional] + DWNLUTIL[libdwnlutil
RDKC only] + FWUTILS[libfwutils
RDKC only] + SECWRAP[libsecure_wrapper] + end + + subgraph "RFC Components" + RFCMGR[rfcMgr] + RFCAPI[librfcapi] + TR181API[libtr181api] + UTILS_LIB[utils] + end + + RFCMGR --> CURL + RFCMGR --> CJSON + RFCMGR --> PTHREAD + RFCMGR --> SECWRAP + RFCMGR --> RFCAPI + RFCMGR -.->|STB| HOSTIF + RFCMGR -.->|RDKB| RBUS + RFCMGR -.->|RDKC| DWNLUTIL + RFCMGR -.->|RDKC| FWUTILS + RFCMGR -.->|optional| CERTSELECTOR + RFCAPI --> TR181API + TR181API --> UTILS_LIB + UTILS_LIB --> CJSON + + style RFCMGR fill:#bbdefb,stroke:#1565c0,stroke-width:2px + style RFCAPI fill:#bbdefb,stroke:#1565c0,stroke-width:2px +``` + +--- + +## 8. External Integrations + +```mermaid +graph LR + subgraph "rfcMgr" + RFC[RFC Daemon] + end + + RFC -->|"HTTP GET + mTLS"| XCONF["Xconf Server
featureControl/getSettings"] + RFC -->|"read/write"| INI["tr181store.ini
RFC parameters"] + RFC -->|"read"| PROPS["rfc.properties
Server URLs & paths"] + RFC -->|"read"| DEVICE["Device Identity Files
partnerid.txt
service_number.txt
accounthash.txt"] + RFC -->|"execute"| MFRAPI["mfrApi_test
MAC address (RDKC)"] + RFC -->|"register events"| IARM["IARM Bus
Maintenance events"] + RFC -->|"trigger"| CRON["RfcRebootCronschedule.sh
Reboot scheduling"] + RFC -->|"notify"| TELEMETRY["telemetry2_0_client
Feature status (non-RDKC)"] + RFC -->|"read/write"| RAMFILES["/tmp/RFC/
.hashValue • .timeValue"] + + style RFC fill:#bbdefb,stroke:#1565c0,stroke-width:2px + style XCONF fill:#fff9c4,stroke:#f9a825,stroke-width:2px +``` + +### Integration Points Summary + +| Integration | Protocol/Method | Platform | +|------------|-----------------|----------| +| Xconf Server | HTTP GET + mTLS (libcurl) | All | +| tr181store.ini | File I/O (flat key=value) | RDKC | +| TR-181 Data Model | hostif / rbus | STB / RDKB | +| IARM Bus | Event registration | STB | +| mfrApi_test | popen() command | RDKC | +| Maintenance Manager | IARM event | STB | +| Reboot Cron | v_secure_system() shell exec | RDKC | +| Telemetry | v_secure_system() call | STB / RDKB | diff --git a/docs/data-processing-flow.md b/docs/data-processing-flow.md new file mode 100644 index 00000000..ba880d81 --- /dev/null +++ b/docs/data-processing-flow.md @@ -0,0 +1,584 @@ +# Data Processing Flow + +> Parameter lifecycle, storage strategies, data transformations, and platform-specific data paths for the RFC system. + +--- + +## Table of Contents + +- [1. End-to-End Data Flow Overview](#1-end-to-end-data-flow-overview) +- [2. Xconf Request Data Pipeline](#2-xconf-request-data-pipeline) +- [3. Xconf Response Processing Pipeline](#3-xconf-response-processing-pipeline) +- [4. Parameter Storage Architecture](#4-parameter-storage-architecture) +- [5. Hash & Timestamp Management](#5-hash--timestamp-management) +- [6. RFC State Machine](#6-rfc-state-machine) +- [7. ClearDB Data Flow](#7-cleardb-data-flow) +- [8. Platform Data Source Matrix](#8-platform-data-source-matrix) +- [9. Configuration File Formats](#9-configuration-file-formats) +- [10. Error Handling Flow](#10-error-handling-flow) + +--- + +## 1. End-to-End Data Flow Overview + +This diagram shows how data flows through the RFC system from external sources to persistent storage. + +```mermaid +flowchart TD + subgraph "Input Sources" + DEV["Device Identity
MAC • FW • Model
Partner • Account"] + CFG["rfc.properties
Server URLs • Paths"] + HASH_IN["Previous Hash/Time
.hashValue • .timeValue"] + end + + subgraph "Processing Engine" + URL["URL Construction
Query string assembly"] + MTLS["mTLS Certificate
Resolution"] + HTTP["HTTP GET Request
libcurl + mTLS"] + PARSE["JSON Response
Parser"] + EVAL["Change Detection
Hash comparison"] + APPLY["Parameter
Application"] + REBOOT["Reboot
Evaluation"] + end + + subgraph "Output Storage" + PARAMS["RFC Parameters
tr181store.ini (RDKC)
TR-181 DB (others)"] + HASH_OUT["Updated Hash/Time
/tmp/RFC/.hashValue
/tmp/RFC/.timeValue"] + CRON["Cron Schedule
Periodic re-run"] + REBOOT_OUT["Reboot Trigger
RfcRebootCronschedule.sh"] + end + + subgraph "External" + XCONF["Xconf Server"] + end + + DEV --> URL + CFG --> URL + HASH_IN --> EVAL + URL --> HTTP + MTLS --> HTTP + HTTP --> XCONF + XCONF --> HTTP + HTTP --> PARSE + PARSE --> EVAL + EVAL -->|"Config changed"| APPLY + EVAL -->|"No change"| HASH_OUT + APPLY --> PARAMS + APPLY --> REBOOT + REBOOT -->|"Reboot needed"| REBOOT_OUT + PARSE --> HASH_OUT + APPLY --> CRON + + style XCONF fill:#fff9c4,stroke:#f9a825,stroke-width:2px + style PARAMS fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px + style REBOOT_OUT fill:#ffcdd2,stroke:#c62828,stroke-width:2px +``` + +--- + +## 2. Xconf Request Data Pipeline + +How device data is collected, transformed, and assembled into the Xconf query URL. + +```mermaid +flowchart LR + subgraph "Raw Data Sources (RDKC)" + A1["mfrApi_test 3 9
→ raw MAC output"] + A2["GetFirmwareVersion()
→ version string"] + A3["GetBuildType()
→ enum"] + A4["GetModelNum()
→ model string"] + A5["/opt/usr_config/
partnerid.txt"] + A6["/opt/usr_config/
service_number.txt"] + A7["/opt/usr_config/
accounthash.txt"] + A8["rfc.properties
RFC_CONFIG_SERVER_URL"] + end + + subgraph "Transform" + T1["Parse popen() output
Extract MAC string"] + T2["Map enum to string
dev/vbn/prod"] + T3["Read file, trim
whitespace/newline"] + T4["URL-encode values"] + end + + subgraph "URL Assembly" + URL["https://xconf.server/
featureControl/getSettings?
estbMacAddress=MAC
&firmwareVersion=FW
&env=BUILD_TYPE
&model=MODEL
&accountHash=HASH
&partnerId=PID
&accountId=AID
&experience=EXP
&version=2"] + end + + A1 --> T1 --> URL + A2 --> URL + A3 --> T2 --> URL + A4 --> URL + A5 --> T3 --> URL + A6 --> T3 + A7 --> T3 + A8 --> URL + T4 --> URL + + style URL fill:#bbdefb,stroke:#1565c0,stroke-width:2px +``` + +### URL Parameter Comparison + +```mermaid +flowchart TB + subgraph "RDKC Camera URL" + C1[estbMacAddress] + C2[firmwareVersion] + C3[env] + C4[model] + C5[accountHash] + C6[partnerId] + C7[accountId] + C8[experience] + C9["version=2"] + end + + subgraph "STB/RDKB URL" + S1[estbMacAddress] + S2[firmwareVersion] + S3[env] + S4[model] + S5[ecmMacAddress] + S6[controllerId] + S7[channelMapId] + S8[vodId] + S9[partnerId] + S10[accountId] + S11[experience] + S12[osclass] + S13[manufacturer] + S14["version=2"] + end + + style C5 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px + style S5 fill:#ffcdd2,stroke:#c62828 + style S6 fill:#ffcdd2,stroke:#c62828 + style S7 fill:#ffcdd2,stroke:#c62828 + style S8 fill:#ffcdd2,stroke:#c62828 + style S12 fill:#ffcdd2,stroke:#c62828 + style S13 fill:#ffcdd2,stroke:#c62828 +``` + +> **Green** = RDKC-only field. **Red** = Fields NOT present in RDKC URL. + +--- + +## 3. Xconf Response Processing Pipeline + +```mermaid +flowchart TD + A["HTTP Response Body
(JSON)"] --> B["cJSON_Parse()"] + B --> C{"Parse successful?"} + C -- No --> ERR["Log error, return failure"] + C -- Yes --> D["Extract featureControl object"] + + D --> E["Iterate features[] array"] + + E --> F["For each feature:"] + F --> G["Read feature name"] + F --> H["Read effectiveImmediate flag"] + F --> I["Read configData[] array"] + + I --> J["For each config param:"] + J --> K["Extract key (TR-181 name)"] + J --> L["Extract value"] + J --> M["Extract dataType"] + + subgraph "effectiveImmediate Tracking (RDKC)" + H -->|true| N["Add all param keys
to _effectiveImmediateParams set"] + end + + subgraph "Parameter Application" + K --> O["set_RFCProperty(name, key, value)"] + L --> O + M --> O + end + + subgraph "Hash Computation" + O --> P["Compute hash of
all applied parameters"] + P --> Q{"Hash different
from stored?"} + Q -- Yes --> R["Configuration changed
Update hash & time"] + Q -- No --> S["No changes detected
Skip update"] + end + + style A fill:#fff9c4,stroke:#f9a825 + style O fill:#c8e6c9,stroke:#2e7d32 + style R fill:#bbdefb,stroke:#1565c0 +``` + +### JSON Response Structure + +``` +{ + "featureControl": { + "features": [ + { + "name": "AccountInfo", + "effectiveImmediate": true, + "enable": true, + "configData": [ + { + "key": "Device.X_RDK.AccountID", + "value": "5789171196032993066", + "dataType": 0 + }, + { + "key": "Device.X_RDK.MD5AccountHash", + "value": "1EMvt8zMMd8muKCBJRnp1z6nZTgsBJ1VhL", + "dataType": 0 + } + ] + } + ] + } +} +``` + +--- + +## 4. Parameter Storage Architecture + +### Write Path + +```mermaid +flowchart TD + A["set_RFCProperty(featureName, key, value)"] + + A --> B{"Platform?"} + + B -- "RDKC" --> C["Read /opt/secure/RFC/tr181store.ini"] + C --> D["Parse into lines[]"] + D --> E{"Key exists?"} + E -- Yes --> F["Replace: line = key=value"] + E -- No --> G["Append: lines.push_back(key=value)"] + F --> H["Write all lines to tr181store.ini"] + G --> H + H --> I["Return WDMP_SUCCESS"] + + B -- "RDKB" --> J["rbus_open(handle)"] + J --> K["rbus_set(handle, key, value)"] + K --> L["rbus_close(handle)"] + L --> I + + B -- "STB" --> M["setRFCParameter(key, value, type)
via hostif/WDMP"] + M --> I + + style C fill:#c8e6c9,stroke:#2e7d32 + style H fill:#c8e6c9,stroke:#2e7d32 +``` + +### Read Path (rfcapi) + +```mermaid +flowchart TD + A["getRFCParameter(name, key, ¶m)"] + + A --> B{"Platform / Backend?"} + + B -- "Flat-file (RDKC)" --> C["Open tr181store.ini"] + C --> D["Scan for key= prefix"] + D --> E{"Found?"} + E -- Yes --> F["Extract value after '='"] + F --> G["param.value = value
param.type = STRING"] + E -- No --> H["Return WDMP_ERR_VALUE_IS_EMPTY"] + + B -- "WDMP (STB)" --> I["Build WDMP request"] + I --> J["Send to hostif backend"] + J --> K["Parse WDMP response"] + K --> G + + B -- "TR-181 int (RDKB)" --> L["rbus_get(key)"] + L --> M["Parse rbus response"] + M --> G + + G --> N["Return 0 (success)"] + + style C fill:#c8e6c9,stroke:#2e7d32 +``` + +### File Format: tr181store.ini + +``` +Device.X_RDK.Feature.AccountInfo.Enable=true +Device.X_RDK.AccountID=5789171196032993066 +Device.X_RDK.MD5AccountHash=1EMvt8zMMd8muKCBJRnp1z6nZTgsBJ1VhL +Device.X_RDK.Feature.VideoAnalytics.Enable=true +Device.X_RDK.Feature.AmbientListening.Enable=false +``` + +--- + +## 5. Hash & Timestamp Management + +```mermaid +flowchart TD + subgraph "Read Phase" + R1["GetStoredHashAndTime()"] + R1 --> R2{"RDKC?"} + R2 -- Yes --> R3["Always call
RetrieveHashAndTime
FromPreviousDataSet()"] + R2 -- No --> R4["Check XconfSelector
slot first"] + R4 --> R5{"Slot matches?"} + R5 -- Yes --> R6["Read from that slot"] + R5 -- No --> R3 + + R3 --> R7{"RDKC override"} + R7 --> R8["Read /tmp/RFC/.hashValue
Default: UPGRADE_HASH"] + R7 --> R9["Read /tmp/RFC/.timeValue
Default: 0"] + end + + subgraph "Compare Phase" + CP1["New hash from
current config"] --> CP2{"Hash matches
stored hash?"} + CP2 -- Yes --> CP3["Config unchanged
Skip parameter apply"] + CP2 -- No --> CP4["Config changed
Proceed with apply"] + + CP5["First request?
(FW changed or
no prior hash)"] --> CP6{"Is first?"} + CP6 -- Yes --> CP4 + CP6 -- No --> CP2 + end + + subgraph "Write Phase" + W1["updateHashInDB(hash)"] + W1 --> W2{"RDKB or RDKC?"} + W2 -- Yes --> W3["Write /tmp/RFC/.hashValue"] + W2 -- No --> W4["set_RFCProperty(ConfigSetHash)"] + + W5["updateTimeInDB(time)"] + W5 --> W6{"RDKB or RDKC?"} + W6 -- Yes --> W7["Write /tmp/RFC/.timeValue"] + W6 -- No --> W8["set_RFCProperty(ConfigSetTime)"] + end + + style R8 fill:#c8e6c9,stroke:#2e7d32 + style R9 fill:#c8e6c9,stroke:#2e7d32 + style W3 fill:#c8e6c9,stroke:#2e7d32 + style W7 fill:#c8e6c9,stroke:#2e7d32 +``` + +### Storage Location Matrix + +| Data | STB | RDKB | RDKC | +|------|-----|------|------| +| **Config Hash** | TR-181 DB (`ConfigSetHash`) | `/tmp/RFC/.hashValue` (RAM) | `/tmp/RFC/.hashValue` (RAM) | +| **Config Time** | TR-181 DB (`ConfigSetTime`) | `/tmp/RFC/.timeValue` (RAM) | `/tmp/RFC/.timeValue` (RAM) | +| **Xconf URL** | TR-181 DB (`XconfUrl`) | TR-181 DB | **Not stored** (no-op) | +| **Xconf Selector** | TR-181 DB (`XconfSelector`) | TR-181 DB | **Not stored** (no-op) | + +> **Note:** RDKC uses RAM files that do NOT survive reboot. This means every boot is treated as a fresh request, which is intentional for camera devices. + +--- + +## 6. RFC State Machine + +```mermaid +stateDiagram-v2 + [*] --> Init : ProcessRuntimeFeatureControlReq() + + Init --> CheckLocal : Load rfc.properties + + CheckLocal --> LocalOverride : Local RFC file exists + CheckLocal --> Redo : No local override + + LocalOverride --> Finish : Apply local config + + Redo --> BuildURL : CreateXconfHTTPUrl() + BuildURL --> AcquireCert : getMtlscert() + AcquireCert --> HttpRequest : ExecuteRequest() + + HttpRequest --> ParseResponse : HTTP 200 + HttpRequest --> Retry : HTTP error + + Retry --> Redo : Retry with backoff + Retry --> Finish : Max retries exceeded + + ParseResponse --> CompareHash : ProcessJsonResponse() + + CompareHash --> ApplyParams : Hash changed / first request + CompareHash --> Finish : Hash unchanged + + ApplyParams --> ClearDB : clearDB() + ClearDB --> SetParams : set_RFCProperty() loop + SetParams --> EvalReboot : Check effectiveImmediate [RDKC] + EvalReboot --> UpdateHash : updateHashInDB() + UpdateHash --> UpdateTime : updateTimeInDB() + UpdateTime --> StoreMetadata : StoreXconfEndpointMetadata() + StoreMetadata --> NotifyTelemetry + + NotifyTelemetry --> Finish : [RDKC: skip telemetry] + + Finish --> [*] + + note right of Init + RfcState enum: + Init, Local, Redo, + Redo_With_Valid_Data, + Finish + end note + + note right of ClearDB + RDKC: std::remove(tr181store.ini) + Others: TR-181 ClearDB parameter + end note +``` + +--- + +## 7. ClearDB Data Flow + +```mermaid +flowchart TD + A["clearDB() called"] --> B{"Platform?"} + + B -- "RDKC" --> C["std::remove(
/opt/secure/RFC/tr181store.ini)"] + C --> D["rfcStashRetrieveParams()"] + D --> E["Restore stashed AccountID
and other identity params"] + + B -- "STB / RDKB" --> F["Create empty tr181store.ini"] + F --> G["set_RFCProperty(ClearDB, true)"] + G --> H["set_RFCProperty(BootstrapClearDB, true)"] + H --> I["set_RFCProperty(ConfigChangeTime, timestamp)"] + + I --> J["clearDBEnd()"] + J --> K{"RDKC or RDKB?"} + K -- Yes --> L["SKIP clearDBEnd()"] + K -- No --> M["set_RFCProperty(ClearDBEnd, true)"] + M --> N["set_RFCProperty(BootstrapClearDBEnd, true)"] + N --> O["set_RFCProperty(ReloadCache, true)"] + + style C fill:#c8e6c9,stroke:#2e7d32 + style L fill:#c8e6c9,stroke:#2e7d32 +``` + +--- + +## 8. Platform Data Source Matrix + +### Device Identity + +| Data Field | STB Source | RDKB Source | RDKC Source | +|------------|-----------|-------------|-------------| +| MAC Address | `GetEstbMac()` → `/tmp/.estb_mac` | `getErouterMac()` | `popen("mfrApi_test 3 9")` | +| Firmware Version | `GetFirmwareVersion()` | `GetFirmwareVersion()` | `GetFirmwareVersion()` | +| Build Type | `GetBuildType()` | `GetBuildType()` | `GetBuildType()` | +| Model Number | `GetModelNum()` | `GetModelNum()` | `GetModelNum()` | +| Manufacturer | `GetMFRName()` | `GetMFRName()` | **Skipped** | +| Partner ID | `GetPartnerId()` → `/opt/partnerid` | `GetPartnerId()` | `fopen("/opt/usr_config/partnerid.txt")` | +| Account ID | `read_RFCProperty()` (TR-181) | `read_RFCProperty()` (rbus) | `ifstream("/opt/usr_config/service_number.txt")` | +| Account Hash | N/A | N/A | `ifstream("/opt/usr_config/accounthash.txt")` | +| ECM MAC | N/A | `geteCMMac()` | N/A | + +### Parameter Storage + +| Operation | STB | RDKB | RDKC | +|-----------|-----|------|------| +| **Write** | `setRFCParameter()` via hostif | `rbus_set()` | Write to `tr181store.ini` | +| **Read** | `getRFCParameter()` via WDMP | `rbus_get()` | Scan `tr181store.ini` | +| **Clear** | TR-181 ClearDB params | TR-181 ClearDB params | `std::remove(tr181store.ini)` | + +### mTLS Certificate + +| Strategy | STB | RDKB | RDKC | +|----------|-----|------|------| +| **Primary** | `librdkcertselector` | `librdkcertselector` | Dynamic XPKI (`/opt/certs/devicecert_1.pk12`) | +| **Fallback** | Cert selector retry | Cert selector retry | Static XPKI (`/etc/ssl/certs/staticXpkiCrt.pk12`) | +| **Last resort** | Fail | Fail | Proceed without mTLS | + +### Reboot Mechanism + +| Aspect | STB | RDKB | RDKC | +|--------|-----|------|------| +| **Trigger** | MaintenanceManager | MaintenanceManager | `RfcRebootCronschedule.sh` | +| **Conditions** | `effectiveImmediate` flag | `effectiveImmediate` flag | `effectiveImmediate` + provisioned + not identity param | +| **Notification** | IARM event | IARM event | Shell script (background) | + +--- + +## 9. Configuration File Formats + +### rfc.properties + +```properties +# Server endpoints +RFC_CONFIG_SERVER_URL=https://xconf.example.com/featureControl/getSettings +RFC_CONFIG_SERVER_URL_EU=https://xconf-eu.example.com/featureControl/getSettings + +# Path configuration +export RFC_RAM_PATH="/tmp/RFC" +TR181_STORE_FILENAME="/opt/secure/RFC/tr181store.ini" +RFC_VAR_FILENAME="/opt/secure/RFC/rfcVariable.ini" +BS_STORE_FILENAME="/opt/secure/RFC/bootstrap.ini" + +# Process management +RFC_SERVICE_LOCK="/tmp/.rfcServiceLock" +RFC_WRITE_LOCK="/tmp/.rfcWriteLock" + +# Tools & scripts +RFC_WHITELIST_TOOL="rfctool" +RFC_POSTPROCESS="/lib/rdk/RFCpostprocess.sh" +``` + +### tr181store.ini (RFC Parameters) + +```ini +# Format: TR-181_parameter_name=value +Device.X_RDK.Feature.AccountInfo.Enable=true +Device.X_RDK.AccountID=5789171196032993066 +Device.X_RDK.MD5AccountHash=1EMvt8zMMd8muKCBJRnp1z6nZTgsBJ1VhL +Device.X_RDK.Feature.VideoAnalytics.Enable=true +``` + +### .hashValue / .timeValue (RAM files) + +``` +# /tmp/RFC/.hashValue +a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5 + +# /tmp/RFC/.timeValue +1712937600 +``` + +--- + +## 10. Error Handling Flow + +```mermaid +flowchart TD + A["rfcMgr starts"] --> B{"Lock file exists?"} + B -- Yes --> C["Log: Already running
Exit immediately"] + B -- No --> D["Create lock file"] + + D --> E{"Network available?"} + E -- No --> F["Poll every 10s
(RDKC: getifaddrs loop)"] + F --> E + E -- Yes --> G["Proceed with RFC"] + + G --> H{"Xconf URL valid?"} + H -- No --> I["Log error
Return failure"] + H -- Yes --> J["HTTP Request"] + + J --> K{"HTTP success?"} + K -- No --> L{"Retry count < max?"} + L -- Yes --> M["Backoff & retry"] + M --> J + L -- No --> N["Log: Max retries
Record error state"] + K -- Yes --> O["Parse JSON"] + + O --> P{"JSON valid?"} + P -- No --> Q["Log parse error
Return failure"] + P -- Yes --> R["Apply parameters"] + + R --> S{"Write error?"} + S -- Yes --> T["Log write error
Continue with next param"] + S -- No --> U["Parameter applied"] + + U --> V["Cleanup & exit"] + N --> V + I --> V + + V --> W["Remove lock file"] + + style C fill:#ffcdd2,stroke:#c62828 + style N fill:#ffcdd2,stroke:#c62828 + style Q fill:#ffcdd2,stroke:#c62828 + style T fill:#fff9c4,stroke:#f9a825 + style U fill:#c8e6c9,stroke:#2e7d32 +``` diff --git a/docs/sequence-diagrams.md b/docs/sequence-diagrams.md new file mode 100644 index 00000000..397fe084 --- /dev/null +++ b/docs/sequence-diagrams.md @@ -0,0 +1,482 @@ +# Sequence Diagrams + +> End-to-end execution flows for the RFC daemon across all operational phases. + +--- + +## Table of Contents + +- [1. Complete Startup to Shutdown](#1-complete-startup-to-shutdown) +- [2. Device Online Detection](#2-device-online-detection) +- [3. Device Identity Collection](#3-device-identity-collection) +- [4. Xconf Query & Response Processing](#4-xconf-query--response-processing) +- [5. mTLS Certificate Acquisition](#5-mtls-certificate-acquisition) +- [6. Parameter Application](#6-parameter-application) +- [7. Reboot Evaluation & Scheduling](#7-reboot-evaluation--scheduling) +- [8. Post-Processing & Cleanup](#8-post-processing--cleanup) + +--- + +## 1. Complete Startup to Shutdown + +The full lifecycle of a single `rfcMgr` invocation from process start to exit. + +```mermaid +sequenceDiagram + participant OS as Operating System + participant Main as rfc_main.cpp + participant RFCMgr as RFCManager + participant Proc as RuntimeFeatureControl
Processor + participant Xconf as Xconf Server + participant FS as File System + + Note over OS,FS: Phase 1 — Process Initialization + OS->>Main: exec /usr/bin/rfcMgr + Main->>Main: fork() — daemonize + Main->>Main: atexit(cleanup_lock_file) + Main->>Main: signal(SIGINT, signal_handler) + Main->>Main: signal(SIGTERM, signal_handler) + Main->>RFCMgr: new RFCManager() + Main->>FS: createDirectoryIfNotExists("/opt/secure/RFC") + Main->>FS: createDirectoryIfNotExists("/tmp/RFC") + Main->>FS: Create lock file /tmp/.rfcServiceLock + + Note over OS,FS: Phase 2 — Network Readiness + Main->>RFCMgr: CheckDeviceIsOnline() + loop Until network available + RFCMgr->>RFCMgr: Poll network interfaces + RFCMgr->>RFCMgr: sleep(10) + end + RFCMgr-->>Main: RFCMGR_DEVICE_ONLINE + + Note over OS,FS: Phase 3 — RFC Processing + Main->>RFCMgr: RFCManagerProcess() + RFCMgr->>RFCMgr: sleep(120) [RDKC only] + RFCMgr->>Proc: new Processor() [platform-specific] + RFCMgr->>Proc: InitializeRuntimeFeatureControlProcessor() + RFCMgr->>Proc: ProcessRuntimeFeatureControlReq() + Proc->>Xconf: HTTP GET + mTLS + Xconf-->>Proc: HTTP 200 + JSON + Proc->>FS: Apply parameters (set_RFCProperty) + Proc->>FS: Update hash & timestamp + Proc-->>RFCMgr: SUCCESS + + Note over OS,FS: Phase 4 — Post-Processing & Exit + RFCMgr->>RFCMgr: Evaluate reboot need + RFCMgr->>RFCMgr: RFCManagerPostProcess() + RFCMgr-->>Main: Return + Main->>FS: Remove lock file + Main->>OS: exit(0) +``` + +--- + +## 2. Device Online Detection + +### RDKC Camera Path + +```mermaid +sequenceDiagram + participant MGR as RFCManager + participant NET as Network Stack + participant SYS as System (getifaddrs) + + MGR->>MGR: CheckDeviceIsOnline() + + loop Poll until IP acquired + MGR->>SYS: getifaddrs(&ifaddr) + SYS-->>MGR: Linked list of interfaces + + loop For each interface + MGR->>MGR: Skip loopback (lo) + MGR->>MGR: Check AF_INET or AF_INET6 + + alt AF_INET (IPv4) + MGR->>MGR: inet_ntop() → IP string + alt Is valid non-link-local IP + MGR->>MGR: Log "IPv4:
" + MGR-->>MGR: break — IP found + end + else AF_INET6 + MGR->>MGR: inet_ntop() → IP string + alt Is valid non-link-local IP + MGR->>MGR: Log "IPv6:
" + MGR-->>MGR: break — IP found + end + end + end + + alt No valid IP found + MGR->>SYS: freeifaddrs(ifaddr) + MGR->>MGR: sleep(10) + else Valid IP found + MGR->>SYS: freeifaddrs(ifaddr) + MGR-->>MGR: Return RFCMGR_DEVICE_ONLINE + end + end +``` + +### Platform Comparison + +```mermaid +sequenceDiagram + participant MGR as RFCManager + + alt RDKC Camera + MGR->>MGR: getifaddrs() loop
Every 10s until non-loopback IP found + else RDKB Broadband + MGR->>MGR: CheckIPConnectivity()
via dmcli eRouter query + MGR->>MGR: CheckIProuteConnectivity()
via ip route get + MGR->>MGR: isDnsResolve()
via nslookup + else STB Set-Top Box + MGR->>MGR: Check /tmp/route_available exists + MGR->>MGR: Check /etc/resolv.dnsmasq exists + end +``` + +--- + +## 3. Device Identity Collection + +```mermaid +sequenceDiagram + participant Init as InitializeRuntime
FeatureControlProcessor + participant XH as XconfHandler::
initializeXconfHandler() + participant Platform as Platform APIs + participant Files as Device Files + + Init->>Init: Skip GetBootstrapXconfUrl() [RDKC] + + Init->>XH: initializeXconfHandler() + + rect rgb(200, 230, 255) + Note over XH,Platform: MAC Address + alt STB + XH->>Platform: GetEstbMac() → /tmp/.estb_mac + else RDKB + XH->>Platform: getErouterMac() + else RDKC + XH->>Platform: popen("mfrApi_test 3 9") + Platform-->>XH: "AA:BB:CC:DD:EE:FF" + end + Note over XH: _estb_mac_address = result + end + + rect rgb(255, 243, 200) + Note over XH,Platform: Common Fields (all platforms) + XH->>Platform: GetFirmwareVersion() + Platform-->>XH: e.g. "XHC1_2.0.1" + XH->>Platform: GetBuildType() + Platform-->>XH: eDEV / eVBN / ePROD + XH->>Platform: GetModelNum() + Platform-->>XH: e.g. "XHC1" + end + + rect rgb(200, 230, 255) + Note over XH,Files: Manufacturer (not RDKC) + alt STB / RDKB + XH->>Platform: GetMFRName() + else RDKC + Note over XH: SKIP — not used in camera URL + end + end + + rect rgb(200, 230, 255) + Note over XH,Files: Partner ID + alt STB / RDKB + XH->>Platform: GetPartnerId() → /opt/partnerid + else RDKC + XH->>Files: fopen("/opt/usr_config/partnerid.txt") + Files-->>XH: "Comcast" + end + Note over XH: _partner_id = result + end + + XH-->>Init: return 0 + + rect rgb(220, 255, 220) + Note over Init,Files: Account ID + alt STB / RDKB + Init->>Init: read_RFCProperty() from TR-181 DB + else RDKC + Init->>Files: ifstream("/opt/usr_config/service_number.txt") + Files-->>Init: "5789171196032993066" + end + Note over Init: _accountId = result + end + + rect rgb(220, 255, 220) + Note over Init,Files: Account Hash (RDKC only) + Init->>Files: ifstream("/opt/usr_config/accounthash.txt") + Files-->>Init: "1EMvt8zMMd8muKCBJRnp1z6nZTgsBJ1VhL" + Note over Init: _accountHash = result + end +``` + +--- + +## 4. Xconf Query & Response Processing + +```mermaid +sequenceDiagram + participant Proc as RuntimeFeatureControl
Processor + participant Hash as Hash/Time Store + participant URL as URL Builder + participant mTLS as mtlsUtils + participant HTTP as libcurl + participant Xconf as Xconf Server + participant JSON as JSON Parser + participant Store as Parameter Store + + Note over Proc,Store: Step 1 — Load Stored State + Proc->>Hash: GetStoredHashAndTime() + alt RDKC + Hash->>Hash: Read /tmp/RFC/.hashValue + Hash->>Hash: Read /tmp/RFC/.timeValue + Note over Hash: Default: hash="UPGRADE_HASH", time="0" + else Other + Hash->>Hash: Check XconfSelector slot + Hash->>Hash: read_RFCProperty(ConfigSetHash) + end + Hash-->>Proc: {hash, timestamp} + + Note over Proc,Store: Step 2 — Build Request URL + Proc->>URL: CreateXconfHTTPUrl() [virtual] + alt RDKC Override + URL->>URL: GetAccountHash() + URL->>URL: Build: server?estbMacAddress=MAC
&firmwareVersion=FW&env=BUILD
&model=MODEL&accountHash=HASH
&partnerId=PID&accountId=AID
&experience=EXP&version=2 + else Default + URL->>URL: Build: server?estbMacAddress=MAC
&firmwareVersion=FW&env=BUILD
&model=MODEL&ecmMacAddress=ECM
&partnerId=PID&accountId=AID
&experience=EXP&manufacturer=MFR
&osclass=OS&version=2 + end + URL-->>Proc: URL string + + Note over Proc,Store: Step 3 — Secure HTTP Request + Proc->>mTLS: getMtlscert(&sec) [RDKC] + mTLS-->>Proc: {cert_path, password, status} + Proc->>HTTP: ExecuteRequest(url, &mTLS_creds, &httpCode) + HTTP->>Xconf: GET url (with mTLS cert) + Xconf-->>HTTP: HTTP 200 + JSON body + HTTP-->>Proc: response file path + + Note over Proc,Store: Step 4 — Parse & Apply + Proc->>JSON: ProcessJsonResponse(response) + JSON->>JSON: Parse features array + JSON->>JSON: Extract parameters per feature + JSON->>JSON: Build effectiveImmediate set [RDKC] + + loop For each feature parameter + Proc->>Store: clearDB() → remove old params + Proc->>Store: set_RFCProperty(name, key, value) + alt RDKC + Store->>Store: Read tr181store.ini + Store->>Store: Update/append key=value line + Store->>Store: Write tr181store.ini + else RDKB + Store->>Store: rbus_open → rbus_set → rbus_close + else STB + Store->>Store: setRFCParameter() via hostif + end + end + + Note over Proc,Store: Step 5 — Persist Metadata + Proc->>Hash: updateHashInDB(new_hash) + Proc->>Hash: updateTimeInDB(new_time) + Proc->>Proc: StoreXconfEndpointMetadata() [no-op on RDKC] +``` + +--- + +## 5. mTLS Certificate Acquisition + +```mermaid +sequenceDiagram + participant Proc as Processor + participant mTLS as getMtlscert() + participant FS as File System + participant Shell as Shell (utils.sh) + + Proc->>mTLS: getMtlscert(&sec) + + alt LIBRDKCERTSELECTOR path + mTLS->>mTLS: rdkcertselector_new() + mTLS->>mTLS: Iterate cert selector choices + mTLS-->>Proc: MTLS_SUCCESS + cert details + else RDKC path + mTLS->>FS: access("/opt/certs/devicecert_1.pk12") + alt Dynamic XPKI exists + mTLS->>Shell: popen(". /lib/rdk/utils.sh && getxpkiPass") + Shell-->>mTLS: password string + alt Password OK + Note over mTLS: sec.cert = "/opt/certs/devicecert_1.pk12"
sec.password = password + mTLS-->>Proc: MTLS_SUCCESS + else Password failed + Note over mTLS: Fall through to static + end + end + + mTLS->>FS: access("/etc/ssl/certs/staticXpkiCrt.pk12") + alt Static XPKI exists + mTLS->>Shell: popen(". /lib/rdk/utils.sh && getstaticxpkiPass") + Shell-->>mTLS: password string + alt Password OK + Note over mTLS: sec.cert = "/etc/ssl/certs/staticXpkiCrt.pk12"
sec.password = password + mTLS-->>Proc: MTLS_SUCCESS + else Password failed + mTLS-->>Proc: MTLS_FAILURE + end + else No static cert + mTLS-->>Proc: MTLS_FAILURE + end + end + + alt MTLS_SUCCESS + Proc->>Proc: ExecuteRequest(&file_dwnl, &sec, &httpCode) + else MTLS_FAILURE + Proc->>Proc: ExecuteRequest(&file_dwnl, NULL, &httpCode) + Note over Proc: Proceed without mTLS + end +``` + +--- + +## 6. Parameter Application + +```mermaid +sequenceDiagram + participant Proc as Processor + participant JSON as JSON Parser + participant INI as tr181store.ini + participant API as rfcapi / rbus / hostif + + Proc->>JSON: Read features[] from response + + loop For each feature in features[] + JSON->>JSON: Extract feature name, configData[], effectiveImmediate + + loop For each param in configData[] + JSON->>JSON: Get {key, value, dataType} + + Proc->>Proc: set_RFCProperty(featureName, key, value) + + alt RDKC Platform + Proc->>INI: Read entire file into lines[] + + alt Key exists in file + Proc->>INI: Replace line: key=value + else Key not found + Proc->>INI: Append: key=value + end + + Proc->>INI: Write all lines back + else RDKB Platform + Proc->>API: rbus_open() + Proc->>API: rbus_set(key, value) + Proc->>API: rbus_close() + else STB Platform + Proc->>API: setRFCParameter(key, value, type) + end + end + end +``` + +--- + +## 7. Reboot Evaluation & Scheduling + +```mermaid +sequenceDiagram + participant Proc as Processor + participant JSON as Feature JSON + participant Device as Device Properties + participant Cron as RfcRebootCronschedule.sh + participant MGR as RFCManager + + Note over Proc,MGR: Step 1 — Build effectiveImmediate set (RDKC) + Proc->>JSON: Parse features[] + loop For each feature + alt feature.effectiveImmediate == true + loop For each param in feature.configData + Proc->>Proc: _effectiveImmediateParams.insert(param.key) + end + end + end + + Note over Proc,MGR: Step 2 — Evaluate per-param reboot need + loop For each applied parameter + alt param.key in _effectiveImmediateParams + Proc->>Device: getDevicePropertyData("RDKC_DEVICE_PROVISION_STATUS") + Device-->>Proc: "1" (provisioned) / "0" (not provisioned) + + alt Device is provisioned + alt param is NOT AccountID or MD5AccountHash + Proc->>Proc: _rfcRebootCronNeeded = true + Note over Proc: Reboot required for this parameter + else Identity param — skip + Note over Proc: No reboot for identity changes + end + else Not provisioned + Note over Proc: No reboot — device not provisioned + end + else Not in effectiveImmediate set + Note over Proc: No reboot needed + end + end + + Note over Proc,MGR: Step 3 — Trigger reboot (if needed) + Proc-->>MGR: Return from ProcessRuntimeFeatureControlReq() + MGR->>Proc: getRfcRebootCronNeeded() + + alt _rfcRebootCronNeeded == true + MGR->>Cron: v_secure_system("sh /lib/rdk/RfcRebootCronschedule.sh &") + Note over Cron: Schedule device reboot via cron + else No reboot needed + Note over MGR: Continue to post-processing + end +``` + +--- + +## 8. Post-Processing & Cleanup + +```mermaid +sequenceDiagram + participant MGR as RFCManager + participant Proc as Processor + participant MM as MaintenanceManager + participant Cron as Cron System + participant FS as File System + + Note over MGR,FS: After ProcessRuntimeFeatureControlReq() returns + + alt RDKC Platform + MGR->>MGR: Skip MaintenanceManager notification + MGR->>Proc: getRfcRebootCronNeeded() + alt Reboot needed + MGR->>FS: v_secure_system("sh /lib/rdk/RfcRebootCronschedule.sh &") + end + else STB Platform + MGR->>MM: SendEventToMaintenanceManager(MAINT_RFC_COMPLETE) + alt RFC error occurred + MGR->>MM: SendEventToMaintenanceManager(MAINT_RFC_ERROR) + end + alt Reboot required + MGR->>MM: SendEventToMaintenanceManager(MAINT_CRITICAL_UPDATE) + MGR->>MM: SendEventToMaintenanceManager(MAINT_REBOOT_REQUIRED) + end + end + + Note over MGR,FS: Post-Processing + MGR->>MGR: RFCManagerPostProcess() + MGR->>Cron: Configure periodic cron schedule + + alt RDKC + Note over Cron: Entry: schedule /usr/bin/rfcMgr + else Other + Note over Cron: Entry: schedule /usr/bin/rfcMgr >> /rdklogs/logs/dcmrfc.log.0 2>&1 + end + + Note over MGR,FS: Cleanup + MGR-->>FS: Return → main() + FS->>FS: atexit() → cleanup_lock_file() + FS->>FS: Remove /tmp/.rfcServiceLock +``` diff --git a/rfcMgr/Makefile.am b/rfcMgr/Makefile.am index 2d6186bb..b5cedb3a 100644 --- a/rfcMgr/Makefile.am +++ b/rfcMgr/Makefile.am @@ -25,6 +25,19 @@ AM_LDFLAGS = -L$(PKG_CONFIG_SYSROOT_DIR)/$(libdir) AM_LDFLAGS += $(cjson_LIBS) $(curl_LIBS) AM_LDFLAGS += -lrdkloggers -ldwnlutil -lfwutils -lparsejson -lsecure_wrapper -lcurl +if ENABLE_RDKC +rfcMgr_SOURCES += rdkc_rfc_xconf_handler.cpp +if ENABLE_XCAM2 +rfcMgr_CPPFLAGS += -DRDKC -I${RDK_FSROOT_PATH}/usr/include/ +AM_LDFLAGS += -L${RDK_FSROOT_PATH}/usr/lib/ -lrdkloggers -ldwnlutil -lfwutils -lparsejson -lsecure_wrapper -lcurl -lrfcapi +AM_LDFLAGS += -L${RDK_SOURCE_PATH}/rfcapi/.libs/ -lrfcapi +else +rfcMgr_CPPFLAGS += -DRDKC -I${STAGING_DIR_TARGET}/usr/include/ +AM_LDFLAGS += -L${STAGING_DIR_TARGET}/usr/lib/ -lrdkloggers -ldwnlutil -lfwutils -lparsejson -lsecure_wrapper -lcurl -lrfcapi +AM_LDFLAGS += -L../../build/rfcapi/.libs/ -lrfcapi +endif +endif + if IS_IARMBUS_ENABLED rfcMgr_CPPFLAGS += $(IARMBUS_EVENT_FLAG) -I$(PKG_CONFIG_SYSROOT_DIR)${includedir}/rdk/iarmbus AM_LDFLAGS += -lIARMBus @@ -34,8 +47,10 @@ if ENABLE_RDKB rfcMgr_CPPFLAGS += $(RDKB_FLAG) $(rbus_CFLAGS) $(RDKBEXTENDER_FLAG) AM_LDFLAGS += -lrbus else +if !ENABLE_RDKC AM_LDFLAGS += ../rfcapi/.libs/librfcapi.la endif +endif if ENABLE_RDKBEXTENDER rfcMgr_CPPFLAGS += $(RDKBEXTENDER_FLAG) diff --git a/rfcMgr/mtlsUtils.cpp b/rfcMgr/mtlsUtils.cpp index 2963c066..bbee9a37 100644 --- a/rfcMgr/mtlsUtils.cpp +++ b/rfcMgr/mtlsUtils.cpp @@ -1,21 +1,23 @@ -/*############################################################################## - # If not stated otherwise in this file or this component's LICENSE file the - # following copyright and licenses apply: - # - # Copyright 2020 RDK Management - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - ############################################################################## +/** + * @file mtlsUtils.cpp + * @brief mTLS certificate retrieval and state-red recovery implementation. + * + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "mtlsUtils.h" @@ -23,15 +25,20 @@ #ifdef LIBRDKCONFIG_BUILD #include "rdkconfig.h" #endif +#ifdef RDKC +#include +#endif #ifdef __cplusplus extern "C" { #endif -/* Description: Checking state red support is present or not - * return :1 = if state red support is present - * return :0 = if state red support is not present */ +/** + * @brief Check if state-red recovery is supported on this device. + * @retval 1 Supported (support file exists). + * @retval 0 Not supported. + */ int isStateRedSupported(void) { int ret = -1; ret = filePresentCheck(STATE_RED_SPRT_FILE); @@ -43,10 +50,11 @@ int isStateRedSupported(void) { return 0; } -/* Description: Checking either device is in state red or not. - * return 1: In state red - * 0: Not in state red - * */ +/** + * @brief Check if the device is currently in state-red. + * @retval 1 Device is in state-red. + * @retval 0 Device is not in state-red. + */ int isInStateRed(void) { int ret = -1; int stateRed = 0; @@ -66,10 +74,12 @@ int isInStateRed(void) { } #ifdef LIBRDKCERTSELECTOR -/* Description: Use for get all mtls related certificate and key. - * @param sec: This is a pointer hold the certificate, key and type of certificate. - * @return : MTLS_CERT_FETCH_SUCCESS on success, MTLS_CERT_FETCH_FAILURE on mtls cert failure , STATE_RED_CERT_FETCH_FAILURE on state red cert failure - * */ +/** + * @brief Fetch mTLS certificate and key via librdkcertselector. + * @param[out] sec Populated mTLS auth structure. + * @param[out] pthisCertSel Certificate-selector handle (caller frees). + * @return MtlsAuthStatus result code. + */ MtlsAuthStatus getMtlscert(MtlsAuth_t *sec, rdkcertselector_h* pthisCertSel) { /* strncpy(sec->cert_name, STATE_RED_CERT, sizeof(sec->cert_name) - 1); @@ -83,11 +93,80 @@ MtlsAuthStatus getMtlscert(MtlsAuth_t *sec, rdkcertselector_h* pthisCertSel) { (void)pthisCertSel; return MTLS_CERT_FETCH_SUCCESS; } +#elif defined(RDKC) +/** + * @brief RDKC camera mTLS certificate retrieval. + * + * Mirrors mtlsUtils.sh / checkxpki flow from RFCbase.sh: + * 1. Try dynamic XPKI cert (CERT_DYNAMIC). + * 2. Fall back to static XPKI cert (CERT_STATIC). + * 3. If neither available, return MTLS_FAILURE. + */ +static int runShellCmd(const char *cmd, char *outBuf, size_t bufLen) +{ + FILE *fp = popen(cmd, "r"); + if (fp == NULL) { + return -1; + } + if (fgets(outBuf, bufLen, fp) != NULL) { + size_t len = strlen(outBuf); + while (len > 0 && (outBuf[len - 1] == '\n' || outBuf[len - 1] == '\r')) { + outBuf[--len] = '\0'; + } + pclose(fp); + return (len > 0) ? 0 : -1; + } + pclose(fp); + return -1; +} + +int getMtlscert(MtlsAuth_t *sec) { + struct stat st; + + if (sec == NULL) { + RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "getMtlscert(): NULL pointer\n"); + return MTLS_FAILURE; + } + memset(sec, '\0', sizeof(MtlsAuth_t)); + + /* Try dynamic XPKI cert first — matches checkxpki() in utils.sh */ + if (stat(CERT_DYNAMIC, &st) == 0 && st.st_size > 0) { + strncpy(sec->cert_name, CERT_DYNAMIC, sizeof(sec->cert_name) - 1); + sec->cert_name[sizeof(sec->cert_name) - 1] = '\0'; + strncpy(sec->cert_type, "P12", sizeof(sec->cert_type) - 1); + sec->cert_type[sizeof(sec->cert_type) - 1] = '\0'; + /* Password via rdkssacli — same as getxpkiPass() in utils.sh */ + if (runShellCmd(". /lib/rdk/utils.sh && getxpkiPass", sec->key_pas, sizeof(sec->key_pas)) == 0) { + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "getMtlscert(): RDKC dynamic XPKI cert: %s\n", CERT_DYNAMIC); + return MTLS_SUCCESS; + } + RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "getMtlscert(): RDKC dynamic cert found but password retrieval failed\n"); + } + + /* Fall back to static XPKI cert — matches static path in checkxpki() */ + if (stat(CERT_STATIC, &st) == 0 && st.st_size > 0) { + strncpy(sec->cert_name, CERT_STATIC, sizeof(sec->cert_name) - 1); + sec->cert_name[sizeof(sec->cert_name) - 1] = '\0'; + strncpy(sec->cert_type, "P12", sizeof(sec->cert_type) - 1); + sec->cert_type[sizeof(sec->cert_type) - 1] = '\0'; + /* Password via GetConfigFile — same as getstaticxpkiPass() in utils.sh */ + if (runShellCmd(". /lib/rdk/utils.sh && getstaticxpkiPass", sec->key_pas, sizeof(sec->key_pas)) == 0) { + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "getMtlscert(): RDKC static XPKI cert: %s\n", CERT_STATIC); + return MTLS_SUCCESS; + } + RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "getMtlscert(): RDKC static cert found but password retrieval failed\n"); + } + + /* No cert available — models without XPKI proceed without mTLS */ + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "getMtlscert(): RDKC no XPKI cert available, proceeding without mTLS\n"); + return MTLS_FAILURE; +} #else -/* Description: Use for get all mtls related certificate and key. - * @param sec: This is a pointer hold the certificate, key and type of certificate. - * @return : int Success 1 and failure -1 - * */ +/** + * @brief Fetch mTLS certificate and key (legacy / non-certselector path). + * @param[out] sec Populated mTLS auth structure. + * @return MTLS_SUCCESS (1) or MTLS_FAILURE (-1). + */ int getMtlscert(MtlsAuth_t *sec) { /* strncpy(sec->cert_name, STATE_RED_CERT, sizeof(sec->cert_name) - 1); diff --git a/rfcMgr/mtlsUtils.h b/rfcMgr/mtlsUtils.h index 9688bfad..de633a04 100644 --- a/rfcMgr/mtlsUtils.h +++ b/rfcMgr/mtlsUtils.h @@ -1,21 +1,23 @@ -/*############################################################################## - # If not stated otherwise in this file or this component's LICENSE file the - # following copyright and licenses apply: - # - # Copyright 2020 RDK Management - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - ############################################################################## +/** + * @file mtlsUtils.h + * @brief mTLS certificate retrieval and state-red recovery utilities. + * + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef VIDEO_REF_INTERFACE_MTLSUTILS_H_ @@ -35,29 +37,44 @@ extern "C" { #ifdef LIBRDKCERTSELECTOR #include "rdkcertselector.h" -// Below macro is invoked if the getMtlscert API fails to retrieve all MTLS certificates. +/** cURL error returned when the local certificate file is missing/broken. */ #define CURL_MTLS_LOCAL_CERTPROBLEM 58 +/** + * @brief mTLS certificate fetch status codes (librdkcertselector path). + */ typedef enum { - STATE_RED_CERT_FETCH_FAILURE = -2, // Indicates failure in state red recovery - MTLS_CERT_FETCH_FAILURE = -1, // Indicates general MTLS failure - MTLS_CERT_FETCH_SUCCESS = 0 // Indicates success + STATE_RED_CERT_FETCH_FAILURE = -2, /**< State-red recovery itself failed. */ + MTLS_CERT_FETCH_FAILURE = -1, /**< General mTLS cert fetch failure. */ + MTLS_CERT_FETCH_SUCCESS = 0 /**< Certificate fetched successfully. */ } MtlsAuthStatus; +/** + * @brief Fetch mTLS certificate and key via librdkcertselector. + * @param[out] sec Populated mTLS auth structure. + * @param[out] pthisCertSel Certificate-selector handle (caller frees). + * @return MtlsAuthStatus result code. + */ MtlsAuthStatus getMtlscert(MtlsAuth_t *sec, rdkcertselector_h* pthisCertSel); #else -#define MTLS_SUCCESS 1 -#define MTLS_FAILURE -1 +#define MTLS_SUCCESS 1 /**< mTLS success (non-librdkcertselector path). */ +#define MTLS_FAILURE -1 /**< mTLS failure (non-librdkcertselector path). */ + +/** + * @brief Fetch mTLS certificate (legacy / non-certselector path). + * @param[out] sec Populated mTLS auth structure. + * @return MTLS_SUCCESS or MTLS_FAILURE. + */ int getMtlscert(MtlsAuth_t *sec); #endif -#define CERT_DYNAMIC "/opt/certs/devicecert_1.pk12" -#define CERT_STATIC "/etc/ssl/certs/staticXpkiCrt.pk12" +#define CERT_DYNAMIC "/opt/certs/devicecert_1.pk12" /**< Dynamic XPKI certificate path. */ +#define CERT_STATIC "/etc/ssl/certs/staticXpkiCrt.pk12" /**< Static XPKI certificate path. */ /** - * Below macros are placeholders. - * Users are free to override with their custom certs and verifier algorithms during compile time - **/ + * @name Certificate / key placeholders. + * Override at compile time with device-specific paths. + * @{ */ #define KEY_STATIC "" #define STATE_RED_CERT "" #define STATE_RED_KEY "" @@ -67,14 +84,19 @@ int getMtlscert(MtlsAuth_t *sec); #define SYS_CMD_GET_CONFIG_FILE "" #define STATE_RED_SPRT_FILE "" #define STATEREDFLAG "" +/** @} */ #if defined(GTEST_ENABLE) +/** @brief Check if state-red recovery is supported on this build. */ int isStateRedSupported(void); +/** @brief Check if the device is currently in state-red. */ int isInStateRed(void); #endif #if defined(RDKB_SUPPORT) +/** @brief Get the eRouter MAC address string. */ std::string getErouterMac(); +/** @brief Get the eCM (cable modem) MAC address string. */ std::string geteCMMac(); #endif diff --git a/rfcMgr/rdkc_rfc_xconf_handler.cpp b/rfcMgr/rdkc_rfc_xconf_handler.cpp new file mode 100644 index 00000000..20988ced --- /dev/null +++ b/rfcMgr/rdkc_rfc_xconf_handler.cpp @@ -0,0 +1,216 @@ +/** + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * rdkc_rfc_xconf_handler.cpp + * + * RDKC-specific overrides of RuntimeFeatureControlProcessor. + * See rdkc_rfc_xconf_handler.h for the design rationale. + **/ + +#ifdef RDKC + +#include "rdkc_rfc_xconf_handler.h" +#include "rfc_common.h" /* read_RFCProperty, RFC_VALUE_BUF_SIZE, LOG_RFCMGR */ +#include "rdk_debug.h" +#include +#include + +/* ------------------------------------------------------------------------- + * Constants + * ---------------------------------------------------------------------- */ + +/** TR181 parameter holding the MD5 account hash on camera devices. */ +#define RFC_MD5_ACCOUNT_HASH \ + "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.MD5AccountHash" + +/** RAM-backed directory used for transient RFC state on all platforms. */ +#define RFC_RAM_PATH "/tmp/RFC" + +/* ========================================================================= + * GetAccountHash — lazy fetch, cached in _accountHash + * ====================================================================== */ + +/** + * Read the MD5 account hash from the RFC parameter store. + * Called once (lazily) from CreateXconfHTTPUrl() before building the URL. + * + * Shell equivalent (XHC1 branch in RFCbase.sh): + * . $RDK_PATH/getAccountHash.sh + * JSONSTR='...&accountHash='$(getAccountHash)'&...' + */ +void RdkcRuntimeFeatureControlProcessor::GetAccountHash() +{ + if (!_accountHash.empty()) + return; /* already populated */ + + /* RDKC: read account hash from /opt/usr_config/accounthash.txt. + * Shell equivalent: . $RDK_PATH/getAccountHash.sh → getAccountHash() */ + std::ifstream ifs("/opt/usr_config/accounthash.txt"); + if (ifs.is_open()) + { + std::getline(ifs, _accountHash); + ifs.close(); + if (!_accountHash.empty()) + { + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC AccountHash: %s\n", + __FUNCTION__, __LINE__, _accountHash.c_str()); + return; + } + } + + RDK_LOG(RDK_LOG_WARN, LOG_RFCMGR, + "[%s][%d] RDKC: /opt/usr_config/accounthash.txt not found or empty\n", + __FUNCTION__, __LINE__); +} + +/* ========================================================================= + * CreateXconfHTTPUrl — camera-specific query parameters + * ====================================================================== */ + +/** + * Build the Xconf HTTP request URL for camera (XHC1) devices. + * + * Differences from the base implementation: + * - Adds : accountHash (camera-specific identity field) + * - Omits : manufacturer, ecmMacAddress, osClass, controllerId, + * channelMapId, vodId (not applicable on camera) + * + * Shell equivalent (XHC1 branch in sendHttpRequestToServer): + * JSONSTR='estbMacAddress='$(getEstbMacAddress) + * '&firmwareVersion='$(getFWVersion) + * '&env='$(getBuildType) + * '&model='$(getModel) + * '&accountHash='$(getAccountHash) + * '&partnerId='$(getPartnerId) + * '&accountId='$(getAccountId) + * '&experience='$(getExperience) + * '&version=2' + */ +std::stringstream RdkcRuntimeFeatureControlProcessor::CreateXconfHTTPUrl() +{ + GetAccountHash(); + + std::stringstream url; + url << _xconf_server_url << "?"; + url << "estbMacAddress=" << _estb_mac_address << "&"; + url << "firmwareVersion=" << _firmware_version << "&"; + url << "env=" << _build_type_str << "&"; + url << "model=" << _model_number << "&"; + url << "accountHash=" << _accountHash << "&"; + url << "partnerId=" << _partner_id << "&"; + url << "accountId=" << _accountId << "&"; + url << "experience=" << _experience << "&"; + url << "version=2"; + + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC Xconf request URL built\n", + __FUNCTION__, __LINE__); + + return url; +} + +/* ========================================================================= + * RetrieveHashAndTimeFromPreviousDataSet — RAM files only + * ====================================================================== */ + +/** + * Read configSetHash and configSetTime from RAM-backed files. + * + * RDKC devices (XHC1) never use the TR181 parameter database for + * hash/time storage. Both values are always written to and read from + * /tmp/RFC/.hashValue and /tmp/RFC/.timeValue. + * + * Shell equivalent (rfcGetHashAndTime, XHC1 branch): + * if [ "$DEVICE_TYPE" = "XHC1" ]; then + * valueHash=`cat $RFC_RAM_PATH/.hashValue` + * valueTime=`cat $RFC_RAM_PATH/.timeValue` + * fi + */ +void RdkcRuntimeFeatureControlProcessor::RetrieveHashAndTimeFromPreviousDataSet( + std::string &valueHash, std::string &valueTime) +{ + valueHash = "UPGRADE_HASH"; + valueTime = "0"; + + const std::string hashFile = std::string(RFC_RAM_PATH) + "/.hashValue"; + if (access(hashFile.c_str(), R_OK) == 0) + { + std::ifstream ifs(hashFile); + if (ifs.is_open()) + { + std::getline(ifs, valueHash); + ifs.close(); + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC ConfigSetHash: %s\n", + __FUNCTION__, __LINE__, valueHash.c_str()); + } + } + else + { + RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR, + "[%s][%d] RDKC: hash file not found, using default\n", + __FUNCTION__, __LINE__); + } + + const std::string timeFile = std::string(RFC_RAM_PATH) + "/.timeValue"; + if (access(timeFile.c_str(), R_OK) == 0) + { + std::ifstream ifs(timeFile); + if (ifs.is_open()) + { + std::getline(ifs, valueTime); + ifs.close(); + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC ConfigSetTime: %s\n", + __FUNCTION__, __LINE__, valueTime.c_str()); + } + } + else + { + RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR, + "[%s][%d] RDKC: time file not found, using default\n", + __FUNCTION__, __LINE__); + } + + bkup_hash = valueHash; /* keep backup consistent */ +} + +/* ========================================================================= + * StoreXconfEndpointMetadata — no-op for camera + * ====================================================================== */ + +/** + * RDKC devices (XHC1) must NOT write XconfSelector or XconfUrl back + * to the parameter store after a successful Xconf sync. + * + * Shell equivalent (processJsonResponseV / sendHttpRequestToServer): + * if [ "$DEVICE_TYPE" != "XHC1" ]; then + * rfcSet ${XCONF_SELECTOR_TR181_NAME} string "$rfcSelectOpt" + * rfcSet ${XCONF_URL_TR181_NAME} string "$rfcSelectUrl" + * fi + */ +void RdkcRuntimeFeatureControlProcessor::StoreXconfEndpointMetadata() +{ + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC (XHC1): skipping XconfSelector/XconfUrl storage\n", + __FUNCTION__, __LINE__); + /* Intentional no-op */ +} + +#endif /* RDKC */ diff --git a/rfcMgr/rdkc_rfc_xconf_handler.h b/rfcMgr/rdkc_rfc_xconf_handler.h new file mode 100644 index 00000000..e4575ce6 --- /dev/null +++ b/rfcMgr/rdkc_rfc_xconf_handler.h @@ -0,0 +1,86 @@ +/** + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * rdkc_rfc_xconf_handler.h + * + * RDKC-specific (RDKC / XHC1) RFC handler. + * + * Inherits all common RFC request/response logic from + * RuntimeFeatureControlProcessor and overrides only the three methods + * whose behaviour differs on camera platforms: + * + * CreateXconfHTTPUrl() + * RDKC query string adds "accountHash" and omits + * manufacturer / ecmMacAddress / osClass. + * + * RetrieveHashAndTimeFromPreviousDataSet() + * RDKC devices store configSetHash / configSetTime in RAM + * files only (/tmp/RFC/.hashValue, /tmp/RFC/.timeValue). + * No TR181 DB lookup is performed. + * + * StoreXconfEndpointMetadata() + * XHC1 must NOT write XconfSelector / XconfUrl back to the + * data store after a successful sync — this is a no-op. + **/ + +#pragma once +#ifdef RDKC + +#include "rfc_xconf_handler.h" +#include +#include + +/** + * @class RdkcRuntimeFeatureControlProcessor + * @brief RDKC camera-specific RFC processor subclass. + * + * Inherits all common RFC logic from RuntimeFeatureControlProcessor + * and overrides only platform-specific methods. + */ +class RdkcRuntimeFeatureControlProcessor : public RuntimeFeatureControlProcessor +{ +public: + /** @brief Default constructor. */ + RdkcRuntimeFeatureControlProcessor() = default; + + RdkcRuntimeFeatureControlProcessor(const RdkcRuntimeFeatureControlProcessor&) = delete; /**< Copy disabled. */ + RdkcRuntimeFeatureControlProcessor& operator=(const RdkcRuntimeFeatureControlProcessor&) = delete; /**< Assignment disabled. */ + +protected: + /** @brief Build RDKC-specific Xconf URL (adds accountHash, omits manufacturer). */ + std::stringstream CreateXconfHTTPUrl() override; + + /** + * @brief Read configSetHash/Time from RAM files (/tmp/RFC/). + * @param[out] valueHash Retrieved hash string. + * @param[out] valueTime Retrieved time string. + */ + void RetrieveHashAndTimeFromPreviousDataSet(std::string &valueHash, + std::string &valueTime) override; + + /** @brief No-op — RDKC must not persist XconfSelector/XconfUrl. */ + void StoreXconfEndpointMetadata() override; + +private: + std::string _accountHash; /**< MD5 account hash, XHC1-specific query param. */ + + /** @brief Lazy-fetch the MD5 account hash from the RFC parameter store. */ + void GetAccountHash(); +}; + +#endif /* RDKC */ diff --git a/rfcMgr/rfc_common.cpp b/rfcMgr/rfc_common.cpp index ae171058..6cdc3f00 100644 --- a/rfcMgr/rfc_common.cpp +++ b/rfcMgr/rfc_common.cpp @@ -1,21 +1,23 @@ -/*############################################################################## - # If not stated otherwise in this file or this component's LICENSE file the - # following copyright and licenses apply: - # - # Copyright 2024 RDK Management - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - ############################################################################## +/** + * @file rfc_common.cpp + * @brief Common RFC utility functions — parameter reading, string helpers. + * + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ @@ -28,7 +30,11 @@ #include #endif - +/** + * @brief Query a sysevent key via the CLI. + * @param[in] key Sysevent key name. + * @return Value string, or empty on failure. + */ std::string getSyseventValue(const std::string& key) { std::string cmd = "sysevent get " + key; @@ -52,6 +58,12 @@ std::string getSyseventValue(const std::string& key) return result; } +/** + * @brief Block until webconfig RFC blob processing completes (RDKB). + * + * Polls the "rfc_blob_processing" sysevent with 100 s retries + * (up to ~10 min total) before proceeding. + */ void waitForRfcCompletion() { // Check RFC blob processing status @@ -90,12 +102,14 @@ void waitForRfcCompletion() } } -/* Description: Reading rfc data - * @param type : rfc type - * @param key: rfc key - * @param data : Store rfc value - * @return int 1 READ_RFC_SUCCESS on success and READ_RFC_FAILURE -1 on failure - * */ +/** + * @brief Read an RFC parameter from the data store. + * @param[in] type Caller ID / namespace (may be NULL on RDKB/RDKC). + * @param[in] key TR181 parameter name. + * @param[out] out_value Buffer to receive the value. + * @param[in] datasize Size of @p out_value buffer. + * @return READ_RFC_SUCCESS (1) or READ_RFC_FAILURE (-1). + */ int read_RFCProperty(const char* type, const char* key, char *out_value, int datasize) { int ret = READ_RFC_FAILURE; @@ -170,6 +184,33 @@ int read_RFCProperty(const char* type, const char* key, char *out_value, int dat } rbus_close(handle); +#elif defined(RDKC) + RFC_ParamData_t param; + memset(¶m, 0, sizeof(RFC_ParamData_t)); + (void)type; + + int data_len; + int status = getRFCParameter(key, ¶m); + if(status == SUCCESS) + { + data_len = strlen(param.value); + if(data_len >= 2 && (param.value[0] == '"') && (param.value[data_len - 1] == '"')) + { + snprintf(out_value, datasize, "%s", ¶m.value[1]); + *(out_value + data_len - 2) = 0; + } + else + { + snprintf(out_value, datasize, "%s", param.value); + } + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC name=%s,type=%d,value=%s,status=%d\n", __FUNCTION__, __LINE__, param.name, param.type, param.value, status); + ret = READ_RFC_SUCCESS; + } + else + { + RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] RFC Read status= %d\n", __FUNCTION__, __LINE__, status); + *out_value = 0; + } #else RFC_ParamData_t param; memset(¶m, 0, sizeof(RFC_ParamData_t)); diff --git a/rfcMgr/rfc_common.h b/rfcMgr/rfc_common.h index 06f8c721..6d3a0997 100644 --- a/rfcMgr/rfc_common.h +++ b/rfcMgr/rfc_common.h @@ -1,4 +1,7 @@ /** + * @file rfc_common.h + * @brief Common utilities, macros, and helpers for the RFC Manager. + * * If not stated otherwise in this file or this component's LICENSE * file the following copyright and licenses apply: * @@ -15,14 +18,14 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - **/ + */ #ifndef RFC_MGR_COMMON_H #define RFC_MGR_COMMON_H -/*----------------------------------------------------------------------------*/ -/* Header File */ -/*----------------------------------------------------------------------------*/ +/** @addtogroup rfcMgr + * @{ */ + #include "rdk_debug.h" #include "rfcapi.h" #include "rfc_mgr_key.h" @@ -41,10 +44,10 @@ #include #include #include -/*----------------------------------------------------------------------------*/ -/* Macros */ -/*----------------------------------------------------------------------------*/ -#define LOG_RFCMGR "LOG.RDK.RFCMGR" + +/** @name Macros + * @{ */ +#define LOG_RFCMGR "LOG.RDK.RFCMGR" /**< RDK Logger module name. */ #define FAILURE -1 #define SUCCESS 0 @@ -63,23 +66,75 @@ #define DEFAULT_DL_ALLOC 1024 +/** System command type selector for executeCommandAndGetOutput(). */ typedef enum { - eRdkSsaCli, - eWpeFrameworkSecurityUtility + eRdkSsaCli, /**< Use rdkssacli binary. */ + eWpeFrameworkSecurityUtility /**< Use WPEFrameworkSecurityUtility binary. */ } SYSCMD; #define WPEFRAMEWORKSECURITYUTILITY "/usr/bin/WPEFrameworkSecurityUtility" #define RDKSSACLI_CMD "/usr/bin/rdkssacli %s" #define KEY_GEN_BIN "/usr/bin/rdkssacli" +/** @} */ /* end Macros */ + +/** + * @brief Execute a system binary and capture its stdout. + * @param[in] eSysCmd Which binary to invoke. + * @param[in] pArgs Arguments passed to the binary. + * @param[out] result Captured standard output. + * @return SUCCESS (0) or FAILURE (-1). + */ int executeCommandAndGetOutput(SYSCMD, const char *, std::string&); + +/** + * @brief Read an RFC parameter from the data store. + * @param[in] type Caller ID / namespace (may be NULL on RDKB/RDKC). + * @param[in] key TR181 parameter name. + * @param[out] out_value Buffer to receive the value. + * @param[in] datasize Size of @p out_value buffer. + * @return READ_RFC_SUCCESS (1) or READ_RFC_FAILURE (-1). + */ int read_RFCProperty(const char* , const char* , char *, int ); + +/** + * @brief Return true if @p str contains characters outside [a-zA-Z0-9._-]. + */ bool CheckSpecialCharacters(const std::string&); + +/** + * @brief Case-insensitive string comparison. + */ bool StringCaseCompare(const std::string& , const std::string& ); + +/** + * @brief Erase every occurrence of @p toRemove from @p str in-place. + */ void RemoveSubstring(std::string& str, const std::string& toRemove); + +/** + * @brief Block until webconfig RFC blob processing completes (RDKB). + */ void waitForRfcCompletion(); + +/** + * @brief Retrieve the eRouter WAN IP address (IPv6 preferred). + */ std::string getErouterIPAddress(); + +/** + * @brief Query a sysevent key via the CLI. + * @param[in] key Sysevent key name. + * @return Value string, or empty on failure. + */ std::string getSyseventValue(const std::string& key); + +/** + * @brief Parse the cron schedule from DCM settings. + * @return Five-field cron string. + */ std::string getCronFromDCMSettings(); +/** @} */ /* end rfcMgr group */ + #endif diff --git a/rfcMgr/rfc_main.cpp b/rfcMgr/rfc_main.cpp index 57ce377d..deee34b2 100644 --- a/rfcMgr/rfc_main.cpp +++ b/rfcMgr/rfc_main.cpp @@ -1,4 +1,7 @@ /** + * @file rfc_main.cpp + * @brief RFC Manager daemon entry point. + * * If not stated otherwise in this file or this component's LICENSE * file the following copyright and licenses apply: * @@ -15,7 +18,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - **/ + */ #include "rfc_common.h" #include "rfc_manager.h" @@ -32,14 +35,14 @@ extern "C" { #include -// Cleanup function +/** @brief Remove the service lock file on exit. */ void cleanup_lock_file(void) { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC: Completed service, deleting lock\n", __FUNCTION__, __LINE__); unlink(RFC_MGR_SERVICE_LOCK_FILE); } -// Signal handler for graceful shutdown +/** @brief Signal handler — clean up and exit gracefully. */ void signal_handler(int sig) { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "RFC: Received signal %d, cleaning up lock file\n", sig); @@ -47,6 +50,12 @@ void signal_handler(int sig) exit(0); } +/** + * @brief Create a directory if it does not already exist. + * @param[in] path Absolute directory path. + * @retval true Directory exists or was created. + * @retval false Creation failed. + */ bool createDirectoryIfNotExists(const char* path) { if (!path || *path == '\0') { RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Invalid path\n", __FUNCTION__, __LINE__); @@ -94,7 +103,14 @@ int main() RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] RFC: Failed to create RFC directory\n", __FUNCTION__, __LINE__); exit(EXIT_FAILURE); } - + +#if defined(RDKB_SUPPORT) || defined(RDKC) + /* Create /tmp/RFC/ for hash/time RAM files (RDKB & RDKC only) */ + if (!createDirectoryIfNotExists("/tmp/RFC")) { + RDK_LOG(RDK_LOG_WARN, LOG_RFCMGR, "[%s][%d] RFC: Failed to create /tmp/RFC directory\n", __FUNCTION__, __LINE__); + } +#endif + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC: Starting service, creating lock \n", __FUNCTION__, __LINE__); #if defined(RDKB_SUPPORT) diff --git a/rfcMgr/rfc_manager.cpp b/rfcMgr/rfc_manager.cpp index 99a99d85..68f9ea00 100644 --- a/rfcMgr/rfc_manager.cpp +++ b/rfcMgr/rfc_manager.cpp @@ -1,4 +1,7 @@ /** + * @file rfc_manager.cpp + * @brief RFC Manager implementation — device connectivity, IARM, Xconf lifecycle. + * * If not stated otherwise in this file or this component's LICENSE * file the following copyright and licenses apply: * @@ -15,22 +18,34 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - **/ + */ #include "rfc_manager.h" #include "rfc_common.h" #include "rfc_mgr_iarm.h" #include "rfc_xconf_handler.h" +#ifdef RDKC +#include "rdkc_rfc_xconf_handler.h" +#endif #include +#include #include #include #include +#ifdef RDKC +#include +#include +#include +#endif namespace rfc { #if defined(USE_IARMBUS) + /** + * @brief IARM event handler for RFC Manager events. + * @note Placeholder for future implementation. + */ void rfcMgrEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) { - /* This is place holder for future */ owner = owner; eventId = eventId; data = data; @@ -38,14 +53,15 @@ namespace rfc { return; } #endif + /** @brief Construct and initialise the RFC Manager (logger + IARM). */ RFCManager ::RFCManager() { #if defined(RDK_LOGGER) -#if defined(RDKB_SUPPORT) +#if defined(RDKB_SUPPORT) || defined(RDKC) RDK_LOGGER_INIT(); -#else +#else /* Initialize RDK Logger */ static char RFCMGRLOG[] = "LOG.RDK.RFCMGR"; - rdk_logger_ext_config_t config = { + rdk_logger_ext_config_t config = { .pModuleName = RFCMGRLOG, /* Module name */ .loglevel = RDK_LOG_INFO, /* Default log level */ .output = RDKLOG_OUTPUT_CONSOLE, /* Output to console (stdout/stderr) */ @@ -56,17 +72,17 @@ namespace rfc { if (rdk_logger_ext_init(&config) != RDK_SUCCESS) { printf("RFC : ERROR - Extended logger init failed\n"); } -#endif #endif +#endif + /* Initialize IARM Bus */ InitializeIARM(); } - /** Description: Check if Module is connected to IARM - * - * @param cur_event_name: event name. - * @param event_status: Status Of the event. - * @return void. + /** + * @brief Check if the IARM bus is connected. + * @retval true IARM bus is registered. + * @retval false IARM bus not available. */ bool RFCManager ::IsIarmBusConnected() { #if defined(USE_IARMBUS) @@ -128,11 +144,9 @@ namespace rfc { #endif } - /** Description: This API UnRegister IARM event handlers in order to release - * bus-facing resources. - * - * @param void - * @return 0. + /** + * @brief Unregister IARM event handlers and clean up bus resources. + * @return 0 always. */ int term_event_handler(void) { #if defined(USE_IARMBUS) @@ -145,6 +159,10 @@ namespace rfc { return 0; } + /** + * @brief Retrieve the eRouter WAN address (IPv6 preferred, IPv4 fallback). + * @return IP address string, or empty on failure. + */ std::string RFCManager::getErouterIPAddress() { std::string address; @@ -181,6 +199,11 @@ namespace rfc { return address; } + /** + * @brief Check eRouter IP availability. + * @retval true eRouter IP address obtained. + * @retval false No IP address available. + */ bool RFCManager::CheckIPConnectivity(void) { bool ip_status = false; @@ -201,12 +224,12 @@ namespace rfc { return ip_status; } - /* Description: Checking IP route address and device is online or not. - * Use IARM event provided by net service manager to check either - * device is online or not. - * @param: file_name : pointer to gateway iproute config file name - * return :true = success - * return :false = failure */ + /** + * @brief Verify IP route connectivity via a gateway config file. + * @param[in] file_name Path to the gateway IP route file. + * @retval true IP route entry found. + * @retval false File missing or no valid IP entry. + */ bool RFCManager ::CheckIProuteConnectivity(const char *file_name) { bool ip_status = false; bool string_check = false; @@ -283,10 +306,12 @@ namespace rfc { return ip_status; } - /* Description: Checking dns nameserver ip is present or not. - * @param: dns_file_name : pointer to dns config file name - * return :true = success - * return :false = failure */ + /** + * @brief Check if DNS nameserver entries are present. + * @param[in] dns_file_name Path to the DNS resolver file. + * @retval true At least one nameserver found. + * @retval false File missing or no nameserver entry. + */ bool isDnsResolve(const char *dns_file_name) { bool dns_status = false; @@ -334,7 +359,60 @@ namespace rfc { { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,"[%s][%d] Checking IP and Route configuration\n", __FUNCTION__,__LINE__); rfc::DeviceStatus result = RFCMGR_DEVICE_OFFLINE; -#if !defined(RDKB_SUPPORT) +#ifdef RDKC + /* Camera (XHC1) IP acquisition — matches waitForIpAcquisition() in + * RFCbase.sh. Poll until a non-loopback IP address appears on any + * interface. The shell loops with 10s sleep; we do the same. */ + { + char ipBuf[INET6_ADDRSTRLEN] = {0}; + while (true) + { + struct ifaddrs *ifap = nullptr; + if (getifaddrs(&ifap) == 0) + { + for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) + { + if (!ifa->ifa_addr) continue; + int family = ifa->ifa_addr->sa_family; + if (family == AF_INET) + { + struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr; + uint32_t ip = ntohl(sa->sin_addr.s_addr); + /* Skip loopback 127.x.x.x */ + if ((ip >> 24) == 127) continue; + /* Skip link-local / APIPA 169.254.x.x */ + if ((ip >> 16) == 0xA9FE) continue; + inet_ntop(AF_INET, &sa->sin_addr, ipBuf, sizeof(ipBuf)); + result = RFCMGR_DEVICE_ONLINE; + break; + } + else if (family == AF_INET6) + { + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ifa->ifa_addr; + /* Skip loopback ::1 and link-local fe80:: */ + if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) continue; + if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) continue; + inet_ntop(AF_INET6, &sa6->sin6_addr, ipBuf, sizeof(ipBuf)); + result = RFCMGR_DEVICE_ONLINE; + break; + } + } + freeifaddrs(ifap); + } + if (result == RFCMGR_DEVICE_ONLINE) + { + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC: Acquired IP address: %s\n", + __FUNCTION__, __LINE__, ipBuf); + break; + } + RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR, + "[%s][%d] RDKC: Waiting for IP address...\n", + __FUNCTION__, __LINE__); + sleep(10); + } + } +#elif !defined(RDKB_SUPPORT) && !defined(RDKC) if (true == CheckIProuteConnectivity(GATEWAYIP_FILE)) { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,"[%s][%d] Checking IP and Route configuration found\n", __FUNCTION__,__LINE__); @@ -367,11 +445,10 @@ namespace rfc { } #if !defined(RDKB_SUPPORT) - /** Description: Send event to iarm event manager - * - * @param cur_event_name: event name. - * @param main_mgr_event: Status Of the event. - * @return void. + /** + * @brief Broadcast an IARM event to the Maintenance Manager. + * @param[in] cur_event_name IARM event owner name. + * @param[in] main_mgr_event Maintenance manager event code. */ void RFCManager::SendEventToMaintenanceManager(const char *cur_event_name, unsigned int main_mgr_event) { @@ -393,6 +470,10 @@ namespace rfc { } #endif + /** + * @brief Run post-processing scripts after RFC parameters are applied. + * @return SUCCESS (0) or FAILURE (-1). + */ int RFCManager::RFCManagerPostProcess() { // Check if the script exists before executing it @@ -410,13 +491,38 @@ namespace rfc { return SUCCESS; } + /** + * @brief Core RFC fetch-and-apply logic. + * + * Creates the platform-appropriate RuntimeFeatureControlProcessor, + * initialises the Xconf handler, processes the feature-control request, + * and triggers reboot scheduling or maintenance-manager events. + * + * @return SUCCESS (0) or FAILURE (-1). + */ int RFCManager::RFCManagerProcess() { - /* Create Object for Xconf Handler */ + /* Create the appropriate RFC processor for the target platform. + * On camera (RDKC/XHC1) use the derived class that overrides + * URL building, hash/time retrieval, and endpoint metadata storage. + * All shared RFC logic is inherited from RuntimeFeatureControlProcessor. */ +#ifdef RDKC + RuntimeFeatureControlProcessor *rfcObj = new RdkcRuntimeFeatureControlProcessor(); +#else RuntimeFeatureControlProcessor *rfcObj = new RuntimeFeatureControlProcessor(); +#endif int reqStatus = FAILURE; +#ifdef RDKC + /* Camera devices wait 120 seconds before first Xconf query. + * Shell equivalent: sleep 120 (RFCbase.sh XHC1 branch) */ + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC: Waiting 120 seconds before querying xconf\n", + __FUNCTION__, __LINE__); + sleep(120); +#endif + /* Initialize xconf Hanlder */ int result = rfcObj->InitializeRuntimeFeatureControlProcessor(); if(result == FAILURE) @@ -431,6 +537,7 @@ namespace rfc { #if !defined(RDKB_SUPPORT) if(result == SUCCESS) { +#ifndef RDKC SendEventToMaintenanceManager("MaintenanceMGR", MAINT_RFC_COMPLETE); bool isRebootRequired = rfcObj->getRebootRequirement(); @@ -441,13 +548,39 @@ namespace rfc { SendEventToMaintenanceManager("MaintenanceMGR", MAINT_CRITICAL_UPDATE); SendEventToMaintenanceManager("MaintenanceMGR", MAINT_REBOOT_REQUIRED); } +#endif /* !RDKC */ reqStatus = SUCCESS; } else { +#ifndef RDKC RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,"[%s][%d] RFC: Posting RFC Error Event to MaintenanceMGR\n", __FUNCTION__,__LINE__); rfcObj->NotifyTelemetry2Count("SYST_INFO_RFC_Error"); SendEventToMaintenanceManager("MaintenanceMGR", MAINT_RFC_ERROR); +#endif /* !RDKC */ + } +#endif + +#ifdef RDKC + /* Camera reboot scheduling — equivalent to: + * if [ "$RfcRebootCronNeeded" = "1" ]; then + * sh /lib/rdk/RfcRebootCronschedule.sh & + * fi */ + if (rfcObj->getRfcRebootCronNeeded()) + { + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC: RfcRebootCronNeeded=true, scheduling reboot in maintenance window\n", + __FUNCTION__, __LINE__); + if (access("/lib/rdk/RfcRebootCronschedule.sh", F_OK) == 0) + { + v_secure_system("sh /lib/rdk/RfcRebootCronschedule.sh &"); + } + else + { + RDK_LOG(RDK_LOG_WARN, LOG_RFCMGR, + "[%s][%d] RDKC: RfcRebootCronschedule.sh not found\n", + __FUNCTION__, __LINE__); + } } #endif int post_process_result = RFCManagerPostProcess(); @@ -465,6 +598,10 @@ namespace rfc { return reqStatus; } + /** + * @brief Entry point — run the full RFC Xconf request cycle. + * @return SUCCESS (0) or FAILURE (-1). + */ int RFCManager ::RFCManagerProcessXconfRequest() { int ret_status = FAILURE; @@ -474,6 +611,15 @@ namespace rfc { return ret_status; } + /** + * @brief Configure the periodic cron job for rfcMgr execution. + * + * Parses a five-field cron string, adjusts the schedule back by + * three minutes, replaces any existing rfcMgr/RFCbase cron entry, + * and applies the new crontab. + * + * @param[in] cron Five-field cron schedule string from DCM. + */ void rfc::RFCManager::manageCronJob(const std::string& cron) { std::string tempFile = "/tmp/cron_tab_tmp_file"; @@ -528,7 +674,12 @@ namespace rfc { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Configuring cron job: %s\n", __FUNCTION__, __LINE__, adjustedCron.c_str()); +#ifdef RDKC + /* Camera cron entry omits log redirect (matches XHC1 shell behaviour) */ + std::string cronEntry = adjustedCron + " /usr/bin/rfcMgr"; +#else std::string cronEntry = adjustedCron + " /usr/bin/rfcMgr >> /rdklogs/logs/dcmrfc.log.0 2>&1"; +#endif // Export existing crontab using popen to avoid redirection issues std::string exportCmd = "crontab -l -c " + crontabPath + " 2>&1"; diff --git a/rfcMgr/rfc_manager.h b/rfcMgr/rfc_manager.h index 4a1ccd95..431870fc 100644 --- a/rfcMgr/rfc_manager.h +++ b/rfcMgr/rfc_manager.h @@ -1,4 +1,7 @@ /** + * @file rfc_manager.h + * @brief RFC Manager — orchestrates the RFC feature-control lifecycle. + * * If not stated otherwise in this file or this component's LICENSE * file the following copyright and licenses apply: * @@ -15,14 +18,13 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - **/ + */ #ifndef RFC_MGR_H #define RFC_MGR_H -/*----------------------------------------------------------------------------*/ -/* Header File */ -/*----------------------------------------------------------------------------*/ +/** @addtogroup rfcMgr + * @{ */ #include "rfc_mgr_iarm.h" #include "rfc_common.h" #include @@ -31,9 +33,8 @@ #include "maintenanceMGR.h" #endif -/*----------------------------------------------------------------------------*/ -/* Macros */ -/*----------------------------------------------------------------------------*/ +/** @name Macros + * @{ */ #define DEBUG_INI_FILE "/etc/debug.ini" #if !defined(RDKB_SUPPORT) #define OVERIDE_DEBUG_INI_FILE "/opt/debug.ini" @@ -50,25 +51,26 @@ #include #endif +/** @} */ /* end Macros */ -/*----------------------------------------------------------------------------*/ -/* Namespace */ -/*----------------------------------------------------------------------------*/ namespace rfc { -/*----------------------------------------------------------------------------*/ -/* Enum */ -/*----------------------------------------------------------------------------*/ + +/** + * @brief Device network connectivity status. + */ enum DeviceStatus { RFCMGR_DEVICE_ONLINE, RFCMGR_DEVICE_OFFLINE }; -/* Maintenance Manager Events */ -#define MAINT_RFC_ERROR 3 -#define MAINT_RFC_INPROGRESS 14 -#define MAINT_RFC_COMPLETE 2 -#define MAINT_CRITICAL_UPDATE 11 -#define MAINT_REBOOT_REQUIRED 12 +/** @name Maintenance Manager Event Codes + * @{ */ +#define MAINT_RFC_ERROR 3 /**< RFC processing encountered an error. */ +#define MAINT_RFC_INPROGRESS 14 /**< RFC processing is in progress. */ +#define MAINT_RFC_COMPLETE 2 /**< RFC processing completed successfully. */ +#define MAINT_CRITICAL_UPDATE 11 /**< A critical firmware update is available. */ +#define MAINT_REBOOT_REQUIRED 12 /**< A device reboot is required. */ +/** @} */ #if !defined(RDKB_SUPPORT) #define RFC_MGR_IPTBLE_INIT_SCRIPT "/lib/rdk/iptables_init" @@ -83,20 +85,47 @@ enum DeviceStatus { bool isDnsResolve(const char *); #endif -/*----------------------------------------------------------------------------*/ -/* Class */ -/*----------------------------------------------------------------------------*/ +/** + * @class RFCManager + * @brief Manages the Remote Feature Control (RFC) lifecycle. + * + * Coordinates device-online checks, Xconf feature queries, post-processing, + * maintenance-manager event notifications, and periodic cron scheduling. + * This class is non-copyable. + */ class RFCManager { public: + /** @brief Construct and initialise RDK Logger + IARM bus. */ RFCManager(); - // We do not allow this class to be copied !! - RFCManager(const RFCManager &) = delete; - RFCManager &operator=(const RFCManager &) = delete; + + RFCManager(const RFCManager &) = delete; /**< Copy construction disabled. */ + RFCManager &operator=(const RFCManager &) = delete; /**< Copy assignment disabled. */ + + /** + * @brief Entry point — run the full RFC Xconf request cycle. + * @return SUCCESS (0) on success, FAILURE (-1) on error. + */ int RFCManagerProcessXconfRequest(); + + /** + * @brief Check whether the device has IP connectivity. + * @return RFCMGR_DEVICE_ONLINE or RFCMGR_DEVICE_OFFLINE. + */ rfc::DeviceStatus CheckDeviceIsOnline(void); + #if !defined(RDKB_SUPPORT) + /** + * @brief Broadcast an IARM event to the Maintenance Manager. + * @param[in] cur_event_name IARM event owner name. + * @param[in] main_mgr_event Maintenance manager event code. + */ void SendEventToMaintenanceManager(const char *, unsigned int); #endif + + /** + * @brief Configure a periodic cron job for rfcMgr execution. + * @param[in] cron Five-field cron schedule string. + */ void manageCronJob(const std::string& cron); #if defined(GTEST_ENABLE) @@ -104,15 +133,17 @@ class RFCManager { #else private: #endif - void InitializeIARM(void); - bool isConnectedToInternet(); - bool CheckIProuteConnectivity(const char *); - std::string getErouterIPAddress(); - bool CheckIPConnectivity(void); - bool IsIarmBusConnected(); - int RFCManagerProcess(); - int RFCManagerPostProcess(); + void InitializeIARM(void); /**< Register on the IARM bus. */ + bool isConnectedToInternet(); /**< Quick internet-reachability probe. */ + bool CheckIProuteConnectivity(const char *); /**< Verify IP route via gateway file. */ + std::string getErouterIPAddress(); /**< Retrieve the eRouter WAN address. */ + bool CheckIPConnectivity(void); /**< Check eRouter IP availability. */ + bool IsIarmBusConnected(); /**< Query IARM connection state. */ + int RFCManagerProcess(); /**< Core RFC fetch-and-apply logic. */ + int RFCManagerPostProcess(); /**< Post-processing scripts (iptables, etc.). */ }; // end of RFCManager Class + +/** @} */ /* end rfcMgr group */ } // end of namespace RFC #endif diff --git a/rfcMgr/rfc_mgr_iarm.h b/rfcMgr/rfc_mgr_iarm.h index 0885e962..6f494d5d 100644 --- a/rfcMgr/rfc_mgr_iarm.h +++ b/rfcMgr/rfc_mgr_iarm.h @@ -1,4 +1,7 @@ /** + * @file rfc_mgr_iarm.h + * @brief IARM bus definitions and event constants for RFC Manager. + * * If not stated otherwise in this file or this component's LICENSE * file the following copyright and licenses apply: * @@ -15,7 +18,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - **/ + */ #ifndef RFC_MGR_IARM_H #define RFC_MGR_IARM_H diff --git a/rfcMgr/rfc_mgr_json.h b/rfcMgr/rfc_mgr_json.h index 5c5fb881..c59cb54b 100644 --- a/rfcMgr/rfc_mgr_json.h +++ b/rfcMgr/rfc_mgr_json.h @@ -1,34 +1,41 @@ /** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2023 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ + * @file rfc_mgr_json.h + * @brief JSON tag constants for Xconf feature-control request/response. + * + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2023 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef RFC_JSON_H #define RFC_JSON_H -/* Items inside XConf Feature Control Request JSON Object */ -#define FEATURE_CONTROL_TAG "featureControl" -#define FEATURES_TAG "features" -#define CONFIG_DATA_TAG "configData" +/** @name Xconf JSON tags + * @{ */ +#define FEATURE_CONTROL_TAG "featureControl" /**< Top-level feature control object. */ +#define FEATURES_TAG "features" /**< Array of feature entries. */ +#define CONFIG_DATA_TAG "configData" /**< Per-feature configuration data. */ +/** @} */ - -#define RFC_FEATURES_NAME_STR "name" -#define RFC_FEATURES_ENABLE_STR "enable" -#define RFC_FEATURE_INSTANCE_STR "featureInstance" -#define RFC_FEATURE_EFF_IMMD_STR "effectiveImmediate" +/** @name RFC Feature JSON keys + * @{ */ +#define RFC_FEATURES_NAME_STR "name" /**< Feature name. */ +#define RFC_FEATURES_ENABLE_STR "enable" /**< Feature enable flag. */ +#define RFC_FEATURE_INSTANCE_STR "featureInstance" /**< Feature instance identifier. */ +#define RFC_FEATURE_EFF_IMMD_STR "effectiveImmediate" /**< Effective-immediate flag. */ +/** @} */ #endif diff --git a/rfcMgr/rfc_mgr_key.h b/rfcMgr/rfc_mgr_key.h index 726bad65..d6d2dcc4 100644 --- a/rfcMgr/rfc_mgr_key.h +++ b/rfcMgr/rfc_mgr_key.h @@ -1,21 +1,24 @@ /** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2023 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ + * @file rfc_mgr_key.h + * @brief TR181 parameter-name constants used by the RFC Manager. + * + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2023 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef RFC_KEY_H #define RFC_KEY_H diff --git a/rfcMgr/rfc_xconf_handler.cpp b/rfcMgr/rfc_xconf_handler.cpp index 69138e39..59ca491f 100644 --- a/rfcMgr/rfc_xconf_handler.cpp +++ b/rfcMgr/rfc_xconf_handler.cpp @@ -1,21 +1,24 @@ -/*############################################################################## - # If not stated otherwise in this file or this component's LICENSE file the - # following copyright and licenses apply: - # - # Copyright 2024 RDK Management - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - ############################################################################## +/** + * @file rfc_xconf_handler.cpp + * @brief RuntimeFeatureControlProcessor implementation — Xconf query, JSON + * response parsing, and RFC parameter application. + * + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ @@ -24,6 +27,7 @@ #include "rfcapi.h" #include "rfc_mgr_json.h" #include +#include #include "mtlsUtils.h" #include #include @@ -85,10 +89,11 @@ int RuntimeFeatureControlProcessor:: InitializeRuntimeFeatureControlProcessor(vo { std::string rfc_file; +#ifndef RDKC int rc = GetBootstrapXconfUrl(_boot_strap_xconf_url); if(rc != 0) RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Failed to get XCONF_BS_URL from Bootstrap config.\n", __FUNCTION__, __LINE__); - +#endif if(0 != initializeXconfHandler()) { return FAILURE; @@ -874,6 +879,21 @@ void RuntimeFeatureControlProcessor::rfcCheckAccountId() void RuntimeFeatureControlProcessor::GetAccountID() { +#ifdef RDKC + /* Camera: read account ID (service number) from + * /opt/usr_config/service_number.txt. */ + { + std::ifstream ifs("/opt/usr_config/service_number.txt"); + if (ifs.is_open()) + { + std::getline(ifs, _accountId); + ifs.close(); + } + if (_accountId.empty()) + _accountId = "Unknown"; + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "GetAccountID: Camera AccountID = %s\n", _accountId.c_str()); + } +#else int i = 0; char tempbuf[1024] = {0}; int szBufSize = sizeof(tempbuf); @@ -906,6 +926,7 @@ void RuntimeFeatureControlProcessor::GetAccountID() } return; +#endif } void RuntimeFeatureControlProcessor::GetRFCPartnerID() @@ -1409,8 +1430,10 @@ void RuntimeFeatureControlProcessor::rfcStashRetrieveParams(void) WDMP_STATUS status = set_RFCProperty(std::move(name), RFC_ACCOUNT_ID_KEY_STR, stashAccountId); if (status != WDMP_SUCCESS) { -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Failed to restore AccountID: %s\n", __FUNCTION__, __LINE__, getRFCErrorString(status)); +#else + RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Failed to restore AccountID: status=%d\n", __FUNCTION__, __LINE__, status); #endif } else @@ -1448,7 +1471,7 @@ void RuntimeFeatureControlProcessor::updateHashInDB(std::string configSetHash) { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Config Set Hash = %s\n", __FUNCTION__, __LINE__, configSetHash.c_str()); -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) std::string ConfigSetHashName = "ConfigSetHash"; std::string ConfigSetHash_key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Control.ConfigSetHash"; set_RFCProperty(std::move(ConfigSetHashName), std::move(ConfigSetHash_key), configSetHash); @@ -1476,7 +1499,7 @@ void RuntimeFeatureControlProcessor::updateHashInDB(std::string configSetHash) void RuntimeFeatureControlProcessor::updateTimeInDB(std::string timestampString) { -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) std::string ConfigSetTimeName = "ConfigSetTime"; std::string ConfigSetTime_Key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Control.ConfigSetTime"; set_RFCProperty(std::move(ConfigSetTimeName), std::move(ConfigSetTime_Key), timestampString); @@ -1683,8 +1706,7 @@ int RuntimeFeatureControlProcessor::ProcessRuntimeFeatureControlReq() #endif RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] COMPLETED RFC PASS\n", __FUNCTION__, __LINE__); NotifyTelemetry2Count("SYST_INFO_RFC_Complete"); - set_RFCProperty(XCONF_SELECTOR_NAME, XCONF_SELECTOR_KEY_STR, rfcSelectOpt.c_str()); - set_RFCProperty(XCONF_URL_TR181_NAME, XCONF_URL_KEY_STR, _xconf_server_url.c_str()); + StoreXconfEndpointMetadata(); break; } @@ -1740,6 +1762,14 @@ void EncodeString(const std::string& key, const std::string& value, std::strings } } +void RuntimeFeatureControlProcessor::StoreXconfEndpointMetadata() +{ + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Storing XconfSelector=%s and XconfUrl\n", + __FUNCTION__, __LINE__, rfcSelectOpt.c_str()); + set_RFCProperty(XCONF_SELECTOR_NAME, XCONF_SELECTOR_KEY_STR, rfcSelectOpt.c_str()); + set_RFCProperty(XCONF_URL_TR181_NAME, XCONF_URL_KEY_STR, _xconf_server_url.c_str()); +} + std::stringstream RuntimeFeatureControlProcessor::CreateXconfHTTPUrl() { std::stringstream url; @@ -1834,6 +1864,11 @@ void RuntimeFeatureControlProcessor::GetStoredHashAndTime( std ::string &valueHa { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Last Image version %s and current image version %s are same \n", __FUNCTION__, __LINE__, _last_firmware.c_str(), _firmware_version.c_str()); /*Both the input strings are equal.*/ +#ifdef RDKC + /* Camera (XHC1) always retrieves hash/time from RAM files — + * it never checks XconfSelector slot. */ + RetrieveHashAndTimeFromPreviousDataSet(valueHash, valueTime); +#else if((rfc_state == Init) && (isXconfSelectorSlotProd() == false)) { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Received XconfSelector as Non Prod for RFC state as INIT \n", __FUNCTION__, __LINE__); @@ -1844,6 +1879,7 @@ void RuntimeFeatureControlProcessor::GetStoredHashAndTime( std ::string &valueHa { RetrieveHashAndTimeFromPreviousDataSet(valueHash, valueTime); } +#endif } else { @@ -2038,6 +2074,20 @@ int RuntimeFeatureControlProcessor::DownloadRuntimeFeatutres(DownloadData *pDwnL RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC Xconf Connection Response cURL Return : %d HTTP Code : %d\n",__FUNCTION__, __LINE__, curl_ret_code, httpCode); } while (rdkcertselector_setCurlStatus(thisCertSel, curl_ret_code, file_dwnl.url) == TRY_ANOTHER); +#elif defined(RDKC) + { + MtlsAuth_t sec; + memset(&sec, '\0', sizeof(MtlsAuth_t)); + int ret = getMtlscert(&sec); + if (ret == MTLS_SUCCESS) { + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RDKC mTLS creds fetched successfully\n", __FUNCTION__, __LINE__); + curl_ret_code = ExecuteRequest(&file_dwnl, &sec, &httpCode); + } else { + RDK_LOG(RDK_LOG_WARN, LOG_RFCMGR, "[%s][%d] RDKC mTLS creds not available, proceeding without mTLS\n", __FUNCTION__, __LINE__); + curl_ret_code = ExecuteRequest(&file_dwnl, NULL, &httpCode); + } + } + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC Xconf Connection Response cURL Return : %d HTTP Code : %d\n",__FUNCTION__, __LINE__, curl_ret_code, httpCode); #else RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Executing request without cert selector\n", __FUNCTION__, __LINE__); curl_ret_code = ExecuteRequest(&file_dwnl, NULL, &httpCode); @@ -2453,10 +2503,50 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Config Data Map is Empty\n", __FUNCTION__, __LINE__); return; } -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) clearDB(); #endif +#ifdef RDKC + /* Build a set of config param names whose parent feature has + * effectiveImmediate=true. Used later for camera reboot evaluation. */ + _effectiveImmediateParams.clear(); + _rfcRebootCronNeeded = false; + { + int nf = GetJsonArraySize(features); + for (int idx = 0; idx < nf; idx++) + { + JSON *feat = GetJsonArrayItem(features, idx); + if (!feat) continue; + char effImmStr[] = RFC_FEATURE_EFF_IMMD_STR; + char buf[6] = {0}; + int sz = GetJsonVal(feat, effImmStr, buf, sizeof(buf)); + if (sz && (strcasecmp(buf, "true") == 0 || strcmp(buf, "1") == 0)) + { + char cdStr[] = "configData"; + JSON *cd = GetJsonItem(feat, cdStr); + if (cd) + { + JSON *ch = cd->child; + while (ch) + { + if (ch->string) + { + std::string k = ch->string; + RemoveSubstring(k, "tr181."); + _effectiveImmediateParams.insert(k); + } + ch = ch->next; + } + } + } + } + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC: %zu params with effectiveImmediate=true\n", + __FUNCTION__, __LINE__, _effectiveImmediateParams.size()); + } +#endif + std::string newKey; std::string newValue; std::string currentValue; @@ -2478,7 +2568,7 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe } else { -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) if (newValue.empty()) { RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] EMPTY value for %s is rejected\n", __FUNCTION__, __LINE__, newKey.c_str()); @@ -2499,7 +2589,7 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe WDMP_STATUS status = set_RFCProperty(name, newKey, newValue); if (status != WDMP_SUCCESS) { -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR,"[%s][%d] SET failed for key=%s with status=%s\n", __FUNCTION__, __LINE__, newKey.c_str(), getRFCErrorString(status)); #else RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR,"[%s][%d] SET failed for key=%s with status=%d\n", __FUNCTION__, __LINE__, newKey.c_str(), status); @@ -2530,11 +2620,43 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe { NotifyTelemetry2Count("SYST_INFO_ACCID_set"); } -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) if (isMaintenanceEnabled()) { isRebootRequired = true; } +#endif +#ifdef RDKC + /* Camera reboot evaluation: + * Schedule reboot if effectiveImmediate is true for this param's + * parent feature, the device is provisioned, and the param + * is not AccountID or MD5AccountHash. */ + { + bool isEffImm = (_effectiveImmediateParams.count(newKey) > 0); + if (isEffImm) + { + char provBuf[16] = {0}; + int provRet = getDevicePropertyData("RDKC_DEVICE_PROVISION_STATUS", provBuf, sizeof(provBuf)); + bool provisioned = (provRet == 1 && strcmp(provBuf, "1") == 0); + if (provisioned) + { + std::string accountHashKey = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.MD5AccountHash"; + if (newKey != RFC_ACCOUNT_ID_KEY_STR && newKey != accountHashKey) + { + _rfcRebootCronNeeded = true; + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC: Enabling RfcRebootCronNeeded for %s old=%s new=%s\n", + __FUNCTION__, __LINE__, newKey.c_str(), currentValue.c_str(), newValue.c_str()); + } + else + { + RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, + "[%s][%d] RDKC: Skip scheduling reboot for Account Id/Hash change\n", + __FUNCTION__, __LINE__); + } + } + } + } #endif } else @@ -2549,7 +2671,7 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe } updateTR181File(TR181_FILE_LIST, paramList); -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) clearDBEnd(); #endif } @@ -2735,6 +2857,65 @@ WDMP_STATUS RuntimeFeatureControlProcessor::set_RFCProperty(std::string name, st // Close the rbus connection rbus_close(handle); + return status; +#elif defined(RDKC) + /* Camera (XHC1) writes parameters directly to the tr181store.ini + * flat file. Format: key=value (one per line) */ + (void)name; + WDMP_STATUS status = WDMP_FAILURE; + + std::string storePath = TR181STOREFILE; + std::ifstream inFile(storePath); + std::vector lines; + bool found = false; + std::string targetLine = key + "=" + value; + + if (inFile.is_open()) + { + std::string line; + while (std::getline(inFile, line)) + { + size_t eq = line.find('='); + if (eq != std::string::npos) + { + std::string existingKey = line.substr(0, eq); + if (existingKey == key) + { + lines.push_back(targetLine); + found = true; + continue; + } + } + lines.push_back(line); + } + inFile.close(); + } + + if (!found) + { + lines.push_back(targetLine); + } + + std::ofstream outFile(storePath, std::ios::trunc); + if (outFile.is_open()) + { + for (const auto &l : lines) + { + outFile << l << "\n"; + } + outFile.close(); + RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR, + "[%s][%d] RDKC: set_RFCProperty key=%s value=%s\n", + __FUNCTION__, __LINE__, key.c_str(), value.c_str()); + status = WDMP_SUCCESS; + } + else + { + RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, + "[%s][%d] RDKC: Failed to open %s for writing\n", + __FUNCTION__, __LINE__, storePath.c_str()); + } + return status; #else RFC_ParamData_t param; @@ -2808,7 +2989,11 @@ void RuntimeFeatureControlProcessor::NotifyTelemetry2RemoteFeatures(const char * if (rfcstatus == "STAGING") { v_secure_system("/usr/bin/telemetry2_0_client rfc_staging_split %s", line.c_str()); } else { +#ifndef RDKC v_secure_system("/usr/bin/telemetry2_0_client rfc_split %s", line.c_str()); +#else + RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR, "[%s][%d] RDKC: Skipping rfc_split telemetry notification\n", __FUNCTION__, __LINE__); +#endif } } diff --git a/rfcMgr/rfc_xconf_handler.h b/rfcMgr/rfc_xconf_handler.h index 9c0acfe1..90a0bd35 100644 --- a/rfcMgr/rfc_xconf_handler.h +++ b/rfcMgr/rfc_xconf_handler.h @@ -1,21 +1,24 @@ /** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2023 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ + * @file rfc_xconf_handler.h + * @brief RuntimeFeatureControlProcessor — Xconf query, JSON parsing, and RFC application. + * + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2023 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef RFC_XCONF_HANDLER_H #define RFC_XCONF_HANDLER_H @@ -25,6 +28,10 @@ #include "rfc_mgr_key.h" #include "rfc_mgr_json.h" +#ifdef RDKC +#include +#endif + #if defined(GTEST_ENABLE) #include #endif @@ -38,6 +45,10 @@ extern "C" { #include #include +#ifdef __cplusplus +} +#endif + #ifndef GTEST_ENABLE #define BOOTSTRAP_FILE "/opt/secure/RFC/bootstrap.ini" #define PARTNER_ID_FILE "/opt/www/authService/partnerId3.dat" @@ -76,71 +87,157 @@ extern "C" { #define RFC_SYNC_DONE "/tmp/.rfcSyncDone" +/** + * @brief RFC state-machine phases. + */ typedef enum { - Invalid, - Init, - Local, - Redo, - Redo_With_Valid_Data, - Finish + Invalid, /**< Not initialised. */ + Init, /**< Initial request. */ + Local, /**< Local override. */ + Redo, /**< Re-attempt needed. */ + Redo_With_Valid_Data, /**< Re-attempt with updated data. */ + Finish /**< Processing complete. */ } RfcState; -#if defined(RDKB_SUPPORT) +#if defined(RDKB_SUPPORT) || defined(RDKC) +/** + * @brief Minimal WDMP status codes for RDKB / RDKC builds. + */ typedef enum { - WDMP_SUCCESS = 0, - WDMP_FAILURE, + WDMP_SUCCESS = 0, /**< Operation succeeded. */ + WDMP_FAILURE, /**< Operation failed. */ } WDMP_STATUS; #endif +/** + * @class RuntimeFeatureControlProcessor + * @brief Queries Xconf, parses feature JSON, and applies RFC parameters. + * + * Inherits device-identity primitives from XconfHandler. On RDKC builds, + * virtual methods allow the RdkcRuntimeFeatureControlProcessor subclass + * to override URL building, hash/time storage, and endpoint metadata. + * + * Non-copyable. + */ class RuntimeFeatureControlProcessor : public xconf::XconfHandler { public : + /** @brief Construct with default state (reboot not required). */ RuntimeFeatureControlProcessor() { isRebootRequired = false; } - // We do not allow this class to be copied !! - RuntimeFeatureControlProcessor(const RuntimeFeatureControlProcessor&) = delete; +#ifdef RDKC + virtual ~RuntimeFeatureControlProcessor() = default; +#else + ~RuntimeFeatureControlProcessor() = default; +#endif + RuntimeFeatureControlProcessor(const RuntimeFeatureControlProcessor&) = delete; /**< Copy disabled. */ + /** + * @brief Initialise the RFC processor (load device identity, server URL, etc.). + * @return SUCCESS (0) or FAILURE (-1). + */ int InitializeRuntimeFeatureControlProcessor(void); + + /** + * @brief Execute the full Xconf feature-control request/response cycle. + * @return SUCCESS (0) or FAILURE (-1). + */ int ProcessRuntimeFeatureControlReq(); + + /** + * @brief Check whether an Xconf response flagged a required reboot. + * @retval true Reboot needed. + * @retval false No reboot. + */ bool getRebootRequirement(); +#ifdef RDKC + /** @brief On RDKC, query if the reboot cron job should be scheduled. */ + bool getRfcRebootCronNeeded() const { return _rfcRebootCronNeeded; } +#endif + /** @brief Send a telemetry-2 count marker. */ void NotifyTelemetry2Count(std ::string markerName); + /** @brief Send a telemetry-2 key/value marker. */ void NotifyTelemetry2Value(std ::string markerName, std ::string value); - private: +#ifdef RDKC + protected: +#else + private: +#endif + /* --------------------------------------------------------------- + * Members and methods accessible to platform-specific subclasses. + * Subclasses (e.g. RdkcRuntimeFeatureControlProcessor) override + * the virtual methods below to handle device-specific behaviour + * without duplicating the shared RFC request/response logic. + * --------------------------------------------------------------- */ + + std::string _accountId; /**< Device Account ID. */ + std::string _experience; /**< Device experience string. */ + std::string _osclass; /**< OS class identifier. */ + std::string _xconf_server_url; /**< Active Xconf server URL. */ + std::string rfcSelectOpt; /**< Xconf selector option. */ + std::string bkup_hash; /**< Backup configSetHash. */ +#ifdef RDKC + bool _rfcRebootCronNeeded = false; /**< RDKC: schedule reboot cron. */ + std::set _effectiveImmediateParams; /**< RDKC: params with effectiveImmediate=true. */ +#endif + + /** Build the full HTTP query URL sent to the Xconf server. + * Override to change device-specific query parameters. */ +#ifdef RDKC + virtual std::stringstream CreateXconfHTTPUrl(); +#else + std::stringstream CreateXconfHTTPUrl(); +#endif + + /** Read configSetHash / configSetTime from the backing store. + * Override to use a different storage medium (e.g. RAM files). */ +#ifdef RDKC + virtual void RetrieveHashAndTimeFromPreviousDataSet(std::string &valueHash, + std::string &valueTime); +#else + void RetrieveHashAndTimeFromPreviousDataSet(std::string &valueHash, + std::string &valueTime); +#endif + + /** Persist XconfSelector and XconfUrl after a successful sync. + * Override as a no-op for platforms that must not write these. */ +#ifdef RDKC + virtual void StoreXconfEndpointMetadata(); +#else + void StoreXconfEndpointMetadata(); +#endif + + private: + /** @brief Per-feature RFC object parsed from Xconf JSON. */ typedef struct RuntimeFeatureControlObject { - std::string name; - std::string featureInstance; - bool enable; - bool effectiveImmediate; + std::string name; /**< Feature name. */ + std::string featureInstance; /**< Feature instance ID. */ + bool enable; /**< Feature enable flag. */ + bool effectiveImmediate; /**< Apply without reboot. */ }RuntimeFeatureControlObject; - std::map _RFCKeyAndValueMap; - RfcState rfc_state; /* RFC State */ - std::string _last_firmware; /* Last Firmware Version */ - std::string _xconf_server_url; /* Xconf server URL */ - std::string _boot_strap_xconf_url; /* Bootstrap XConf URL */ - std::string _valid_accountId; /* Valid Account ID*/ - std::string _valid_partnerId; /* Valid Partner ID*/ - std::string _accountId; /* Device Account ID */ - std::string stashAccountId; - std::string _partnerId; /* Device Partner ID */ - std::string _bkPartnerId; /* Device Partner ID */ - std::string _accountMgmt; - std::string _serialNumber; - std::string _extendermacAddress; - std::string _experience; - std::string _osclass; - bool isRebootRequired; - std::string bkup_hash; - bool _is_first_request = false; - bool _url_validation_in_progress = false; - std::string rfcSelectOpt; - std:: string rfcSelectorSlot; + std::map _RFCKeyAndValueMap; /**< Parsed config key-value map. */ + RfcState rfc_state; /**< Current RFC state-machine phase. */ + std::string _last_firmware; /**< Last firmware version processed. */ + std::string _boot_strap_xconf_url; /**< Bootstrap Xconf URL. */ + std::string _valid_accountId; /**< Validated account ID. */ + std::string _valid_partnerId; /**< Validated partner ID. */ + std::string stashAccountId; /**< Stashed account ID for comparison. */ + std::string _partnerId; /**< Device partner ID. */ + std::string _bkPartnerId; /**< Backup partner ID. */ + std::string _accountMgmt; /**< Account management flag. */ + std::string _serialNumber; /**< Device serial number. */ + std::string _extendermacAddress; /**< Extender MAC address. */ + bool isRebootRequired; /**< True if Xconf requested reboot. */ + bool _is_first_request = false; /**< First request after FW upgrade. */ + bool _url_validation_in_progress = false; /**< URL validation in flight. */ + std:: string rfcSelectorSlot; /**< Xconf selector slot (prod/ci). */ bool checkWhoamiSupport(); bool IsNewFirmwareFirstRequest(void); @@ -149,7 +246,7 @@ class RuntimeFeatureControlProcessor : public xconf::XconfHandler void GetRFCPartnerID(); bool isMaintenanceEnabled(); void GetOsClass( void ); - void GetSerialNumber( void ); + void GetSerialNumber( void ); void GetExtenderMacAddress( void ); int GetExperience( void ); int GetServURL(const char *rfcPropertiesFile); @@ -172,9 +269,7 @@ class RuntimeFeatureControlProcessor : public xconf::XconfHandler void rfcStashRetrieveParams(void); - std::stringstream CreateXconfHTTPUrl(); void GetStoredHashAndTime( std ::string &valueHash, std::string &valueTime ); - void RetrieveHashAndTimeFromPreviousDataSet(std ::string &valueHash, std::string &valueTime); void InitDownloadData(DownloadData *pDwnData); int DownloadRuntimeFeatutres(DownloadData *pDwnLoc, DownloadData *pHeaderDwnLoc, const std::string& url_str); void NotifyTelemetry2ErrorCode(int CurlReturn); @@ -313,7 +408,4 @@ class RuntimeFeatureControlProcessor : public xconf::XconfHandler #endif }; -#ifdef __cplusplus -} -#endif #endif diff --git a/rfcMgr/xconf_handler.cpp b/rfcMgr/xconf_handler.cpp index 7d990d20..ce0f8258 100644 --- a/rfcMgr/xconf_handler.cpp +++ b/rfcMgr/xconf_handler.cpp @@ -1,25 +1,32 @@ -/*############################################################################## - # If not stated otherwise in this file or this component's LICENSE file the - # following copyright and licenses apply: - # - # Copyright 2024 RDK Management - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - ############################################################################## +/** + * @file xconf_handler.cpp + * @brief XconfHandler implementation — device identity collection and HTTP downloads. + * + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "xconf_handler.h" +#if defined(RDKC) +#include "rdk_debug.h" +#define LOG_RFCMGR "LOG.RDK.RFCMGR" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -59,6 +66,24 @@ int XconfHandler:: initializeXconfHandler() tmpbuf[sizeof(tmpbuf) - 1] = '\0'; len = strlen(tmpbuf); } +#elif defined(RDKC) + /* Camera: get MAC address via MFR API (mfrApi_test 3 9). + * This matches the shell's getEstbMacAddress() for XHC1. */ + { + FILE *fp = popen("mfrApi_test 3 9", "r"); + if (fp) + { + if (fgets(tmpbuf, sizeof(tmpbuf), fp)) + { + size_t mlen = strlen(tmpbuf); + if (mlen > 0 && tmpbuf[mlen - 1] == '\n') tmpbuf[mlen - 1] = '\0'; + len = strlen(tmpbuf); + } + pclose(fp); + } + if (len == 0) + RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Camera: mfrApi_test failed to get MAC\n", __FUNCTION__, __LINE__); + } #else len = GetEstbMac(tmpbuf, sizeof(tmpbuf)); #endif @@ -102,7 +127,7 @@ int XconfHandler:: initializeXconfHandler() { _ecm_mac_address = tmpbuf; } -#else +#elif !defined(RDKC) memset(tmpbuf, '\0', sizeof(tmpbuf)); len = GetMFRName( tmpbuf, sizeof(tmpbuf) ); if( len ) @@ -110,6 +135,25 @@ int XconfHandler:: initializeXconfHandler() _manufacturer = tmpbuf; } #endif +#ifdef RDKC + /* Camera: read partner ID from /opt/usr_config/partnerid.txt */ + { + FILE *fp = fopen("/opt/usr_config/partnerid.txt", "r"); + if (fp) + { + memset(tmpbuf, '\0', sizeof(tmpbuf)); + if (fgets(tmpbuf, sizeof(tmpbuf), fp)) + { + size_t plen = strlen(tmpbuf); + if (plen > 0 && tmpbuf[plen - 1] == '\n') tmpbuf[plen - 1] = '\0'; + _partner_id = tmpbuf; + } + fclose(fp); + } + if (_partner_id.empty()) + _partner_id = "Unknown"; + } +#else memset(tmpbuf, '\0', sizeof(tmpbuf)); len = GetPartnerId( tmpbuf, sizeof(tmpbuf) ); if( len ) @@ -118,8 +162,9 @@ int XconfHandler:: initializeXconfHandler() } else { - _partner_id="Unkown"; + _partner_id="Unknown"; } +#endif return 0; } diff --git a/rfcMgr/xconf_handler.h b/rfcMgr/xconf_handler.h index f7e52ac2..7dd753cb 100644 --- a/rfcMgr/xconf_handler.h +++ b/rfcMgr/xconf_handler.h @@ -1,21 +1,24 @@ /** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2023 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ + * @file xconf_handler.h + * @brief Base Xconf HTTP handler — device identity and download primitives. + * + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2023 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef XCONF_HANDLER_H #define XCONF_HANDLER_H @@ -34,28 +37,50 @@ extern "C" { #include namespace xconf { + + /** + * @class XconfHandler + * @brief Collects device identity (MAC, FW version, model, etc.) and + * provides an HTTP download helper for Xconf communication. + * + * Non-copyable. Derived classes (RuntimeFeatureControlProcessor and its + * platform overrides) build on these primitives. + */ class XconfHandler { public : + /** @brief Default constructor. */ XconfHandler(){ } + + /** + * @brief Populate all device-identity fields. + * @return 0 on success. + */ int initializeXconfHandler(void); - - // We do not allow this class to be copied !! - XconfHandler(const XconfHandler&) = delete; - XconfHandler& operator=(const XconfHandler&) = delete; + + XconfHandler(const XconfHandler&) = delete; /**< Copy disabled. */ + XconfHandler& operator=(const XconfHandler&) = delete; /**< Assignment disabled. */ #if defined(GTEST_ENABLE) public: #else protected : #endif - std::string _estb_mac_address; /* Device Mac Address*/ - std::string _firmware_version; /* Device Frimware version */ - BUILDTYPE _ebuild_type; /* Device Build Type */ - std::string _build_type_str; - std::string _model_number; /* Device Model Number */ - std::string _manufacturer; /* Device Manufacturer */ - std::string _ecm_mac_address; /* Cable Modem Mac Address*/ - std::string _partner_id; /* Device Partner ID */ + std::string _estb_mac_address; /**< Device eSTB MAC address. */ + std::string _firmware_version; /**< Current firmware version. */ + BUILDTYPE _ebuild_type; /**< Build type enum (DEV/VBN/PROD). */ + std::string _build_type_str; /**< Build type as a string. */ + std::string _model_number; /**< Device model number. */ + std::string _manufacturer; /**< Device manufacturer name. */ + std::string _ecm_mac_address; /**< Cable-modem MAC address. */ + std::string _partner_id; /**< Syndication partner ID. */ + + /** + * @brief Execute an HTTP file download via cURL. + * @param[in,out] file_dwnl Download descriptor (URL, output buffer). + * @param[in] security mTLS certificate bundle. + * @param[out] httpCode Resulting HTTP status code. + * @return cURL return code (0 = OK). + */ int ExecuteRequest(FileDwnl_t *file_dwnl, MtlsAuth_t *security, int *httpCode); }; } diff --git a/rfcapi/Makefile.am b/rfcapi/Makefile.am index 69d93831..4011b384 100644 --- a/rfcapi/Makefile.am +++ b/rfcapi/Makefile.am @@ -24,8 +24,13 @@ librfcapi_la_SOURCES = rfcapi.cpp librfcapi_la_includedir = $(includedir) librfcapi_la_include_HEADERS = rfcapi.h if ENABLE_RDKC -librfcapi_la_CPPFLAGS = "-std=c++11" -DLINUX -fPIC -g -O2 -Wall -DRDKC -I${top_srcdir}/../rdklogger/include/ -librfcapi_la_LIBADD = -L${top_srcdir}/../rdklogger/src/.libs -lrdkloggers +if ENABLE_XCAM2 +librfcapi_la_CPPFLAGS = "-std=c++11" -DLINUX -fPIC -g -O2 -Wall -DRDKC -I${RDK_FSROOT_PATH}/usr/include/ +librfcapi_la_LIBADD = -L${RDK_FSROOT_PATH}/usr/lib/ -lrdkloggers +else +librfcapi_la_CPPFLAGS = "-std=c++11" -DLINUX -fPIC -g -O2 -Wall -DRDKC -I${STAGING_DIR_TARGET}/usr/include/ +librfcapi_la_LIBADD = -L${STAGING_DIR_TARGET}/usr/lib/ -lrdkloggers +endif else librfcapi_la_CPPFLAGS = "-std=c++11" -DLINUX -fPIC -g -O2 -Wall -I=/usr/include/cjson -I=/usr/include/wdmp-c $(IARMBUS_EVENT_FLAG) librfcapi_la_LIBADD = -lcurl -lcjson -lrdkloggers diff --git a/rfcapi/rfcapi.cpp b/rfcapi/rfcapi.cpp index 382feaaa..ae666700 100644 --- a/rfcapi/rfcapi.cpp +++ b/rfcapi/rfcapi.cpp @@ -1,4 +1,7 @@ -/* +/** + * @file rfcapi.cpp + * @brief RFC parameter API implementation — get/set via hostif, rbus, or flat files. + * * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * @@ -15,15 +18,16 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #include #include -#ifndef RDKC +#if !defined(RDKB_SUPPORT) && !defined(RDKC) #include #include "cJSON.h" #endif #include +#include #include #include #include @@ -31,7 +35,7 @@ #include "rdk_debug.h" using namespace std; -#define LOG_RFCAPI "LOG.RDK.RFCAPI" +#define LOG_RFCAPI "LOG.RDK.RFCAPI" /**< RDK Logger module name for rfcapi. */ #define TR181_RFC_PREFIX "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC" #define BOOTSTRAP_FILE "/opt/secure/RFC/bootstrap.ini" #define RFCDEFAULTS_FILE "/tmp/rfcdefaults.ini" @@ -65,6 +69,11 @@ static string prefix() } #endif +/** + * @brief Merge per-feature rfcdefaults ini files into a single combined file. + * @retval true Merge succeeded. + * @retval false /etc/rfcdefaults/ could not be opened. + */ bool init_rfcdefaults() { DIR *dir; @@ -93,86 +102,14 @@ bool init_rfcdefaults() return true; } -#if defined(RDKC) -int getValue(const char* fileName, const char* pcParameterName, RFC_ParamData_t *pstParam) -{ - ifstream ifs_rfcVar(fileName); - if (!ifs_rfcVar.is_open()) - { - RDK_LOG (RDK_LOG_ERROR, LOG_RFCAPI, "%s: Trying to open a non-existent file %s \n", __FUNCTION__, fileName); - if ( strcmp(fileName, RFCDEFAULTS_FILE) == 0 && init_rfcdefaults() ) - { - RDK_LOG(RDK_LOG_DEBUG, LOG_RFCAPI, "Trying to open %s after newly creating\n", RFCDEFAULTS_FILE); - ifs_rfcVar.open(RFCDEFAULTS_FILE, ifstream::in); - if (!ifs_rfcVar.is_open()) - return FAILURE; - } - else - return FAILURE; - } - { - string line; - while (getline(ifs_rfcVar, line)) - { - line=line.substr(line.find_first_of(" \t")+1);//Remove any export word that maybe before the key(for rfcVariable.ini) - size_t splitterPos = line.find('='); - if (splitterPos < line.length()) - { - string key = line.substr(0, splitterPos); - if ( !key.compare(pcParameterName) ) - { - ifs_rfcVar.close(); - string value = line.substr(splitterPos+1, line.length()); - RDK_LOG(RDK_LOG_DEBUG, LOG_RFCAPI, "Found Key = %s : Value = %s\n", key.c_str(), value.c_str()); - if(value.length() > 0) - { - strncpy(pstParam->name, pcParameterName, MAX_PARAM_LEN); - pstParam->name[MAX_PARAM_LEN - 1] = '\0'; - - pstParam->type = NONE; //The caller must know what type they are expecting if they are requesting a param before the hostif is ready. - - strncpy(pstParam->value, value.c_str(), MAX_PARAM_LEN); - pstParam->value[MAX_PARAM_LEN - 1] = '\0'; - return SUCCESS; - } - return EMPTY; - } - } - } - ifs_rfcVar.close(); - } - return FAILURE; -} - -int getRFCParameter(const char* pcParameterName, RFC_ParamData_t *pstParam) -{ - int ret = FAILURE; - if(!strcmp(pcParameterName+strlen(pcParameterName)-1,".")) - { - RDK_LOG (RDK_LOG_DEBUG, LOG_RFCAPI, "%s: RFC API doesn't support wildcard parameterName\n", __FUNCTION__); - } - - if(strncmp(pcParameterName, "RFC_", 4) == 0 && strchr(pcParameterName, '.') == NULL) - { - return getValue(RFCVAR_FILE, pcParameterName, pstParam); - } - - else - { - ret = getValue(TR181STORE_FILE, pcParameterName, pstParam); - if (SUCCESS == ret) - return SUCCESS; - - // If the param is not found in override files, find it in rfcdefaults. - return getValue(RFCDEFAULTS_FILE, pcParameterName, pstParam); - - } -} -#endif - -#define FAILURE -1 -#define SUCCESS 0 - +#if !defined(RDKB_SUPPORT) && !defined(RDKC) +/** + * @brief Look up a parameter by name in an ini-style file (WDMP path). + * @param[in] fileName Path to the ini file. + * @param[in] pcParameterName Parameter name to search for. + * @param[out] pstParam Filled with name/value/type on success. + * @return WDMP_SUCCESS, WDMP_ERR_VALUE_IS_EMPTY, or WDMP_FAILURE. + */ WDMP_STATUS getValue(const char* fileName, const char* pcParameterName, RFC_ParamData_t *pstParam) { ifstream ifs_rfcVar(fileName); @@ -222,7 +159,9 @@ WDMP_STATUS getValue(const char* fileName, const char* pcParameterName, RFC_Para } return WDMP_FAILURE; } +#endif +/** @brief cURL write callback — appends received data to a std::string. */ static size_t writeCurlResponse(void *ptr, size_t size, size_t nmemb, string stream) { size_t realsize = size * nmemb; @@ -231,30 +170,14 @@ static size_t writeCurlResponse(void *ptr, size_t size, size_t nmemb, string str return realsize; } -int getRFCParameter(const char* pcParameterName, RFC_ParamData_t *pstParam) -{ - int ret = FAILURE; - if(!strcmp(pcParameterName+strlen(pcParameterName)-1,".")) - { - RDK_LOG (RDK_LOG_DEBUG, LOG_RFCAPI, "%s: RFC API doesn't support wildcard parameterName\n", __FUNCTION__); - } - - if(strncmp(pcParameterName, "RFC_", 4) == 0 && strchr(pcParameterName, '.') == NULL) - { - return getValue(RFCVAR_FILE, pcParameterName, pstParam); - } - else - { - ret = getValue(TR181STORE_FILE, pcParameterName, pstParam); - if (SUCCESS == ret) - return SUCCESS; - - // If the param is not found in override files, find it in rfcdefaults. - return getValue(RFCDEFAULTS_FILE, pcParameterName, pstParam); - - } -} - +#if !defined(RDKB_SUPPORT) && !defined(RDKC) +/** + * @brief Retrieve an RFC parameter via hostif HTTP (STB path). + * @param[in] pcCallerID Caller identifier. + * @param[in] pcParameterName TR181 parameter name. + * @param[out] pstParam Filled with name/value/type. + * @return WDMP_STATUS code. + */ WDMP_STATUS getRFCParameter(const char *pcCallerID, const char* pcParameterName, RFC_ParamData_t *pstParam) { #ifdef TEMP_LOGGING @@ -452,6 +375,14 @@ WDMP_STATUS getRFCParameter(const char *pcCallerID, const char* pcParameterName, return ret; } +/** + * @brief Set an RFC parameter via hostif HTTP. + * @param[in] pcCallerID Caller identifier. + * @param[in] pcParameterName TR181 parameter name. + * @param[in] pcParameterValue New value to set. + * @param[in] eDataType WDMP data type. + * @return WDMP_STATUS code. + */ WDMP_STATUS setRFCParameter(const char *pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType) { #ifdef TEMP_LOGGING @@ -568,10 +499,10 @@ WDMP_STATUS setRFCParameter(const char *pcCallerID, const char* pcParameterName, } /** -* Return the textual description of error code from wdmp_status -*@param [in] wdmp_status -*@param [out] textual description of error code. -*/ + * @brief Return a human-readable error string for a WDMP status code. + * @param[in] code WDMP status code. + * @return Static error description string. + */ const char * getRFCErrorString(WDMP_STATUS code) { const char * err_string; @@ -690,7 +621,105 @@ const char * getRFCErrorString(WDMP_STATUS code) } return err_string; } +#elif defined(RDKB_SUPPORT) || defined(RDKC) +/** + * @brief Look up a parameter by name in an ini-style file (int return path). + * @param[in] fileName Path to the ini file. + * @param[in] pcParameterName Parameter name to search for. + * @param[out] pstParam Filled with name/value/type on success. + * @return SUCCESS (0), EMPTY, or FAILURE. + */ +int getValue(const char* fileName, const char* pcParameterName, RFC_ParamData_t *pstParam) +{ + ifstream ifs_rfcVar(fileName); + if (!ifs_rfcVar.is_open()) + { + RDK_LOG (RDK_LOG_ERROR, LOG_RFCAPI, "%s: Trying to open a non-existent file %s \n", __FUNCTION__, fileName); + if ( strcmp(fileName, RFCDEFAULTS_FILE) == 0 && init_rfcdefaults() ) + { + RDK_LOG(RDK_LOG_DEBUG, LOG_RFCAPI, "Trying to open %s after newly creating\n", RFCDEFAULTS_FILE); + ifs_rfcVar.open(RFCDEFAULTS_FILE, ifstream::in); + if (!ifs_rfcVar.is_open()) + return FAILURE; + } + else + return FAILURE; + } + { + string line; + while (getline(ifs_rfcVar, line)) + { + line=line.substr(line.find_first_of(" \t")+1);//Remove any export word that maybe before the key(for rfcVariable.ini) + size_t splitterPos = line.find('='); + if (splitterPos < line.length()) + { + string key = line.substr(0, splitterPos); + if ( !key.compare(pcParameterName) ) + { + ifs_rfcVar.close(); + string value = line.substr(splitterPos+1, line.length()); + RDK_LOG(RDK_LOG_DEBUG, LOG_RFCAPI, "Found Key = %s : Value = %s\n", key.c_str(), value.c_str()); + if(value.length() > 0) + { + strncpy(pstParam->name, pcParameterName, MAX_PARAM_LEN); + pstParam->name[MAX_PARAM_LEN - 1] = '\0'; + pstParam->type = NONE; //The caller must know what type they are expecting if they are requesting a param before the hostif is ready. + + strncpy(pstParam->value, value.c_str(), MAX_PARAM_LEN); + pstParam->value[MAX_PARAM_LEN - 1] = '\0'; + return SUCCESS; + } + return EMPTY; + } + } + } + ifs_rfcVar.close(); + } + return FAILURE; +} + + +/** + * @brief Retrieve an RFC parameter from ini files (RDKB / RDKC path). + * @param[in] pcParameterName TR181 parameter name. + * @param[out] pstParam Filled with name/value/type. + * @return SUCCESS (0) or FAILURE. + */ +int getRFCParameter(const char* pcParameterName, RFC_ParamData_t *pstParam) +{ + int ret = FAILURE; + if(!strcmp(pcParameterName+strlen(pcParameterName)-1,".")) + { + RDK_LOG (RDK_LOG_DEBUG, LOG_RFCAPI, "%s: RFC API doesn't support wildcard parameterName\n", __FUNCTION__); + } + + if(strncmp(pcParameterName, "RFC_", 4) == 0 && strchr(pcParameterName, '.') == NULL) + { + return getValue(RFCVAR_FILE, pcParameterName, pstParam); + } + + else + { + ret = getValue(TR181STORE_FILE, pcParameterName, pstParam); + if (SUCCESS == ret) + return SUCCESS; + + // If the param is not found in override files, find it in rfcdefaults. + return getValue(RFCDEFAULTS_FILE, pcParameterName, pstParam); + + } +} + +#endif + +#if !defined(RDKB_SUPPORT) && !defined(RDKC) +/** + * @brief Check whether a named RFC feature is enabled. + * @param[in] feature Feature name (without "RFC_" prefix). + * @retval true Feature ini marker file exists. + * @retval false Feature not enabled. + */ bool isRFCEnabled(const char *feature) { struct stat buffer; @@ -699,9 +728,10 @@ bool isRFCEnabled(const char *feature) return (stat(fileName.c_str(), &buffer) == 0); } -// Define your write callback function +/** @brief Expose writeCurlResponse for unit testing. */ #ifdef GTEST_ENABLE size_t (*getWriteCurlResponse(void))(void *ptr, size_t size, size_t nmemb, std::string stream) { return &writeCurlResponse; } #endif +#endif diff --git a/rfcapi/rfcapi.h b/rfcapi/rfcapi.h index 2f5441a8..10d8cd58 100644 --- a/rfcapi/rfcapi.h +++ b/rfcapi/rfcapi.h @@ -1,4 +1,7 @@ -/* +/** + * @file rfcapi.h + * @brief Public C API for reading and writing RFC parameters. + * * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * @@ -15,7 +18,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #ifndef RFCAPI_H_ #define RFCAPI_H_ @@ -23,53 +26,109 @@ #include #include -#define RFCVAR_FILE "/opt/secure/RFC/rfcVariable.ini" -#define TR181STORE_FILE "/opt/secure/RFC/tr181store.ini" +#define RFCVAR_FILE "/opt/secure/RFC/rfcVariable.ini" /**< RFC shell-variable store. */ +#define TR181STORE_FILE "/opt/secure/RFC/tr181store.ini" /**< TR181 parameter override store. */ #ifdef __cplusplus extern "C" { #endif -#if !defined(RDKB_SUPPORT) +#if !defined(RDKB_SUPPORT) && !defined(RDKC) #include #endif -#define MAX_PARAM_LEN (2*1024) +#define MAX_PARAM_LEN (2*1024) /**< Maximum length of a parameter name or value. */ -#if defined(RDKB_SUPPORT) +#if defined(RDKB_SUPPORT) || defined(RDKC) +/** + * @brief Return-type / value-status codes (RDKB & RDKC path). + */ typedef enum { - SUCCESS=0, - FAILURE, - NONE, - EMPTY + SUCCESS=0, /**< Operation succeeded. */ + FAILURE, /**< Operation failed. */ + NONE, /**< No type information available. */ + EMPTY /**< Parameter value is empty. */ }DATA_TYPE; #endif +/** + * @struct _RFC_Param_t + * @brief Container for a single RFC parameter (name + value + type). + */ #if defined(USE_IARMBUS) typedef struct _RFC_Param_t { - char name[MAX_PARAM_LEN]; - char value[MAX_PARAM_LEN]; - DATA_TYPE type; + char name[MAX_PARAM_LEN]; /**< Parameter name. */ + char value[MAX_PARAM_LEN]; /**< Parameter value. */ + DATA_TYPE type; /**< WDMP data type. */ } RFC_ParamData_t; #else typedef struct _RFC_Param_t { - char name[MAX_PARAM_LEN]; - char value[MAX_PARAM_LEN]; - DATA_TYPE type; + char name[MAX_PARAM_LEN]; /**< Parameter name. */ + char value[MAX_PARAM_LEN]; /**< Parameter value. */ + DATA_TYPE type; /**< WDMP data type. */ } RFC_ParamData_t; #endif -#if defined(RDKB_SUPPORT) +#if defined(RDKB_SUPPORT) || defined(RDKC) +/** + * @brief Retrieve an RFC parameter value (RDKB / RDKC — int return path). + * @param[in] pcParameterName TR181 parameter name. + * @param[out] pstParamData Filled with the retrieved name/value/type. + * @return SUCCESS (0) or FAILURE (1). + */ int getRFCParameter(const char* pcParameterName, RFC_ParamData_t *pstParamData); #else +/** + * @brief Retrieve an RFC parameter value (STB — WDMP_STATUS return path). + * @param[in] pcCallerID Caller identifier string. + * @param[in] pcParameterName TR181 parameter name. + * @param[out] pstParamData Filled with the retrieved name/value/type. + * @return WDMP_STATUS code. + */ WDMP_STATUS getRFCParameter(const char *pcCallerID, const char* pcParameterName, RFC_ParamData_t *pstParamData); + +/** + * @brief Set an RFC parameter value via hostif. + * @param[in] pcCallerID Caller identifier string. + * @param[in] pcParameterName TR181 parameter name. + * @param[in] pcParameterValue New value to set. + * @param[in] eDataType WDMP data type of the value. + * @return WDMP_STATUS code. + */ WDMP_STATUS setRFCParameter(const char *pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType); + +/** + * @brief Return a human-readable error string for a WDMP status code. + * @param[in] code WDMP status code. + * @return Static error description string. + */ const char* getRFCErrorString(WDMP_STATUS code); + +/** + * @brief Check whether a named RFC feature is enabled. + * @param[in] feature Feature name (without "RFC_" prefix). + * @retval true Feature ini marker file exists. + * @retval false Feature not enabled. + */ bool isRFCEnabled(const char *); + +/** + * @brief Check whether a file exists in a given directory. + * @param[in] dir Directory path to search. + * @param[in] filename Filename to look for. + * @retval true File found. + * @retval false File not found. + */ bool isFileInDirectory(const char *, const char *); + #if defined(GTEST_ENABLE) +/** + * @brief Merge per-feature rfcdefaults ini files into a single file. + * @retval true Merge succeeded. + * @retval false /etc/rfcdefaults/ could not be opened. + */ bool init_rfcdefaults(); #endif #endif