Skip to content

Comments

[RDK-E]: NetworkconnectionRecovery.sh migration to C/C++ Module#274

Open
udaykrishnag wants to merge 13 commits intodevelopfrom
topic/RDK-59986
Open

[RDK-E]: NetworkconnectionRecovery.sh migration to C/C++ Module#274
udaykrishnag wants to merge 13 commits intodevelopfrom
topic/RDK-59986

Conversation

@udaykrishnag
Copy link

No description provided.

@udaykrishnag udaykrishnag requested a review from a team as a code owner February 10, 2026 20:26
Copilot AI review requested due to automatic review settings February 10, 2026 20:26
@github-actions
Copy link


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@rdkcmf-jenkins
Copy link
Contributor

b'## Blackduck scan failure details

Summary: 0 violations, 0 files pending approval, 1 file pending identification.

  • Protex Server Path: /home/blackduck/github/networkmanager/274/rdkcentral/networkmanager

  • Commit: 3fd5c23

Report detail: gist'

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new NetworkConnectionStats Thunder/WPEFramework module (in-process plugin + out-of-process implementation) intended to replace shell-based recovery/diagnostics with a C/C++ implementation that queries NetworkManager via COM-RPC/JSON-RPC and emits telemetry.

Changes:

  • Adds an out-of-process diagnostics implementation that periodically generates network reports and subscribes to NetworkManager events.
  • Adds two NetworkManager provider implementations (COM-RPC and JSON-RPC) plus a runtime factory selector.
  • Integrates the new networkstats/ component into the build and adds configuration/docs assets.

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 24 comments.

Show a summary per file
File Description
networkstats/plugin/ThunderJsonRPCProvider.h Declares JSON-RPC-based NetworkManager provider.
networkstats/plugin/ThunderJsonRPCProvider.cpp Implements NetworkManager JSON-RPC calls (GetIPSettings, Ping, event subscribe).
networkstats/plugin/ThunderComRPCProvider.h Declares COM-RPC-based NetworkManager provider.
networkstats/plugin/ThunderComRPCProvider.cpp Implements NetworkManager COM-RPC calls (GetIPSettings, Ping, event subscribe).
networkstats/plugin/NetworkDataProviderFactory.h Factory to select COM-RPC vs JSON-RPC provider based on config.
networkstats/plugin/NetworkConnectionStatsLogger.h Adds a lightweight logging wrapper/macros for the module.
networkstats/plugin/NetworkConnectionStatsLogger.cpp Implements stdout/RDK logger backend for logging wrapper.
networkstats/plugin/NetworkConnectionStatsImplementation.h Declares out-of-process implementation class, threading, and event handlers.
networkstats/plugin/NetworkConnectionStatsImplementation.cpp Implements periodic report generation, telemetry emission, and event-driven triggers.
networkstats/plugin/NetworkConnectionStats.h Declares in-process plugin shell that spawns/aggregates the implementation.
networkstats/plugin/NetworkConnectionStats.cpp Implements plugin lifecycle wiring and COM-RPC aggregation.
networkstats/plugin/NetworkConnectionStats.config Adds example Thunder plugin JSON configuration.
networkstats/plugin/NetworkConnectionStats.conf.in Adds config template for CMake write_config() generation.
networkstats/plugin/Module.h Adds module header wiring for Thunder build macros/includes.
networkstats/plugin/Module.cpp Adds module declaration for build reference.
networkstats/plugin/INetworkData.h Defines common interface for network data providers.
networkstats/plugin/CMakeLists.txt Builds the plugin + implementation libraries and installs config.
networkstats/interface/INetworkConnectionStats.h Defines COM-RPC interface for the out-of-process implementation.
networkstats/interface/CMakeLists.txt Generates ProxyStub library for the interface.
networkstats/definition/NetworkConnectionStats.json Adds JSON-RPC API definition/documentation (currently not wired into build).
networkstats/definition/CMakeLists.txt Adds JsonGenerator integration for docs/stubs generation.
networkstats/THUNDER_PLUGIN_QUICK_REFERENCE.md Adds quick-reference documentation for the intended architecture.
networkstats/THUNDER_PLUGIN_CONVERSION.md Adds conversion notes from standalone app to Thunder module.
networkstats/README_INTERNAL_PLUGIN.md Describes internal-only plugin behavior/configuration and telemetry outputs.
networkstats/NetworkStatsDesign_ver1.md Provides high-level design diagrams and operational flow.
networkstats/CMakeLists.txt Adds networkstats sub-project build entrypoint.
CMakeLists.txt Adds USE_TELEMETRY option and includes networkstats in the top-level build.
.DS_Store Adds an unintended macOS metadata file.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +20 to +21
#ifndef __THUNDERPROVIDER_H__
#define __THUNDERPROVIDER_H__
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The include guard macro name starts with double underscores (THUNDERPROVIDER_H), which is reserved for the implementation in C/C++. Please rename it to a non-reserved identifier (e.g., THUNDER_JSONRPC_PROVIDER_H).

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +21
#ifndef __THUNDERCOMRPCPROVIDER_H__
#define __THUNDERCOMRPCPROVIDER_H__
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The include guard macro (THUNDERCOMRPCPROVIDER_H) begins with double underscores, which are reserved identifiers in C/C++. Please rename it to a non-reserved macro to avoid undefined behavior/toolchain issues.

