diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f777c83..b6d09fde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ include(CmakeHelperFunctions) option(USE_RDK_LOGGER "Enable RDK Logger for logging" OFF ) option(ENABLE_UNIT_TESTING "Enable unit tests" OFF) - +option(USE_TELEMETRY "Enable telemetry" ON ) string(TOLOWER ${NAMESPACE} STORAGE_DIRECTORY) get_directory_property(SEVICES_DEFINES COMPILE_DEFINITIONS) @@ -62,6 +62,10 @@ pkg_check_modules(GLIB REQUIRED glib-2.0) pkg_check_modules(LIBNM REQUIRED libnm) pkg_check_modules(GLIB REQUIRED gio-2.0) else() +pkg_check_modules(LIBSOUP REQUIRED libsoup-2.4) +pkg_check_modules(GLIB REQUIRED glib-2.0) +pkg_check_modules(GUPNP REQUIRED gupnp-1.0) +pkg_check_modules(GSSDP REQUIRED gssdp-1.2) find_package(IARMBus REQUIRED) endif () @@ -96,6 +100,12 @@ if (USE_RDK_LOGGER) include_directories(${RDKLOGGER_INCLUDE_DIRS}) endif (USE_RDK_LOGGER) +if (USE_TELEMETRY) + find_package(telemetry_msgsender REQUIRED) + add_definitions(-DUSE_TELEMETRY) + include_directories(${TELEMETRY_INCLUDE_DIRS}) +endif (USE_TELEMETRY) + include_directories(${PROJECT_SOURCE_DIR}) # Build the main plugin that runs inside the WPEFramework daemon add_library(${MODULE_NAME} SHARED @@ -107,7 +117,10 @@ add_library(${MODULE_NAME} SHARED NetworkManagerStunClient.cpp WiFiSignalStrengthMonitor.cpp Module.cpp + UpnpDiscoveryManager.cpp ${PROXY_STUB_SOURCES}) + target_include_directories(${MODULE_NAME} PRIVATE ${GLIB_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} ${GUPNP_INCLUDE_DIRS} ${GSSDP_INCLUDE_DIRS}) + target_link_libraries(${MODULE_NAME} PRIVATE ${GLIB_LIBRARIES} ${LIBSOUP_LIBRARIES} ${GUPNP_LIBRARIES} ${GSSDP_LIBRARIES}) target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Core::${NAMESPACE}Core @@ -118,7 +131,10 @@ set_target_properties(${MODULE_NAME} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES FRAMEWORK FALSE) - + +if (USE_TELEMETRY) + target_link_libraries(${MODULE_NAME} PRIVATE ${TELEMETRY_LIBRARIES}) +endif (USE_TELEMETRY) if(ENABLE_GNOME_NETWORKMANAGER) if(ENABLE_GNOME_GDBUS) @@ -206,4 +222,3 @@ write_config(PLUGINS LegacyPlugin_WiFiManagerAPIs CLASSNAME WiFiManager LOCATOR if(ENABLE_UNIT_TESTING) include(Tests/unit_test/unit_tests.cmake) endif(ENABLE_UNIT_TESTING) - diff --git a/NetworkManagerImplementation.cpp b/NetworkManagerImplementation.cpp index fc1bfda8..412e4314 100644 --- a/NetworkManagerImplementation.cpp +++ b/NetworkManagerImplementation.cpp @@ -582,6 +582,12 @@ namespace WPEFramework if(Exchange::INetworkManager::INTERFACE_LINK_UP == state && interface == "eth0") m_ethConnected = true; + if ((interface == "eth0") || (interface == "wlan0")) + { + NMLOG_ERROR("MYTEST Calling NotifyInterfaceStateChangeEvent"); + m_upnpDiscoveryManager.NotifyInterfaceStateChangeEvent(); + } + _notificationLock.Lock(); NMLOG_INFO("Posting onInterfaceChange %s - %u", interface.c_str(), (unsigned)state); for (const auto callback : _notificationCallbacks) { @@ -627,6 +633,9 @@ namespace WPEFramework m_defaultInterface = interface; connectivityMonitor.switchToInitialCheck(); + + NMLOG_ERROR("MYTEST Calling NotifyIpAcquiredEvent"); + m_upnpDiscoveryManager.NotifyIpAcquiredEvent(interface); } _notificationLock.Lock(); diff --git a/NetworkManagerImplementation.h b/NetworkManagerImplementation.h index 16fd2f79..dccbb612 100644 --- a/NetworkManagerImplementation.h +++ b/NetworkManagerImplementation.h @@ -34,6 +34,7 @@ using namespace std; #include "WiFiSignalStrengthMonitor.h" #include "NetworkManagerConnectivity.h" #include "NetworkManagerStunClient.h" +#include "UpnpDiscoveryManager.h" namespace WPEFramework { @@ -276,6 +277,7 @@ namespace WPEFramework std::atomic m_ethConnected; std::atomic m_wlanConnected; WiFiSignalStrengthMonitor m_wifiSignalMonitor; + UpnpDiscoveryManager m_upnpDiscoveryManager; mutable ConnectivityMonitor connectivityMonitor; }; } diff --git a/NetworkManagerRDKProxy.cpp b/NetworkManagerRDKProxy.cpp index 890d8543..631354bc 100644 --- a/NetworkManagerRDKProxy.cpp +++ b/NetworkManagerRDKProxy.cpp @@ -545,9 +545,9 @@ namespace WPEFramework oldInterface = e->oldInterface; newInterface = e->newInterface; NMLOG_INFO ("IARM_BUS_NETWORK_MANAGER_EVENT_DEFAULT_INTERFACE %s :: %s..", oldInterface.c_str(), newInterface.c_str()); - if(oldInterface != "eth0" || oldInterface != "wlan0") + if(oldInterface != "eth0" && oldInterface != "wlan0") oldInterface = ""; /* assigning "null" if the interface is not eth0 or wlan0 */ - if(newInterface != "eth0" || newInterface != "wlan0") + if(newInterface != "eth0" && newInterface != "wlan0") newInterface = ""; /* assigning "null" if the interface is not eth0 or wlan0 */ ::_instance->ReportActiveInterfaceChange(oldInterface, newInterface); diff --git a/UpnpDiscoveryManager.cpp b/UpnpDiscoveryManager.cpp new file mode 100644 index 00000000..1ce7438f --- /dev/null +++ b/UpnpDiscoveryManager.cpp @@ -0,0 +1,210 @@ +/** +* 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. +**/ + +#include +#include +#include +#include "UpnpDiscoveryManager.h" + +std::string const UpnpDiscoveryManager::m_deviceInternetGateway = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"; + +UpnpDiscoveryManager::UpnpDiscoveryManager() +{ + m_context = NULL; + m_controlPoint = NULL; + m_mainLoop = NULL; + + m_mainLoop = g_main_loop_new(NULL, FALSE); + +#if USE_TELEMETRY + // Initialize Telemtry + t2_init("networkmanager-plugin"); +#endif + + //Timer thread to handle telemetry logging + g_timeout_add_seconds (LOGGING_PERIOD_IN_SEC, GSourceFunc(&UpnpDiscoveryManager::logTelemetry), this); + + m_threadUpnp = g_thread_new("thread_upnp", UpnpDiscoveryManager::runUpnp, this); + m_threadGmain = g_thread_new("thread_gmain", UpnpDiscoveryManager::runMainLoop, this); +} + +UpnpDiscoveryManager::~UpnpDiscoveryManager() +{ + if (m_controlPoint) + g_object_unref(m_controlPoint); + if (m_context) + g_object_unref(m_context); + if (m_mainLoop) + { + g_main_loop_quit(m_mainLoop); + g_main_loop_unref(m_mainLoop); + } +} + +void UpnpDiscoveryManager::NotifyInterfaceStateChangeEvent() +{ + // Clear the upnp running status if there is any interface state change + std::lock_guard lock(m_upnpStatusMutex); + m_upnpRunStatus = false; +} + +void UpnpDiscoveryManager::NotifyIpAcquiredEvent(const std::string& interface) +{ + std::lock_guard lock(m_upnpStatusMutex); + // Once IP is acquired, notify upnp thread to start discovery + if (m_upnpRunStatus == false) + { + m_upnpRunStatus = true; + m_interface = interface; + m_upnpCv.notify_one(); + } +} + +void* UpnpDiscoveryManager::runUpnp(void *arg) +{ + UpnpDiscoveryManager* manager = static_cast(arg); + while(true) + { + std::unique_lock lock(manager->m_upnpCvMutex); + manager->m_upnpCv.wait(lock); + if (true == manager->m_upnpRunStatus) + { + manager->findGatewayDevice(manager->m_interface); + } + } +} + +gboolean UpnpDiscoveryManager::initialiseUpnp(const std::string& interface) +{ + GError *error = NULL; + uint8_t count = 0; + + do + { + // Create a gupnp context + m_context = gupnp_context_new(NULL, interface.c_str(), 0, &error); + if (!m_context) + { + LOG_ERR("Error creating Upnp context: %s", error->message); + g_clear_error(&error); + count++; + sleep(1); + } + } while ((m_context == NULL) && (count < MAX_CONTEXT_FAIL)); + if (count == MAX_CONTEXT_FAIL) + { + LOG_ERR("Context creation failed"); + return false; + } + + // Create a control point for InternetGatewayDevice + m_controlPoint = gupnp_control_point_new(m_context, m_deviceInternetGateway.c_str()); + if (!m_controlPoint) + { + LOG_ERR("Error creating control point"); + return false; + } + + // Connects a callback function to a signal for InternetGatewayDevice + g_signal_connect(m_controlPoint, "device-proxy-available", + G_CALLBACK(&UpnpDiscoveryManager::deviceProxyAvailableCallback), this); + return true; +} + +void* UpnpDiscoveryManager::runMainLoop(void *arg) +{ + // gmain loop need to be running for upnp discovery and telemetry logging + g_main_loop_run(((UpnpDiscoveryManager *)arg)->m_mainLoop); +} + +gboolean UpnpDiscoveryManager::logTelemetry(void *arg) +{ + std::lock_guard lock(((UpnpDiscoveryManager *)arg)->m_apMutex); + LOG_INFO("Connected_to_Gateway: %s", ((UpnpDiscoveryManager *)arg)->m_gatewayDetails.str().c_str()); +#if USE_TELEMETRY + LOG_INFO("Telemetry logging"); + //T2 telemtery logging + T2ERROR t2error = t2_event_s("gateway_details_split", ((UpnpDiscoveryManager *)arg)->m_gatewayDetails.str().c_str()); + if (t2error != T2ERROR_SUCCESS) + { + LOG_ERR("t2_event_s(\"%s\", \"%s\") returned error code %d", "gateway_details_split", ((UpnpDiscoveryManager *)arg)->m_gatewayDetails.str().c_str(), t2error); + } +#endif + return true; +} + +void UpnpDiscoveryManager::findGatewayDevice(const std::string& interface) +{ + //Clear previous gupnp contexts if any + clearUpnpExistingRequests(); + + //Initialise gupnp context + if (true == initialiseUpnp(interface)) + { + // Start discovery to find InternetGatewayDevice + if (TRUE != gssdp_resource_browser_get_active(GSSDP_RESOURCE_BROWSER(m_controlPoint))) + { + LOG_INFO("Searching for InternetGatewayDevice"); + gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(m_controlPoint), TRUE); + } + } + else + { + LOG_ERR("Failed in initialising upnp"); + } +} + +void UpnpDiscoveryManager::clearUpnpExistingRequests() +{ + if (m_controlPoint) + { + g_object_ref_sink(m_controlPoint); + stopSearchGatewayDevice(); + g_object_unref(m_controlPoint); + m_controlPoint = NULL; + } + if (m_context) + { + g_object_unref(m_context); + m_context = NULL; + } +} + +void UpnpDiscoveryManager::on_device_proxy_available(GUPnPControlPoint *controlPoint, GUPnPDeviceProxy *proxy) +{ + m_apMake = gupnp_device_info_get_manufacturer(GUPNP_DEVICE_INFO(proxy)); + m_apModelName = gupnp_device_info_get_model_name(GUPNP_DEVICE_INFO(proxy)); + m_apModelNumber = gupnp_device_info_get_model_number(GUPNP_DEVICE_INFO(proxy)); + m_apMake = m_apMake.substr(0, m_apMake.find(',')); + // Stop discovery to find InternetGatewayDevice + stopSearchGatewayDevice(); + std::lock_guard lock(m_apMutex); + m_gatewayDetails.str(""); + m_gatewayDetails.clear(); + m_gatewayDetails << m_apMake << "," << m_apModelName << "," << m_apModelNumber; + LOG_INFO("Received gateway details: %s", m_gatewayDetails.str().c_str()); +} + +void UpnpDiscoveryManager::stopSearchGatewayDevice() +{ + if (TRUE == gssdp_resource_browser_get_active(GSSDP_RESOURCE_BROWSER(m_controlPoint))) + { + gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(m_controlPoint), FALSE); + } +} diff --git a/UpnpDiscoveryManager.h b/UpnpDiscoveryManager.h new file mode 100644 index 00000000..d227648c --- /dev/null +++ b/UpnpDiscoveryManager.h @@ -0,0 +1,77 @@ +/** +* 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 __UPNP_H__ +#define __UPNP_H__ + +#include +#include +#include +#include +#include +#include +#if USE_TELEMETRY +#include +#endif + +#define LOG_ERR(msg, ...) g_printerr("[%s:%d] " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__) +#define LOG_INFO(msg, ...) g_printerr("[%s:%d] " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__) + +#define MAX_CONTEXT_FAIL 3 + +class UpnpDiscoveryManager +{ +public: + void NotifyInterfaceStateChangeEvent(); + void NotifyIpAcquiredEvent(const std::string& interface); + UpnpDiscoveryManager(); + ~UpnpDiscoveryManager(); + +private: + static void* runMainLoop(void *arg); + static void* runUpnp(void *arg); + static gboolean logTelemetry(void* arg); + gboolean initialiseUpnp(const std::string& interface); + void clearUpnpExistingRequests(); + void findGatewayDevice(const std::string& interface); + void stopSearchGatewayDevice(); + void on_device_proxy_available(GUPnPControlPoint *control_point, GUPnPDeviceProxy *proxy); + static void deviceProxyAvailableCallback(GUPnPControlPoint *control_point, GUPnPDeviceProxy *proxy, gpointer user_data) + { + auto *self = static_cast(user_data); + self->on_device_proxy_available(control_point, proxy); + } + GUPnPContext* m_context; + GUPnPControlPoint* m_controlPoint; + GMainLoop* m_mainLoop; + GThread* m_threadGmain; + GThread* m_threadUpnp; + std::string m_apMake; + std::string m_apModelName; + std::string m_apModelNumber; + std::string m_interface; + std::mutex m_apMutex; + std::mutex m_upnpStatusMutex; + std::mutex m_upnpCvMutex; + std::condition_variable m_upnpCv; + std::ostringstream m_gatewayDetails; + static std::string const m_deviceInternetGateway; + static const int LOGGING_PERIOD_IN_SEC = 30; //15min * 60 + bool m_upnpRunStatus; +}; +#endif diff --git a/cmake/Findtelemetry_msgsender.cmake b/cmake/Findtelemetry_msgsender.cmake new file mode 100644 index 00000000..64ef7f51 --- /dev/null +++ b/cmake/Findtelemetry_msgsender.cmake @@ -0,0 +1,37 @@ +############################################################################# +# 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. +############################################################################# + +find_package(PkgConfig) + +find_library(TELEMETRY_LIBRARIES NAMES telemetry_msgsender) +find_path(TELEMETRY_INCLUDE_DIRS NAMES telemetry_busmessage_sender.h) + +set(TELEMETRY_LIBRARIES ${TELEMETRY_LIBRARIES} CACHE PATH "Path to telemetry library") +set(TELEMETRY_INCLUDE_DIRS ${TELEMETRY_INCLUDE_DIRS} ) +set(TELEMETRY_INCLUDE_DIRS ${TELEMETRY_INCLUDE_DIRS} CACHE PATH "Path to telemetry include") + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(TELEMETRY DEFAULT_MSG TELEMETRY_INCLUDE_DIRS TELEMETRY_LIBRARIES) + +mark_as_advanced( + TELEMETRY_FOUND + TELEMETRY_INCLUDE_DIRS + TELEMETRY_LIBRARIES + TELEMETRY_LIBRARY_DIRS + TELEMETRY_FLAGS)