Copilot uses AI. Check for mistakes.
Comment on lines +186 to +191
/* @brief Get DNS server entries */
std::string NetworkJsonRPCProvider::getDnsEntries()
{
// TODO: Implement DNS entries retrieval
return "";
}
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getDnsEntries() is currently a stub that always returns an empty string. Since this provider can be selected at runtime via providerType=jsonrpc, this will lead to incorrect diagnostics when that provider is used; please implement DNS retrieval (or remove the method from the interface if it’s not needed).

Copilot uses AI. Check for mistakes.
Comment on lines +109 to +118
struct tm* lt;
const char* fileName = trimPath(file);

if (gDefaultLogLevel < level)
return;

gettimeofday(&tv, NULL);
lt = localtime(&tv.tv_sec);

printf("%.2d:%.2d:%.2d.%.6lld [%-5s] [PID=%d] [TID=%d] [%s +%d] %s : %s\n", lt->tm_hour, lt->tm_min, lt->tm_sec, (long long int)tv.tv_usec, levelMap[level], getpid(), gettid(), fileName, line, func, formattedLog);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logPrint() uses localtime(), which is not thread-safe and can cause data races/corrupted timestamps when logging from multiple threads (this plugin starts several threads). Please use localtime_r() (or gmtime_r()) with a stack-allocated tm instead.

Suggested change
struct tm* lt;
const char* fileName = trimPath(file);
if (gDefaultLogLevel < level)
return;
gettimeofday(&tv, NULL);
lt = localtime(&tv.tv_sec);
printf("%.2d:%.2d:%.2d.%.6lld [%-5s] [PID=%d] [TID=%d] [%s +%d] %s : %s\n", lt->tm_hour, lt->tm_min, lt->tm_sec, (long long int)tv.tv_usec, levelMap[level], getpid(), gettid(), fileName, line, func, formattedLog);
struct tm lt;
const char* fileName = trimPath(file);
if (gDefaultLogLevel < level)
return;
gettimeofday(&tv, NULL);
localtime_r(&tv.tv_sec, &lt);
printf("%.2d:%.2d:%.2d.%.6lld [%-5s] [PID=%d] [TID=%d] [%s +%d] %s : %s\n", lt.tm_hour, lt.tm_min, lt.tm_sec, (long long int)tv.tv_usec, levelMap[level], getpid(), gettid(), fileName, line, func, formattedLog);

Copilot uses AI. Check for mistakes.
Comment on lines +118 to +119
printf("%.2d:%.2d:%.2d.%.6lld [%-5s] [PID=%d] [TID=%d] [%s +%d] %s : %s\n", lt->tm_hour, lt->tm_min, lt->tm_sec, (long long int)tv.tv_usec, levelMap[level], getpid(), gettid(), fileName, line, func, formattedLog);
fflush(stdout);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code calls gettid(), but gettid() is not a portable/POSIX API and may be unavailable depending on libc/kernel headers, causing build failures. Consider using syscall(SYS_gettid) (since you already include <sys/syscall.h>) or conditionally compiling the TID output.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +35
#### COM-RPC Interface
- **INetworkConnectionStats.h** - Defines the COM-RPC interface with:
- INetworkConnectionStats interface with all network diagnostic methods
- INotification sub-interface for event notifications
- Proper interface IDs and stubgen annotations

#### Plugin Main Class
- **NetworkConnectionStats.h** - Plugin header with:
- Inherits from `PluginHost::IPlugin` and `PluginHost::JSONRPC`
- Notification handler for RPC connection lifecycle and events
- Interface aggregation for COM-RPC

- **NetworkConnectionStats.cpp** - Plugin implementation with:
- IPlugin lifecycle methods (Initialize, Deinitialize, Information)
- RPC connection management
- JSON-RPC registration
- Notification forwarding
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conversion document states the plugin inherits PluginHost::JSONRPC, registers JSON-RPC methods, and provides a JSON-RPC API spec. The current codebase implements an internal-only IPlugin + COM-RPC aggregate and the networkstats/definition subdir is not built. Please update the document to reflect the implemented architecture (or implement the described JSON-RPC layer).

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +8
{
"$schema": "interface.schema.json",
"jsonrpc": "2.0",
"info": {
"title": "NetworkConnectionStats API",
"class": "NetworkConnectionStats",
"description": "NetworkConnectionStats plugin for network diagnostics and monitoring"
},
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This JSON-RPC definition describes a public API surface (methods/events) that is not implemented by the current plugin (which is internal-only and does not derive from PluginHost::JSONRPC). Please either update this spec to match the implemented interfaces, or remove/disable it to avoid generating misleading documentation/stubs later.

Copilot uses AI. Check for mistakes.
#include <atomic>
#include <queue>
#include <mutex>
#include <condition_variable>
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NetworkConnectionStatsImplementation.h uses std::list (_notificationCallbacks) but does not include . Please add the missing standard header to avoid compile failures depending on indirect includes.

Suggested change
#include <condition_variable>
#include <condition_variable>
#include <list>

Copilot uses AI. Check for mistakes.
#include "INetworkData.h"
#include "Module.h"
#include <string>
#include <core/JSON.h>
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This header declares std::shared_ptr (m_networkManagerClient) but never includes . Please include here to avoid build failures due to indirect include order.

Suggested change
#include <core/JSON.h>
#include <core/JSON.h>
#include <memory>
#include <functional>

Copilot uses AI. Check for mistakes.
@rdkcmf-jenkins
Copy link
Contributor

b'## Blackduck scan failure details

Summary: 0 violations, 0 files pending approval, 1 file pending identification.

  • Protex Server Path: /home/blackduck/github/networkmanager/274/rdkcentral/networkmanager

  • Commit: 3fd5c23

Report detail: gist'

@rdkcmf-jenkins
Copy link
Contributor

b'## WARNING: A Blackduck scan failure has been waived

A prior failure has been upvoted

  • Upvote reason: OK

  • Commit: 3fd5c23
    '

@mhughesacn
Copy link

I have checked the fossid failures: There is one match to rdkcentral which is not of interest. The other two matches are from jmanc3/winbar and Karunakaran has pointed out that jmanc3 has used original code from rdkcentral (committed 17-Nov-24) which jmanc3 then committed several months later on 16-Jun-25. So the matches are a non-issue.

Copilot AI review requested due to automatic review settings February 12, 2026 15:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

option(ENABLE_LEGACY_PLUGINS "Enable Legacy Plugins" ON)
option(USE_RDK_LOGGER "Enable RDK Logger for logging" OFF )
option(ENABLE_UNIT_TESTING "Enable unit tests" OFF)
option(USE_TELEMETRY "Enable Telemetry support for NetworkConnectionStats" ON)
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This top-level option introduces USE_TELEMETRY defaulting to ON. USE_TELEMETRY is also used by other targets in this repo (e.g., tools/upnp), so this change will implicitly enable telemetry (and add a hard dependency on T2) beyond NetworkConnectionStats. Consider defaulting this option to OFF, or using a more scoped option name (e.g., NETWORKSTATS_USE_TELEMETRY) to avoid changing behavior of unrelated components.

Copilot uses AI. Check for mistakes.
Comment on lines +96 to +99

// Notification callbacks
std::list<Exchange::INetworkConnectionStats::INotification*> _notificationCallbacks;
Core::CriticalSection _notificationLock;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This header uses std::list for _notificationCallbacks but does not include <list>. Please include the required standard header directly here (avoid relying on transitive includes from Thunder headers).

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +15
│ │ - Inherits IPlugin + JSONRPC │ │
│ │ - Manages RPC connection │ │
│ │ - Forwards JSON-RPC calls │ │
│ │ - Handles notifications │ │
│ └────────────────┬───────────────────────────────────────────┘ │
│ │ COM-RPC │
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This quick reference states the plugin inherits PluginHost::JSONRPC and exposes many JSON-RPC methods/events, but the implementation in this PR is IPlugin-only and the COM-RPC interface only defines Configure/Register/Unregister. Please update this document to match the actual code (or implement the documented APIs) to avoid misleading integrators.

Suggested change
│ │ - Inherits IPlugin + JSONRPC │ │
│ │ - Manages RPC connection │ │
│ │ - Forwards JSON-RPC calls │ │
│ │ - Handles notifications │ │
│ └────────────────┬───────────────────────────────────────────┘ │
│ │ COM-RPC │
│ │ - Implements IPlugin │ │
│ │ - Manages COM-RPC connection │ │
│ │ - Uses COM-RPC to talk to implementation │ │
│ └────────────────┬───────────────────────────────────────────┘ │
│ │ COM-RPC (INetworkConnectionStats) │

Copilot uses AI. Check for mistakes.
configuration = JSON()
configuration.add("root", process)
configuration.add("reportingInterval", "@PLUGIN_NETWORKCONNECTIONSTATS_REPORTING_INTERVAL@")
configuration.add("autoStart", True)
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configuration.add("autoStart", True) doesn’t match the format used by other *.conf.in files in this repo (they use quoted strings like "true" or CMake substitutions). True is likely invalid for this config templating and may break config generation/parsing.

Suggested change
configuration.add("autoStart", True)
configuration.add("autoStart", "@PLUGIN_NETWORKCONNECTIONSTATS_AUTOSTART@")

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +58
uint32_t Register(INetworkConnectionStats::INotification* notification) override;
uint32_t Unregister(INetworkConnectionStats::INotification* notification) override;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Register/Unregister use INetworkConnectionStats::INotification* but INetworkConnectionStats is declared under WPEFramework::Exchange. As written, this won’t resolve in WPEFramework::Plugin and should be fully qualified (e.g., Exchange::INetworkConnectionStats::INotification*) to match the inherited interface.

Suggested change
uint32_t Register(INetworkConnectionStats::INotification* notification) override;
uint32_t Unregister(INetworkConnectionStats::INotification* notification) override;
uint32_t Register(Exchange::INetworkConnectionStats::INotification* notification) override;
uint32_t Unregister(Exchange::INetworkConnectionStats::INotification* notification) override;

Copilot uses AI. Check for mistakes.
Comment on lines +174 to +176
// Create network provider using factory
m_provider = NetworkDataProviderFactory::CreateProvider(providerType);
if (m_provider == nullptr) {
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configure() assigns a new object to m_provider without first cleaning up any existing provider instance (and any running threads/subscriptions tied to it). If Configure() is called more than once, this will leak and can leave multiple background threads running. Clean up the previous state before replacing m_provider.

Copilot uses AI. Check for mistakes.

#include "Module.h"

MODULE_NAME_DECLARATION(BUILD_REFERENCE)
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MODULE_NAME_DECLARATION(BUILD_REFERENCE) looks inconsistent with the rest of this repo, which uses PLUGIN_BUILD_REFERENCE (and this module’s CMake defines -DPLUGIN_BUILD_REFERENCE=...). If BUILD_REFERENCE isn’t defined, this will fail to compile or embed the wrong build reference.

Suggested change
MODULE_NAME_DECLARATION(BUILD_REFERENCE)
MODULE_NAME_DECLARATION(PLUGIN_BUILD_REFERENCE)

Copilot uses AI. Check for mistakes.
/* Test main function to validate NetworkJsonRPCProvider member functions */
int main()
{
NetworkJsonRPCProvider provider;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON-RPC provider test main() constructs NetworkJsonRPCProvider but never calls Initialize(). As a result, the menu actions will hit "client not initialized" and return empty/false. Call provider.Initialize() once before entering the menu (as done in the COM-RPC provider test).

Suggested change
NetworkJsonRPCProvider provider;
NetworkJsonRPCProvider provider;
uint32_t initResult = provider.Initialize();
if (initResult != WPEFramework::Core::ERROR_NONE) {
std::cerr << "Failed to initialize NetworkJsonRPCProvider, error code: " << initResult << std::endl;
return 1;
}

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 18, 2026 14:55
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated 15 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* @param interface_name Interface name (e.g., eth0, wlan0)
* @return IPv4 address string
*/
std::string getIpv4Address(std::string interface_name) override;
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String parameters should be passed by const reference to avoid unnecessary copies. Change std::string interface_name to const std::string& interface_name.

Copilot uses AI. Check for mistakes.
int choice;
std::string interface_name;
bool running = true;

Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Initialize method should be called before using the provider in the test main function. Add a check and call to provider.Initialize() before running tests to ensure proper initialization.

Suggested change
const uint32_t initResult = provider.Initialize();
if (initResult != WPEFramework::Core::ERROR_NONE) {
std::cerr << "Failed to initialize NetworkJsonRPCProvider, error code: " << initResult << std::endl;
return -1;
}

Copilot uses AI. Check for mistakes.
if (result.HasLabel("success")) {
bool success = result["success"].Boolean();

// Extract ping statistics
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment mismatch: The comment says "Extract ping statistics" but the immediately following code checks the "success" field which is a Boolean status, not statistics. The actual statistics extraction happens later. Consider updating the comment to accurately reflect the code structure.

Suggested change
// Extract ping statistics
// Process ping result status and statistics

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +373
/**
* If not stated otherwise in this file or this component's LICENSE
* file the following copyright and licenses apply:
*
* Copyright 2025 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 "ThunderComRPCProvider.h"
#include "NetworkConnectionStatsLogger.h"
#include <cstring>

using namespace std;
using namespace NetworkConnectionStatsLogger;

/* @brief Constructor */
NetworkComRPCProvider::NetworkComRPCProvider()
: m_networkManagerClient(nullptr)
{
NSLOG_INFO("NetworkComRPCProvider constructed");
}

/* @brief Destructor */
NetworkComRPCProvider::~NetworkComRPCProvider()
{
m_networkManagerClient.reset();
}

/* @brief Initialize the provider with Thunder COM-RPC connection */
bool NetworkComRPCProvider::Initialize()
{
try {
NSLOG_INFO("Creating JSON-RPC client for callsign: %s over COM-RPC", NETWORK_MANAGER_CALLSIGN);

// For COM-RPC, don't set THUNDER_ACCESS - let it use the default connection
// The plugin framework handles the routing automatically
m_networkManagerClient = std::make_shared<WPEFramework::JSONRPC::LinkType<WPEFramework::Core::JSON::IElement>>(
_T(NETWORK_MANAGER_CALLSIGN)
);

if (m_networkManagerClient) {
NSLOG_INFO("NetworkManager COM-RPC client initialized successfully");
return true;
} else {
NSLOG_ERROR("Failed to create NetworkManager COM-RPC client");
return false;
}
}
catch (const std::exception& e) {
NSLOG_ERROR("Exception during initialization: %s", e.what());
return false;
}
}

/* @brief Retrieve IPv4 address for specified interface */
std::string NetworkComRPCProvider::getIpv4Address(std::string interface_name)
{
std::string ipv4_address = "";

// Initialize member variables
m_ipv4Gateway = "";
m_ipv4PrimaryDns = "";

if (!m_networkManagerClient) {
NSLOG_ERROR("NetworkManager client not initialized");
return "";
}

WPEFramework::Core::JSON::VariantContainer params;
params["interface"] = interface_name;
params["ipversion"] = "IPv4";

WPEFramework::Core::JSON::VariantContainer result;

uint32_t rc = m_networkManagerClient->Invoke<WPEFramework::Core::JSON::VariantContainer, WPEFramework::Core::JSON::VariantContainer>(
5000, "GetIPSettings", params, result);

if (rc == WPEFramework::Core::ERROR_NONE) {
if (result.HasLabel("ipaddress")) {
ipv4_address = result["ipaddress"].String();
NSLOG_INFO("IPv4 address retrieved: %s", ipv4_address.c_str());
}
if (result.HasLabel("gateway")) {
m_ipv4Gateway = result["gateway"].String();
NSLOG_INFO("IPv4 Route: %s", m_ipv4Gateway.c_str());
}
if (result.HasLabel("primarydns")) {
m_ipv4PrimaryDns = result["primarydns"].String();
NSLOG_INFO("DNS entry: %s", m_ipv4PrimaryDns.c_str());
}
} else {
NSLOG_ERROR("GetIPSettings COM-RPC call failed with error code: %u", rc);
}

return ipv4_address;
}

/* @brief Retrieve IPv6 address for specified interface */
std::string NetworkComRPCProvider::getIpv6Address(std::string interface_name)
{
std::string ipv6_address = "";

// Initialize member variables
m_ipv6Gateway = "";
m_ipv6PrimaryDns = "";

if (!m_networkManagerClient) {
NSLOG_ERROR("NetworkManager client not initialized");
return "";
}

WPEFramework::Core::JSON::VariantContainer params;
params["interface"] = interface_name;
params["ipversion"] = "IPv6";

WPEFramework::Core::JSON::VariantContainer result;

uint32_t rc = m_networkManagerClient->Invoke<WPEFramework::Core::JSON::VariantContainer, WPEFramework::Core::JSON::VariantContainer>(
5000, "GetIPSettings", params, result);

if (rc == WPEFramework::Core::ERROR_NONE) {
if (result.HasLabel("ipaddress")) {
ipv6_address = result["ipaddress"].String();
NSLOG_INFO("IPv6 address retrieved: %s", ipv6_address.c_str());
}
if (result.HasLabel("gateway")) {
m_ipv6Gateway = result["gateway"].String();
NSLOG_INFO("IPv6 Route: %s", m_ipv6Gateway.c_str());
}
if (result.HasLabel("primarydns")) {
m_ipv6PrimaryDns = result["primarydns"].String();
NSLOG_INFO("DNS entry: %s", m_ipv6PrimaryDns.c_str());
}
} else {
NSLOG_ERROR("GetIPSettings COM-RPC call failed with error code: %u", rc);
}

return ipv6_address;
}

/* @brief Get current network connection type */
std::string NetworkComRPCProvider::getConnectionType()
{
std::string interface = getInterface();

if (interface.empty()) {
NSLOG_ERROR("Error: Unable to retrieve interface");
return "";
}

std::string connectionType;

// Check if interface starts with "eth" or "eno"
if (interface.find("eth") == 0 || interface.find("eno") == 0) {
connectionType = "Ethernet";
NSLOG_INFO("Connection type: %s (interface: %s)", connectionType.c_str(), interface.c_str());
}
// Check if interface starts with "wlan"
else if (interface.find("wlan") == 0) {
connectionType = "WiFi";
NSLOG_INFO("Connection type: %s (interface: %s)", connectionType.c_str(), interface.c_str());
}
else {
connectionType = "Unknown";
NSLOG_INFO("Connection type: %s (interface: %s)", connectionType.c_str(), interface.c_str());
}

return connectionType;
}

/* @brief Get DNS server entries */
std::string NetworkComRPCProvider::getDnsEntries()
{
// Return combined DNS entries from IPv4 and IPv6
std::string dnsEntries = "";

if (!m_ipv4PrimaryDns.empty()) {
dnsEntries += m_ipv4PrimaryDns;
}

if (!m_ipv6PrimaryDns.empty()) {
if (!dnsEntries.empty()) {
dnsEntries += ",";
}
dnsEntries += m_ipv6PrimaryDns;
}

return dnsEntries;
}

/* @brief Populate network interface data */
void NetworkComRPCProvider::populateNetworkData()
{
std::string interface = getInterface();

if (!interface.empty()) {
getIpv4Address(interface);
getIpv6Address(interface);
NSLOG_INFO("Network data populated for interface: %s", interface.c_str());
}
}

/* @brief Get current active interface name */
std::string NetworkComRPCProvider::getInterface()
{
if (!m_networkManagerClient) {
NSLOG_ERROR("NetworkManager client not initialized");
return "";
}

WPEFramework::Core::JSON::VariantContainer params;
WPEFramework::Core::JSON::VariantContainer result;

uint32_t rc = m_networkManagerClient->Invoke<WPEFramework::Core::JSON::VariantContainer, WPEFramework::Core::JSON::VariantContainer>(
5000, "GetPrimaryInterface", params, result);

std::string interface = "";
if (rc == WPEFramework::Core::ERROR_NONE) {
if (result.HasLabel("interface")) {
interface = result["interface"].String();
NSLOG_INFO("Primary interface retrieved: %s", interface.c_str());
}
} else {
NSLOG_ERROR("GetPrimaryInterface COM-RPC call failed with error code: %u", rc);
}

return interface;
}

/* @brief Ping to gateway to check packet loss */
bool NetworkComRPCProvider::pingToGatewayCheck(std::string endpoint, std::string ipversion, int count, int timeout)
{
// Initialize member variables
m_packetLoss = "";
m_avgRtt = "";

if (!m_networkManagerClient) {
NSLOG_ERROR("NetworkManager client not initialized");
return false;
}

WPEFramework::Core::JSON::VariantContainer params;
params["endpoint"] = endpoint;
params["ipversion"] = ipversion;
params["count"] = count;
params["timeout"] = timeout;
params["guid"] = "network-stats-ping";

WPEFramework::Core::JSON::VariantContainer result;

uint32_t rc = m_networkManagerClient->Invoke<WPEFramework::Core::JSON::VariantContainer, WPEFramework::Core::JSON::VariantContainer>(
30000, "Ping", params, result);

if (rc != WPEFramework::Core::ERROR_NONE) {
NSLOG_ERROR("Ping COM-RPC call failed with error code: %u", rc);
return false;
}

NSLOG_INFO("Ping request sent to %s (%s)", endpoint.c_str(), ipversion.c_str());

// Check if ping was successful
if (result.HasLabel("success")) {
bool success = result["success"].Boolean();

// Extract ping statistics
if (result.HasLabel("packetsTransmitted")) {
NSLOG_INFO("Packets transmitted: %d", static_cast<int>(result["packetsTransmitted"].Number()));
}
if (result.HasLabel("packetsReceived")) {
NSLOG_INFO("Packets received: %d", static_cast<int>(result["packetsReceived"].Number()));
}
if (result.HasLabel("packetLoss")) {
m_packetLoss = result["packetLoss"].String();
NSLOG_INFO("Packet loss: %s", m_packetLoss.c_str());
}
if (result.HasLabel("tripMin")) {
NSLOG_INFO("RTT min: %s ms", result["tripMin"].String().c_str());
}
if (result.HasLabel("tripAvg")) {
m_avgRtt = result["tripAvg"].String();
NSLOG_INFO("RTT avg: %s ms", m_avgRtt.c_str());
}
if (result.HasLabel("tripMax")) {
NSLOG_INFO("RTT max: %s ms", result["tripMax"].String().c_str());
}

return success;
}
else {
NSLOG_ERROR("Error: 'success' field not found in response");
return false;
}
}

/* @brief Get IPv4 gateway/route address from last getIpv4Address call */
std::string NetworkComRPCProvider::getIpv4Gateway()
{
return m_ipv4Gateway;
}

/* @brief Get IPv6 gateway/route address from last getIpv6Address call */
std::string NetworkComRPCProvider::getIpv6Gateway()
{
return m_ipv6Gateway;
}

/* @brief Get IPv4 primary DNS from last getIpv4Address call */
std::string NetworkComRPCProvider::getIpv4PrimaryDns()
{
return m_ipv4PrimaryDns;
}

/* @brief Get IPv6 primary DNS from last getIpv6Address call */
std::string NetworkComRPCProvider::getIpv6PrimaryDns()
{
return m_ipv6PrimaryDns;
}

/* @brief Get packet loss from last ping call */
std::string NetworkComRPCProvider::getPacketLoss()
{
return m_packetLoss;
}

/* @brief Get average RTT from last ping call */
std::string NetworkComRPCProvider::getAvgRtt()
{
return m_avgRtt;
}

/* @brief Subscribe to NetworkManager events */
uint32_t NetworkComRPCProvider::SubscribeToEvent(const std::string& eventName,
std::function<void(const WPEFramework::Core::JSON::VariantContainer&)> callback)
{
if (!m_networkManagerClient) {
NSLOG_ERROR("NetworkManager client not initialized");
return WPEFramework::Core::ERROR_UNAVAILABLE;
}

try {
// Subscribe to the event using Thunder's Subscribe API
// Note: The callback will be invoked when the event is received
uint32_t result = m_networkManagerClient->Subscribe<WPEFramework::Core::JSON::VariantContainer>(
5000, // timeout in milliseconds
eventName,
[callback](const WPEFramework::Core::JSON::VariantContainer& parameters) {
callback(parameters);
}
);

if (result == WPEFramework::Core::ERROR_NONE) {
NSLOG_INFO("Successfully subscribed to event: %s", eventName.c_str());
} else {
NSLOG_ERROR("Failed to subscribe to event %s, error code: %u", eventName.c_str(), result);
}

return result;
} catch (const std::exception& e) {
NSLOG_ERROR("Exception subscribing to event %s: %s", eventName.c_str(), e.what());
return WPEFramework::Core::ERROR_GENERAL;
}
}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication: ThunderJsonRPCProvider and ThunderComRPCProvider have nearly identical implementations for all methods except the client initialization. Consider creating a base class or using a template pattern to reduce duplication. The getIpv4Address, getIpv6Address, getConnectionType, getInterface, pingToGatewayCheck, and other methods are duplicated between the two files with only minor differences in the client type.

Copilot uses AI. Check for mistakes.

uint32_t NetworkConnectionStatsImplementation::Configure(const string configLine)
{
NSLOG_INFO("NetworkConnectionStatsImplementation::Configure");
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling: If m_provider is deleted due to initialization failure but Configure() is called again (which shouldn't happen but could in error scenarios), m_provider will be nullptr and any subsequent access will cause crashes. Consider adding a check at the beginning of Configure() to prevent re-configuration or handle the re-initialization case properly.

Suggested change
NSLOG_INFO("NetworkConnectionStatsImplementation::Configure");
NSLOG_INFO("NetworkConnectionStatsImplementation::Configure");
// Ensure provider is available before proceeding. If this occurs,
// it likely indicates an earlier initialization failure or misuse.
if (m_provider == nullptr) {
NSLOG_ERROR("Configure called while provider is not initialized (m_provider is nullptr)");
return Core::ERROR_GENERAL;
}

Copilot uses AI. Check for mistakes.
if (result.HasLabel("success")) {
bool success = result["success"].Boolean();

// Extract ping statistics from JSON
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment mismatch: The comment says "Extract ping statistics from JSON" but the field being accessed is "success" which is a Boolean, not statistics. Consider updating the comment to accurately reflect the code flow.

Suggested change
// Extract ping statistics from JSON
// Retrieve ping result status and statistics from JSON response

Copilot uses AI. Check for mistakes.
std::cout << "Primary DNS: " << (primaryDns.empty() ? "(empty)" : primaryDns) << "\n";
}

std::cout << "\n[Test 6/7] getIpv6Address()\n";
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test count mismatch: The text says "Test 6/7" but there are only 6 tests shown (getInterface, getIpv4Address, getIpv6Address, getConnectionType, getDnsEntries, populateNetworkData, pingToGatewayCheck). Either the label should be "Test 6/7" or the comment should reflect the actual number of tests.

Suggested change
std::cout << "\n[Test 6/7] getIpv6Address()\n";
std::cout << "\n[Test 6/6] getIpv6Address()\n";

Copilot uses AI. Check for mistakes.
{
try {
// Set Thunder access point
WPEFramework::Core::SystemInfo::SetEnvironment(_T("THUNDER_ACCESS"), _T("127.0.0.1:9998"));
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security concern: The THUNDER_ACCESS environment variable is hardcoded to "127.0.0.1:9998". If this plugin runs in an environment where Thunder is bound to a different address or port, or if the environment variable is already set, this could cause connection failures or unexpected behavior. Consider making this configurable through the plugin configuration or checking if the environment variable is already set before overwriting it.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +98
std::string getIpv4Address(std::string interface_name) override;

/* @brief Retrieve IPv6 address for specified interface
* @param interface_name Interface name (e.g., eth0, wlan0)
* @return IPv6 address string
*/
std::string getIpv6Address(std::string interface_name) override;

/* @brief Get IPv4 gateway/route address from last getIpv4Address call */
std::string getIpv4Gateway() override;

/* @brief Get IPv6 gateway/route address from last getIpv6Address call */
std::string getIpv6Gateway() override;

/* @brief Get IPv4 primary DNS from last getIpv4Address call */
std::string getIpv4PrimaryDns() override;

/* @brief Get IPv6 primary DNS from last getIpv6Address call */
std::string getIpv6PrimaryDns() override;

/* @brief Get current network connection type */
std::string getConnectionType() override;

/* @brief Get DNS server entries */
std::string getDnsEntries() override;

/* @brief Populate network interface data */
void populateNetworkData() override;

/* @brief Get current active interface name */
std::string getInterface() override;

/* @brief Ping to gateway to check packet loss
* @param endpoint Gateway IP address to ping
* @param ipversion Either "IPv4" or "IPv6"
* @param count Number of ping packets to send
* @param timeout Timeout in seconds
* @return true if ping successful, false otherwise
*/
bool pingToGatewayCheck(std::string endpoint, std::string ipversion, int count, int timeout) override;

/* @brief Get packet loss from last ping call */
std::string getPacketLoss() override;

/* @brief Get average RTT from last ping call */
std::string getAvgRtt() override;

/* @brief Subscribe to NetworkManager events
* @param eventName Name of the event (e.g., "onInterfaceStateChange")
* @param callback Callback function to be called when event fires
* @return Error code (Core::ERROR_NONE on success)
*/
uint32_t SubscribeToEvent(const std::string& eventName,
std::function<void(const WPEFramework::Core::JSON::VariantContainer&)> callback) override;
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String parameters should be passed by const reference to avoid unnecessary copies. Change all std::string parameters to const std::string& throughout the interface methods.

Copilot uses AI. Check for mistakes.
Comment on lines +208 to +211
// Clean up the partially initialized provider to prevent leaks and later accidental use
delete m_provider;
m_provider = nullptr;
result = Core::ERROR_GENERAL;
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential memory leak: When initialization fails (lines 176-177 and 209-211), m_provider is deleted but not set to nullptr. If Configure is called again or if other methods check m_provider before deletion in the destructor, this could cause use-after-free or double-free issues. After deleting m_provider, set it to nullptr.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants