From d0cc656535794d72836fbe5ba1faae67bbdb30f0 Mon Sep 17 00:00:00 2001 From: RAFI <103924677+cmuhammedrafi@users.noreply.github.com> Date: Thu, 16 Jan 2025 01:37:51 +0530 Subject: [PATCH 1/3] RDK-55450 [NetworkManager] Improve Connectivity Monitoring (#71) * connectivity monitor clean up change * InetworkManager enums added * start and stop connectivity monitor api removed * log line added * code review comments updated * fix the limited timeout * Update NetworkManager.json * Update NetworkManagerPlugin.md * Update NetworkManager.json * Update NetworkManagerPlugin.md * remove cache logic form workflow --------- Co-authored-by: Karunakaran A <48997923+karuna2git@users.noreply.github.com> --- .github/workflows/gnome_unit_test.yml | 18 - INetworkManager.h | 5 - LegacyPlugin_NetworkAPIs.cpp | 26 +- NetworkManager.h | 2 - NetworkManager.json | 100 +-- NetworkManagerConnectivity.cpp | 744 +++++++++--------- NetworkManagerConnectivity.h | 123 ++- NetworkManagerImplementation.cpp | 53 +- NetworkManagerImplementation.h | 5 - NetworkManagerJsonRpc.cpp | 32 - NetworkManagerRDKProxy.cpp | 1 - .../test_NetworkManagerConnectivity.cpp | 74 +- docs/NetworkManagerPlugin.md | 148 +--- 13 files changed, 512 insertions(+), 819 deletions(-) diff --git a/.github/workflows/gnome_unit_test.yml b/.github/workflows/gnome_unit_test.yml index 3d8fd278..23be4d13 100644 --- a/.github/workflows/gnome_unit_test.yml +++ b/.github/workflows/gnome_unit_test.yml @@ -15,20 +15,6 @@ jobs: runs-on: ubuntu-22.04 steps: - - name: Configure cache - if: ${{ !env.ACT }} - id: cache - uses: actions/cache@v3 - with: - path: | - build/Thunder - build/ThunderInterfaces - build/ThunderTools - install - !install/etc/WPEFramework/plugins - !install/usr/lib/wpeframework/plugins - key: ${{ runner.os }}-${{ env.THUNDER_REF }} - - name: Install packages run: | sudo apt update @@ -46,14 +32,12 @@ jobs: cmake-version: '3.16.x' - name: Checkout thunder repositories - if: steps.cache.outputs.cache-hit != 'true' run: | git clone https://github.com/rdkcentral/ThunderTools ThunderTools --branch ${{ env.THUNDER_REF }} git clone https://github.com/rdkcentral/Thunder Thunder --branch ${{ env.THUNDER_REF }} git clone https://github.com/rdkcentral/ThunderInterfaces ThunderInterfaces --branch ${{ env.THUNDER_REF }} - name: Build ThunderTools - if: steps.cache.outputs.cache-hit != 'true' run: > cmake -S "${{github.workspace}}/ThunderTools" -B build/ThunderTools @@ -64,7 +48,6 @@ jobs: cmake --build build/ThunderTools --target install -j8 - name: Build Thunder - if: steps.cache.outputs.cache-hit != 'true' run: > cmake -S "${{github.workspace}}/Thunder" -B build/Thunder @@ -77,7 +60,6 @@ jobs: cmake --build build/Thunder --target install -j8 - name: Build ThunderInterfaces - if: steps.cache.outputs.cache-hit != 'true' run: > cmake -S "${{github.workspace}}/ThunderInterfaces" -B build/ThunderInterfaces diff --git a/INetworkManager.h b/INetworkManager.h index 6b67729f..26d63374 100644 --- a/INetworkManager.h +++ b/INetworkManager.h @@ -237,11 +237,6 @@ namespace WPEFramework /* @brief Get Authentication URL if the device is behind Captive Portal */ virtual uint32_t GetCaptivePortalURI(string &uri/* @out */) const = 0; - /* @brief Start The Internet Connectivity Monitoring */ - virtual uint32_t StartConnectivityMonitoring(const uint32_t interval /* @in */) = 0; - /* @brief Stop The Internet Connectivity Monitoring */ - virtual uint32_t StopConnectivityMonitoring(void) const = 0; - /* @brief Get the Public IP used for external world communication */ virtual uint32_t GetPublicIP (string& interface /* @inout */, string &ipversion /* @inout */, string& ipaddress /* @out */) = 0; diff --git a/LegacyPlugin_NetworkAPIs.cpp b/LegacyPlugin_NetworkAPIs.cpp index 67b82246..8d49452e 100644 --- a/LegacyPlugin_NetworkAPIs.cpp +++ b/LegacyPlugin_NetworkAPIs.cpp @@ -817,19 +817,7 @@ const string CIDR_PREFIXES[CIDR_NETMASK_IP_LEN+1] = { uint32_t Network::startConnectivityMonitoring(const JsonObject& parameters, JsonObject& response) { LOG_INPARAM(); - uint32_t rc = Core::ERROR_GENERAL; - uint32_t interval = parameters["interval"].Number(); - - NMLOG_DEBUG("connectivity interval = %d", interval); - auto _nwmgr = m_service->QueryInterfaceByCallsign(NETWORK_MANAGER_CALLSIGN); - if (_nwmgr) - rc = _nwmgr->StartConnectivityMonitoring(interval); - else - rc = Core::ERROR_UNAVAILABLE; - - if(_nwmgr) - _nwmgr->Release(); - + uint32_t rc = Core::ERROR_NONE; returnJson(rc); } @@ -857,17 +845,7 @@ const string CIDR_PREFIXES[CIDR_NETMASK_IP_LEN+1] = { uint32_t Network::stopConnectivityMonitoring(const JsonObject& parameters, JsonObject& response) { LOG_INPARAM(); - uint32_t rc = Core::ERROR_GENERAL; - - auto _nwmgr = m_service->QueryInterfaceByCallsign(NETWORK_MANAGER_CALLSIGN); - if (_nwmgr) - { - rc = _nwmgr->StopConnectivityMonitoring(); - _nwmgr->Release(); - } - else - rc = Core::ERROR_UNAVAILABLE; - + uint32_t rc = Core::ERROR_NONE; returnJson(rc); } diff --git a/NetworkManager.h b/NetworkManager.h index c99b8615..d4830dd0 100644 --- a/NetworkManager.h +++ b/NetworkManager.h @@ -247,8 +247,6 @@ namespace WPEFramework uint32_t SetConnectivityTestEndpoints(const JsonObject& parameters, JsonObject& response); uint32_t IsConnectedToInternet(const JsonObject& parameters, JsonObject& response); uint32_t GetCaptivePortalURI(const JsonObject& parameters, JsonObject& response); - uint32_t StartConnectivityMonitoring(const JsonObject& parameters, JsonObject& response); - uint32_t StopConnectivityMonitoring(const JsonObject& parameters, JsonObject& response); uint32_t GetPublicIP(const JsonObject& parameters, JsonObject& response); uint32_t Ping(const JsonObject& parameters, JsonObject& response); uint32_t Trace(const JsonObject& parameters, JsonObject& response); diff --git a/NetworkManager.json b/NetworkManager.json index 649a044b..ed3e481a 100644 --- a/NetworkManager.json +++ b/NetworkManager.json @@ -108,14 +108,14 @@ "example": "30" }, "ssid":{ - "summary": "The paired SSID", + "summary": "The WiFi SSID Name", "type": "string", - "example": "123412341234" + "example": "myHomeSSID" }, "bssid":{ - "summary": "The paired BSSID", + "summary": "The BSSID of given SSID", "type": "string", - "example": "ff:ff:ff:ff:ff:ff" + "example": "AA:BB:CC:DD:EE:FF" }, "passphrase": { "summary": "The access point password", @@ -128,10 +128,15 @@ "example": 6 }, "strength":{ - "summary": "The RSSI value in dBm", + "summary": "The Signal RSSI value in dBm", "type": "string", "example": "-27.000000" }, + "quality":{ + "summary": "Signal strength Quality", + "type": "string", + "example": "Excellent" + }, "frequency":{ "summary": "The supported frequency for this SSID in GHz", "type": "string", @@ -334,9 +339,7 @@ "type": "object", "properties": { "interface": { - "summary": "Disable the specified interface", - "type": "string", - "example": "wlan0" + "$ref": "#/definitions/interface" } }, "required": [ @@ -552,9 +555,10 @@ "type":"object", "properties": { "endpoints": { - "summary": "", + "summary": "A list of endpoint URLs used", "type": "array", "items": { + "summary": "The endpoint URL", "type": "string", "example": "http://clients3.google.com/generate_204" } @@ -578,6 +582,7 @@ "summary": "A list of endpoints to test", "type": "array", "items": { + "summary": "The endpoint URL", "type": "string", "example": "http://clients3.google.com/generate_204" } @@ -665,49 +670,6 @@ ] } }, - "StartConnectivityMonitoring":{ - "summary": "Enable a continuous monitoring of internet connectivity with heart beat interval thats given. If the monitoring is already happening, it will be restarted with new given interval. When the interval is not passed, it will be 60s by default.", - "events":{ - "onInternetStatusChange" : "Triggered when internet connection state changed." - }, - "params": { - "type":"object", - "properties": { - "interval": { - "summary": "Interval in sec.", - "type": "number", - "example": "30" - } - }, - "required": [ - ] - }, - "result": { - "type": "object", - "properties": { - "success":{ - "$ref": "#/definitions/success" - } - }, - "required": [ - "success" - ] - } - }, - "StopConnectivityMonitoring":{ - "summary": "Stops the connectivity monitoring", - "result": { - "type": "object", - "properties": { - "success":{ - "$ref": "#/definitions/success" - } - }, - "required": [ - "success" - ] - } - }, "GetPublicIP":{ "summary": "Gets the internet/public IP Address of the device.", "params": { @@ -915,6 +877,7 @@ "summary": "The list of SSIDs to be scanned.", "type": "array", "items": { + "summary": "The SSID to scan.", "type": "string", "example": "Xfinity Mobile" } @@ -955,9 +918,10 @@ "type": "object", "properties": { "ssids": { - "summary": "Known SSIDS", + "summary": "A list of known SSIDs", "type": "array", "items": { + "summary": "The WiFi SSID Name", "type": "string", "example": "Xfinity_Guest" } @@ -1263,9 +1227,7 @@ "$ref": "#/definitions/strength" }, "quality":{ - "summary": "Signal strength Quality", - "type": "string", - "example": "Excellent" + "$ref": "#/definitions/quality" }, "success":{ "$ref": "#/definitions/success" @@ -1514,24 +1476,18 @@ "type":"object", "properties": { "ssid":{ - "summary": "ssid", + "summary": "Discovered SSID", "type": "string", "example": "myAP-2.4" }, "security":{ - "summary": "security", - "type": "integer", - "example": 6 + "$ref": "#/definitions/security" }, "strength":{ - "summary": "strength", - "type": "string", - "example": "-27.000000" + "$ref": "#/definitions/strength" }, "frequency":{ - "summary": "frequency", - "type": "string", - "example": "2.442000" + "$ref": "#/definitions/frequency" } }, "required": [ @@ -1573,19 +1529,13 @@ "type": "object", "properties": { "ssid":{ - "summary": "Signal Strength changed SSID", - "type": "string", - "example": "home-new_123" + "$ref": "#/definitions/ssid" }, "strength":{ - "summary": "Signal Strength", - "type": "string", - "example": "-27.000000" + "$ref": "#/definitions/strength" }, "quality":{ - "summary": "Signal quality", - "type": "string", - "example": "Excellent" + "$ref": "#/definitions/quality" } }, "required": [ diff --git a/NetworkManagerConnectivity.cpp b/NetworkManagerConnectivity.cpp index ce38c246..8140b2e9 100644 --- a/NetworkManagerConnectivity.cpp +++ b/NetworkManagerConnectivity.cpp @@ -19,14 +19,17 @@ #include #include -#include +#include #include #include -#include +#include +#include +#include #include "NetworkManagerImplementation.h" #include "NetworkManagerConnectivity.h" #include "NetworkManagerLogger.h" +#include "INetworkManager.h" namespace WPEFramework { @@ -35,27 +38,30 @@ namespace WPEFramework extern NetworkManagerImplementation* _instance; - static const char* getInternetStateString(nsm_internetState state) + constexpr auto INTERNET_NOT_AVAILABLE = Exchange::INetworkManager::InternetStatus::INTERNET_NOT_AVAILABLE; + constexpr auto INTERNET_LIMITED = Exchange::INetworkManager::InternetStatus::INTERNET_LIMITED; + constexpr auto INTERNET_CAPTIVE_PORTAL = Exchange::INetworkManager::InternetStatus::INTERNET_CAPTIVE_PORTAL; + constexpr auto INTERNET_FULLY_CONNECTED = Exchange::INetworkManager::InternetStatus::INTERNET_FULLY_CONNECTED; + constexpr auto INTERNET_UNKNOWN = Exchange::INetworkManager::InternetStatus::INTERNET_UNKNOWN; + + constexpr auto IP_ADDRESS_V4 = Exchange::INetworkManager::IPVersion::IP_ADDRESS_V4; + constexpr auto IP_ADDRESS_V6 = Exchange::INetworkManager::IPVersion::IP_ADDRESS_V6; + + static const char* getInternetStateString(Exchange::INetworkManager::InternetStatus state) { switch(state) { - case NO_INTERNET: return "NO_INTERNET"; - case LIMITED_INTERNET: return "LIMITED_INTERNET"; - case CAPTIVE_PORTAL: return "CAPTIVE_PORTAL"; - case FULLY_CONNECTED: return "FULLY_CONNECTED"; + case INTERNET_NOT_AVAILABLE: return "NO_INTERNET"; + case INTERNET_LIMITED: return "LIMITED_INTERNET"; + case INTERNET_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL"; + case INTERNET_FULLY_CONNECTED: return "FULLY_CONNECTED"; default: return "UNKNOWN"; } } - bool EndpointCache::isEndpointCashFileExist() - { - std::ifstream fileStream(CachefilePath); - return fileStream.is_open(); - } - - void EndpointCache::writeEnpointsToFile(const std::vector& endpoints) + void EndpointManager::writeEndpointsToFile(const std::vector& endpoints) { - std::ofstream outputFile(CachefilePath); + std::ofstream outputFile(m_CachefilePath); if (outputFile.is_open()) { for (const std::string& str : endpoints) @@ -70,10 +76,10 @@ namespace WPEFramework } } - std::vector EndpointCache::readEnpointsFromFile() + std::vector EndpointManager::readEndpointsFromFile() { std::vector readStrings; - std::ifstream inputFile(CachefilePath); + std::ifstream inputFile(m_CachefilePath); if (inputFile.is_open()) { std::string line; @@ -90,9 +96,152 @@ namespace WPEFramework return readStrings; } - TestConnectivity::TestConnectivity(const std::vector& endpoints, long timeout_ms, bool headReq, nsm_ipversion ipversion) + void EndpointManager::setConnectivityMonitorEndpoints(const std::vector& endpoints) + { + const std::lock_guard lock(m_endpointMutex); + if(endpoints.empty()) + { + NMLOG_ERROR("Empty endpoints"); + return; + } + + m_Endpoints.clear(); + for (auto endpoint : endpoints) { + if(!endpoint.empty() && endpoint.size() > 3) + m_Endpoints.push_back(endpoint.c_str()); + else + NMLOG_ERROR("endpoint not vallied = %s", endpoint.c_str()); + } + + // write the endpoints to a file + writeEndpointsToFile(m_Endpoints); + + std::string endpointsStr; + for (const auto& endpoint : m_Endpoints) + endpointsStr.append(endpoint).append(" "); + NMLOG_INFO("Connectivity monitor endpoints updated -: %d :- %s", static_cast(m_Endpoints.size()), endpointsStr.c_str()); + } + + EndpointManager::EndpointManager() + { + m_CachefilePath = NMCONNECTIVITY_MONITOR_CACHE_FILE; + m_Endpoints.clear(); // default value will be loaded from NetworkManagerImplementation configuration + + std::ifstream inputFile(m_CachefilePath); + if (inputFile.is_open()) + { + std::string line; + std::vector endpoints{}; + while (std::getline(inputFile, line)) + { + if(!line.empty() && line.size() > 3) + endpoints.push_back(line); + } + NMLOG_WARNING("cached connectivity endpoints loaded .."); + setConnectivityMonitorEndpoints(endpoints); + inputFile.close(); + } + else + { + NMLOG_ERROR("no endpoint cache file found"); + } + } + + std::vector EndpointManager::getConnectivityMonitorEndpoints() + { + const std::lock_guard lock(m_endpointMutex); + return m_Endpoints; + } + + bool DnsResolver::resolveIP(std::string& uri, Exchange::INetworkManager::IPVersion& ipversion) + { + struct addrinfo sockAddrProps, *resultAddr= NULL; + char ipStr[INET6_ADDRSTRLEN] = {0}; + + if(ipversion == IP_ADDRESS_V4) + sockAddrProps.ai_family = AF_INET; + else if(ipversion == IP_ADDRESS_V6) + sockAddrProps.ai_family = AF_INET6; + else + sockAddrProps.ai_family = AF_UNSPEC; + + sockAddrProps.ai_socktype = SOCK_STREAM; + sockAddrProps.ai_flags = 0; + sockAddrProps.ai_protocol = 0; + + int ret = getaddrinfo(uri.c_str(), NULL, &sockAddrProps, &resultAddr); + if (ret != 0) { + NMLOG_WARNING("Resolved IP Failed getaddrinfo: %s", gai_strerror(ret)); + return false; + } + + NMLOG_DEBUG("Resolved IP addresses for %s", uri.c_str()); + + for (struct addrinfo * resutIP = resultAddr; resutIP != NULL; resutIP = resutIP->ai_next) + { + void *addr= NULL; + if (resutIP->ai_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)resutIP->ai_addr; + addr = &(ipv4->sin_addr); + ipv4Resolved = true; + } else if (resutIP->ai_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)resutIP->ai_addr; + addr = &(ipv6->sin6_addr); + ipv6Resolved = true; + } else { + continue; + } + + inet_ntop(resutIP->ai_family, addr, ipStr, sizeof(ipStr)); + NMLOG_DEBUG("Resolved IP --> %s", ipStr); + } + + freeaddrinfo(resultAddr); + return true; + } + + std::string DnsResolver::convertUrIToDomainName(std::string& url) { - internetSate = UNKNOWN; + size_t domainStart = 0; + size_t protocolEnd = url.find("://"); + if (protocolEnd != std::string::npos) { + domainStart = protocolEnd + 3; + } + + size_t domainEnd = url.find('/', domainStart); + if (domainEnd != std::string::npos) + return url.substr(domainStart, domainEnd - domainStart); + else + return url.substr(domainStart); + } + + DnsResolver::DnsResolver(std::string url, Exchange::INetworkManager::IPVersion ipversion, int curlErrorCode) + { + NMLOG_DEBUG("url %s - ipversion %d - curl error %d ", url.c_str(), ipversion, curlErrorCode); + if(url.empty()) { + NMLOG_ERROR("URI/hostname missing"); + return; + } + switch (curlErrorCode) + { + case CURLE_COULDNT_RESOLVE_HOST: // 6 - Could not resolve host + case CURLE_OPERATION_TIMEDOUT: // 28 - Operation timeout. time-out period + case CURLE_RECV_ERROR: // 56 - Failure with receiving network data + { + m_domain = convertUrIToDomainName(url); + resolveIP(m_domain, ipversion); + break; + } + default: + ipv4Resolved = false; + ipv6Resolved = false; + break; + } + } + + TestConnectivity::TestConnectivity(const std::vector& endpoints, long timeout_ms, bool headReq, Exchange::INetworkManager::IPVersion ipversion) + { + internetSate = INTERNET_UNKNOWN; if(endpoints.size() < 1) { NMLOG_ERROR("Endpoints size error ! curl check not possible"); return; @@ -119,7 +268,7 @@ namespace WPEFramework return size * nmemb; } - nsm_internetState TestConnectivity::checkCurlResponse(const std::vector& endpoints, long timeout_ms, bool headReq, nsm_ipversion ipversion) + Exchange::INetworkManager::InternetStatus TestConnectivity::checkCurlResponse(const std::vector& endpoints, long timeout_ms, bool headReq, Exchange::INetworkManager::IPVersion ipversion) { long deadline = current_time() + timeout_ms, time_now = 0, time_earlier = 0; @@ -127,7 +276,7 @@ namespace WPEFramework if (!curl_multi_handle) { NMLOG_ERROR("curl_multi_init returned NULL"); - return NO_INTERNET; + return INTERNET_NOT_AVAILABLE; } CURLMcode mc; @@ -156,15 +305,17 @@ namespace WPEFramework } curl_easy_setopt(curl_easy_handle, CURLOPT_WRITEFUNCTION, writeFunction); curl_easy_setopt(curl_easy_handle, CURLOPT_TIMEOUT_MS, deadline - current_time()); - if ((ipversion == CURL_IPRESOLVE_V4) || (ipversion == CURL_IPRESOLVE_V6)) - { - NMLOG_DEBUG("curlopt ipversion = %s reqtyp = %s", ipversion == CURL_IPRESOLVE_V4?"IPv4":"IPv6", headReq? "HEAD":"GET"); - curl_easy_setopt(curl_easy_handle, CURLOPT_IPRESOLVE, ipversion); + if (IP_ADDRESS_V4 == ipversion) { + curl_easy_setopt(curl_easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + NMLOG_DEBUG("curlopt ipversion = IPv4 reqtyp = %s", headReq? "HEAD":"GET"); + } + else if (IP_ADDRESS_V6 == ipversion) { + curl_easy_setopt(curl_easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); + NMLOG_DEBUG("curlopt ipversion = IPv6 reqtyp = %s", headReq? "HEAD":"GET"); } else - { NMLOG_DEBUG("curlopt ipversion = whatever reqtyp = %s", headReq? "HEAD":"GET"); - } + if(curlVerboseEnabled()) curl_easy_setopt(curl_easy_handle, CURLOPT_VERBOSE, 1L); if (CURLM_OK != (mc = curl_multi_add_handle(curl_multi_handle, curl_easy_handle))) @@ -205,8 +356,10 @@ namespace WPEFramework } } } - else + else { NMLOG_ERROR("endpoint = <%s> curl error = %d (%s)", endpoint, msg->data.result, curl_easy_strerror(msg->data.result)); + curlErrorCode = static_cast(msg->data.result); + } http_responses.push_back(response_code); } time_earlier = time_now; @@ -264,9 +417,9 @@ namespace WPEFramework * Return Internet State: FULLY_CONNECTED - 50 % */ - nsm_internetState TestConnectivity::checkInternetStateFromResponseCode(const std::vector& responses) + Exchange::INetworkManager::InternetStatus TestConnectivity::checkInternetStateFromResponseCode(const std::vector& responses) { - nsm_internetState InternetConnectionState = NO_INTERNET; + Exchange::INetworkManager::InternetStatus InternetConnectionState = INTERNET_NOT_AVAILABLE; nsm_connectivity_httpcode http_response_code = HttpStatus_response_error; int max_count = 0; @@ -289,20 +442,20 @@ namespace WPEFramework switch (http_response_code) { case HttpStatus_204_No_Content: - InternetConnectionState = FULLY_CONNECTED; + InternetConnectionState = INTERNET_FULLY_CONNECTED; NMLOG_INFO("Internet State: FULLY_CONNECTED - %.1f%%", (percentage*100)); break; case HttpStatus_200_OK: - InternetConnectionState = LIMITED_INTERNET; + InternetConnectionState = INTERNET_LIMITED; NMLOG_INFO("Internet State: LIMITED_INTERNET - %.1f%%", (percentage*100)); break; case HttpStatus_511_Authentication_Required: case HttpStatus_302_Found: - InternetConnectionState = CAPTIVE_PORTAL; + InternetConnectionState = INTERNET_CAPTIVE_PORTAL; NMLOG_INFO("Internet State: CAPTIVE_PORTAL - %.1f%%", (percentage*100)); break; default: - InternetConnectionState = NO_INTERNET; + InternetConnectionState = INTERNET_NOT_AVAILABLE; if(http_response_code == -1) NMLOG_ERROR("Internet State: NO_INTERNET (curl error)"); else @@ -315,202 +468,111 @@ namespace WPEFramework ConnectivityMonitor::ConnectivityMonitor() { - if(endpointCache.isEndpointCashFileExist()) - { - std::vector cachedEndPnt = endpointCache.readEnpointsFromFile(); - setConnectivityMonitorEndpoints(cachedEndPnt); - NMLOG_WARNING("cached connectivity endpoints loaded .."); - } - - doContinuousMonitor = false; - doConnectivityMonitor = false; - m_InternetState = nsm_internetState::UNKNOWN; - m_Ipv4InternetState = nsm_internetState::UNKNOWN; - m_Ipv6InternetState = nsm_internetState::UNKNOWN; + NMLOG_WARNING("ConnectivityMonitor"); + m_cmRunning = false; + m_notify = true; + m_InternetState = INTERNET_UNKNOWN; + m_Ipv4InternetState = INTERNET_UNKNOWN; + m_Ipv6InternetState = INTERNET_UNKNOWN; + startConnectivityMonitor(); } ConnectivityMonitor::~ConnectivityMonitor() { NMLOG_WARNING("~ConnectivityMonitor"); - doContinuousMonitor = false; - doConnectivityMonitor = false; - cvConnectivityMonitor.notify_one(); - cvContinuousMonitor.notify_one(); - if (continuousMonitorThrd.joinable()) - continuousMonitorThrd.join(); - if (connectivityMonitorThrd.joinable()) - connectivityMonitorThrd.join(); + stopConnectivityMonitor(); } std::vector ConnectivityMonitor::getConnectivityMonitorEndpoints() { - const std::lock_guard lock(endpointMutex); - std::vector endpoints; - for (auto endpoint : connectivityMonitorEndpt) { - endpoints.push_back(endpoint); - } - return endpoints; + return m_endpoint.getConnectivityMonitorEndpoints(); } void ConnectivityMonitor::setConnectivityMonitorEndpoints(const std::vector &endpoints) { - const std::lock_guard lock(endpointMutex); - connectivityMonitorEndpt.clear(); - for (auto endpoint : endpoints) { - if(!endpoint.empty() && endpoint.size() > 3) - connectivityMonitorEndpt.push_back(endpoint.c_str()); - else - NMLOG_ERROR("endpoint not vallied = %s", endpoint.c_str()); - } - - // write the endpoints to a file - endpointCache.writeEnpointsToFile(connectivityMonitorEndpt); - - std::string endpointsStr; - for (const auto& endpoint : connectivityMonitorEndpt) - endpointsStr.append(endpoint).append(" "); - NMLOG_INFO("Connectivity monitor endpoints -: %d :- %s", static_cast(connectivityMonitorEndpt.size()), endpointsStr.c_str()); - } - - bool ConnectivityMonitor::isConnectedToInternet(nsm_ipversion ipversion) - { - if (nsm_internetState::FULLY_CONNECTED == getInternetState(ipversion)) - { - NMLOG_INFO("isConnectedToInternet %s = true", (ipversion == nsm_ipversion::NSM_IPRESOLVE_WHATEVER)?"":(ipversion == nsm_ipversion::NSM_IPRESOLVE_V4? "IPv4":"IPv6")); - return true; - } - NMLOG_WARNING("isConnectedToInternet %s = false",(ipversion == nsm_ipversion::NSM_IPRESOLVE_WHATEVER)?"":(ipversion == nsm_ipversion::NSM_IPRESOLVE_V4? "IPv4":"IPv6") ); - return false; + m_endpoint.setConnectivityMonitorEndpoints(endpoints); } - nsm_internetState ConnectivityMonitor::getInternetState(nsm_ipversion& ipversion) + Exchange::INetworkManager::InternetStatus ConnectivityMonitor::getInternetState(Exchange::INetworkManager::IPVersion& ipversion, bool ipVersionNotSpecified) { - nsm_internetState internetState = nsm_internetState::UNKNOWN; - // If monitor connectivity is running take the cache value - - if ( doContinuousMonitor && (nsm_ipversion::NSM_IPRESOLVE_V4 == ipversion || nsm_ipversion::NSM_IPRESOLVE_WHATEVER == ipversion) - && m_Ipv4InternetState != nsm_internetState::UNKNOWN ) { - NMLOG_WARNING("Reading Ipv4 internet state cached value %s", getInternetStateString(m_Ipv4InternetState)); - internetState = m_Ipv4InternetState; - ipversion = NSM_IPRESOLVE_V4; - } - else if ( doContinuousMonitor && (nsm_ipversion::NSM_IPRESOLVE_V6 == ipversion || nsm_ipversion::NSM_IPRESOLVE_WHATEVER == ipversion) - && m_Ipv6InternetState != nsm_internetState::UNKNOWN ) { - NMLOG_WARNING("Reading Ipv6 internet state cached value %s", getInternetStateString(m_Ipv6InternetState)); - internetState = m_Ipv6InternetState; - ipversion = NSM_IPRESOLVE_V6; + if(ipVersionNotSpecified) { + ipversion = m_ipversion; + NMLOG_DEBUG("ipversion %s - %s", ipversion == IP_ADDRESS_V4? "IPv4":"IPv6", getInternetStateString(m_InternetState.load())); + return m_InternetState.load(); } + else if(ipversion == IP_ADDRESS_V4) + return m_Ipv4InternetState.load(); + else if(ipversion == IP_ADDRESS_V6) + return m_Ipv6InternetState.load(); else - { - TestConnectivity testInternet(getConnectivityMonitorEndpoints(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, NMCONNECTIVITY_CURL_GET_REQUEST, ipversion); - internetState = testInternet.getInternetState(); - // TODO : Lets not hard code here. - ipversion = NSM_IPRESOLVE_V4; - } - return internetState; + return INTERNET_UNKNOWN; } std::string ConnectivityMonitor::getCaptivePortalURI() { - TestConnectivity testInternet(getConnectivityMonitorEndpoints(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, NMCONNECTIVITY_CURL_GET_REQUEST, NSM_IPRESOLVE_WHATEVER); - if(nsm_internetState::CAPTIVE_PORTAL == testInternet.getInternetState()) + if(m_Ipv4InternetState == INTERNET_CAPTIVE_PORTAL || m_Ipv6InternetState == INTERNET_CAPTIVE_PORTAL) { - NMLOG_WARNING("captive portal URI = %s", testInternet.getCaptivePortal().c_str()); - return testInternet.getCaptivePortal(); + NMLOG_INFO("captive portal URI = %s", m_captiveURI.c_str()); + return m_captiveURI; } + NMLOG_WARNING("No captive portal found !"); return std::string(""); } - bool ConnectivityMonitor::startContinuousConnectivityMonitor(int timeoutInSeconds) + bool ConnectivityMonitor::startConnectivityMonitor() { - if(_instance != nullptr ) - NMLOG_INFO("interface status eth - %s wlan - %s ", _instance->m_ethConnected? "up":"down", _instance->m_wlanConnected? "up":"down"); - continuousMonitorTimeout.store(timeoutInSeconds >= NMCONNECTIVITY_MONITOR_MIN_INTERVAL ? timeoutInSeconds : NMCONNECTIVITY_MONITOR_DEFAULT_INTERVAL); - if (doContinuousMonitor) + if (m_cmRunning) { - if(doConnectivityMonitor) - { - NMLOG_INFO("continuous monitor new timeout updated %d Sec", continuousMonitorTimeout.load()); - } - else - { - NMLOG_INFO("continuous monitor restarted with %d Sec", continuousMonitorTimeout.load()); - cvContinuousMonitor.notify_one(); - } + m_cmCv.notify_one(); + NMLOG_DEBUG("connectivity monitor is already running"); return true; } - if (continuousMonitorThrd.joinable()) { - NMLOG_WARNING("continuous monitor joinable thread running"); - doContinuousMonitor = false; - continuousMonitorThrd.join(); - } + m_cmRunning = true; + m_cmThrdID = std::thread(&ConnectivityMonitor::connectivityMonitorFunction, this); - doContinuousMonitor = true; - continuousMonitorThrd = std::thread(&ConnectivityMonitor::continuousMonitorFunction, this); - NMLOG_INFO("continuous connectivity monitor started with %d Sec", continuousMonitorTimeout.load()); - if(!continuousMonitorThrd.joinable()) { - NMLOG_ERROR("continuous connectivity monitor start Failed"); - return false; + if(_instance != nullptr) { + NMLOG_INFO("connectivity monitor started - eth %s - wlan %s", + _instance->m_ethConnected? "up":"down", _instance->m_wlanConnected? "up":"down"); } + + NMLOG_INFO("connectivity monitor is started"); return true; } - bool ConnectivityMonitor::stopContinuousConnectivityMonitor() + bool ConnectivityMonitor::stopConnectivityMonitor() { - doContinuousMonitor = false; - cvContinuousMonitor.notify_one(); - if (continuousMonitorThrd.joinable()) - continuousMonitorThrd.join(); - NMLOG_INFO("continuous connectivity monitor stopped"); + m_cmRunning = false; + m_cmCv.notify_one(); + if(m_cmThrdID.joinable()) + m_cmThrdID.join(); + m_InternetState = INTERNET_UNKNOWN; + m_Ipv4InternetState = INTERNET_UNKNOWN; + m_Ipv6InternetState = INTERNET_UNKNOWN; + NMLOG_INFO("connectivity monitor stoped !!!"); return true; } - /* - * - * call startConnectivityMonitor function - * --> when IP address accuired - * --> when etherenet/wifi disconnected - */ - bool ConnectivityMonitor::startConnectivityMonitor() + bool ConnectivityMonitor::switchToInitialCheck() { - m_InternetState = nsm_internetState::UNKNOWN; - m_Ipv4InternetState = nsm_internetState::UNKNOWN; - m_Ipv6InternetState = nsm_internetState::UNKNOWN; - if (doConnectivityMonitor) - { - cvConnectivityMonitor.notify_one(); - NMLOG_DEBUG("trigger connectivity monitor thread"); - return true; - } - - if (connectivityMonitorThrd.joinable()) { // cleanup of previous thread - doConnectivityMonitor = false; - connectivityMonitorThrd.join(); - } - - doConnectivityMonitor = true; - connectivityMonitorThrd = std::thread(&ConnectivityMonitor::connectivityMonitorFunction, this); - if(!connectivityMonitorThrd.joinable()) { - NMLOG_ERROR("connectivity monitor start failed"); - return false; - } - + m_switchToInitial = true; + m_notify = true; // m_notify internet state because some network state change may happen + m_cmCv.notify_one(); if(_instance != nullptr) { - NMLOG_INFO("connectivity monitor started %d sec - eth %s - wlan %s", NMCONNECTIVITY_MONITOR_MIN_INTERVAL, - _instance->m_ethConnected? "up":"down", _instance->m_wlanConnected? "up":"down"); + NMLOG_INFO("switching to initial check - eth %s - wlan %s", + _instance->m_ethConnected? "up":"down", _instance->m_wlanConnected? "up":"down"); } return true; } - void ConnectivityMonitor::notifyInternetStatusChangedEvent(nsm_internetState newInternetState) + void ConnectivityMonitor::notifyInternetStatusChangedEvent(Exchange::INetworkManager::InternetStatus newInternetState) { - static Exchange::INetworkManager::InternetStatus oldState = Exchange::INetworkManager::InternetStatus::INTERNET_UNKNOWN; + static Exchange::INetworkManager::InternetStatus oldState = INTERNET_UNKNOWN; if(_instance != nullptr) { - NMLOG_INFO("notify internet state %s", getInternetStateString(newInternetState)); - Exchange::INetworkManager::InternetStatus newState = static_cast(newInternetState); + NMLOG_INFO("notifying internet state %s", getInternetStateString(newInternetState)); + Exchange::INetworkManager::InternetStatus newState = newInternetState; _instance->ReportInternetStatusChange(oldState , newState); m_InternetState = newInternetState; oldState = newState; // 'm_InternetState' not exactly previous state, it may change to unknow when interface changed @@ -519,223 +581,181 @@ namespace WPEFramework NMLOG_FATAL("NetworkManagerImplementation Instance NULL notifyInternetStatusChange failed."); } - void ConnectivityMonitor::continuousMonitorFunction() + void ConnectivityMonitor::connectivityMonitorFunction() { - int TempInterval = continuousMonitorTimeout.load(); - std::mutex connMutex; - nsm_ipversion ipResolveTyp = NSM_IPRESOLVE_WHATEVER; - int notifyPreRetry = 1; - nsm_internetState currentInternetState = nsm_internetState::UNKNOWN; - - do - { - if(_instance != nullptr && (!_instance->m_ethConnected && !_instance->m_wlanConnected)) // no wifi no ethernet connected - { - NMLOG_DEBUG("no interface connected; no ccm check"); - m_Ipv4InternetState = NO_INTERNET; - m_Ipv6InternetState = NO_INTERNET; - std::unique_lock lock(connMutex); - cvContinuousMonitor.wait_for(lock, std::chrono::seconds(continuousMonitorTimeout.load())); - ipResolveTyp = NSM_IPRESOLVE_WHATEVER; - continue; + int timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; + Exchange::INetworkManager::InternetStatus currentInternetState = INTERNET_NOT_AVAILABLE; + int InitialRetryCount = 0; + int IdealRetryCount = 0; + m_switchToInitial = true; + m_InternetState = INTERNET_UNKNOWN; + m_Ipv4InternetState = INTERNET_UNKNOWN; + m_Ipv6InternetState = INTERNET_UNKNOWN; + m_notify = true; + + while (m_cmRunning) { + // Check if no interfaces are connected + if (_instance != nullptr && !_instance->m_ethConnected && !_instance->m_wlanConnected) { + NMLOG_DEBUG("no interface connected, no ccm check"); + timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; + m_InternetState = INTERNET_NOT_AVAILABLE; + m_Ipv4InternetState = INTERNET_NOT_AVAILABLE; + m_Ipv6InternetState = INTERNET_NOT_AVAILABLE; + currentInternetState = INTERNET_NOT_AVAILABLE; + if (InitialRetryCount == 0) + m_notify = true; + InitialRetryCount = 1; } - - if(doConnectivityMonitor) - { - NMLOG_DEBUG("connectivity monitor running so skiping ccm check"); - m_Ipv4InternetState = nsm_internetState::UNKNOWN; - m_Ipv6InternetState = nsm_internetState::UNKNOWN; - std::unique_lock lock(connMutex); - cvContinuousMonitor.wait_for(lock, std::chrono::seconds(continuousMonitorTimeout.load())); - ipResolveTyp = NSM_IPRESOLVE_WHATEVER; /* some interface change happense */ - continue; - } - else if (ipResolveTyp == NSM_IPRESOLVE_WHATEVER) + else if (m_switchToInitial) { - nsm_internetState ipV4InternetState = nsm_internetState::UNKNOWN; - nsm_internetState ipV6InternetState = nsm_internetState::UNKNOWN; + NMLOG_INFO("Initial cm check - retry count %d - %s", InitialRetryCount, getInternetStateString(currentInternetState)); + timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; + + // Lambda functions to check connectivity for IPv4 and IPv6 auto curlCheckThrdIpv4 = [&]() { - TestConnectivity testInternet(getConnectivityMonitorEndpoints(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, - NMCONNECTIVITY_CURL_GET_REQUEST, NSM_IPRESOLVE_V4); - ipV4InternetState = testInternet.getInternetState(); + TestConnectivity testInternet(m_endpoint(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, + NMCONNECTIVITY_CURL_HEAD_REQUEST, IP_ADDRESS_V4); + m_Ipv4InternetState = testInternet.getInternetState(); + if(m_Ipv6InternetState == INTERNET_CAPTIVE_PORTAL) + m_captiveURI = testInternet.getCaptivePortal(); }; auto curlCheckThrdIpv6 = [&]() { - TestConnectivity testInternet(getConnectivityMonitorEndpoints(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, - NMCONNECTIVITY_CURL_GET_REQUEST, NSM_IPRESOLVE_V6); - ipV6InternetState = testInternet.getInternetState(); + TestConnectivity testInternet(m_endpoint(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, + NMCONNECTIVITY_CURL_HEAD_REQUEST, IP_ADDRESS_V6); + m_Ipv6InternetState = testInternet.getInternetState(); + if(m_Ipv6InternetState == INTERNET_CAPTIVE_PORTAL) + m_captiveURI = testInternet.getCaptivePortal(); }; + + // Start threads for IPv4 and IPv6 checks std::thread ipv4thread(curlCheckThrdIpv4); std::thread ipv6thread(curlCheckThrdIpv6); + // Wait for both threads to finish ipv4thread.join(); ipv6thread.join(); - if(ipV4InternetState == FULLY_CONNECTED) { - ipResolveTyp = NSM_IPRESOLVE_V4; - currentInternetState = ipV4InternetState; - NMLOG_INFO("connectivity monitor default ip resolve IPV4"); - } - else if(ipV6InternetState == FULLY_CONNECTED) { - ipResolveTyp = NSM_IPRESOLVE_V6; - currentInternetState = ipV6InternetState; - NMLOG_INFO("connectivity monitor default ip resolve IPV6"); - } - else /* not changing ip resolve type */ - currentInternetState = ipV4InternetState; - } - else /* IPV4 or IPV6 based on default values */ - { - TestConnectivity testInternet(getConnectivityMonitorEndpoints(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, - NMCONNECTIVITY_CURL_HEAD_REQUEST, ipResolveTyp); - currentInternetState = testInternet.getInternetState(); - if(ipResolveTyp == NSM_IPRESOLVE_V4) - m_Ipv4InternetState = currentInternetState; - else if(ipResolveTyp == NSM_IPRESOLVE_V6) - m_Ipv6InternetState = currentInternetState; - } - if (currentInternetState == NO_INTERNET) - { - if(m_InternetState == FULLY_CONNECTED && notifyPreRetry < NMCONNECTIVITY_NO_INTERNET_RETRY_COUNT) - { - /* it will prevent posting notification */ - currentInternetState = m_InternetState; - TempInterval = 5; - NMLOG_INFO("No internet retrying connection check %d ...", notifyPreRetry); - notifyPreRetry++; - /* no internet state retry do it in ipv4 and ipv6 sepratly in two thread */ - ipResolveTyp = NSM_IPRESOLVE_WHATEVER; + // Determine the current internet state based on the results + if (m_Ipv4InternetState == INTERNET_NOT_AVAILABLE && m_Ipv6InternetState == INTERNET_NOT_AVAILABLE) { + currentInternetState = INTERNET_NOT_AVAILABLE; + if (InitialRetryCount == 0) + m_notify = true; + InitialRetryCount = 1; // continue same check for 5 sec + } else { + if (m_Ipv4InternetState == INTERNET_FULLY_CONNECTED || m_Ipv6InternetState == INTERNET_FULLY_CONNECTED) + { + currentInternetState = INTERNET_FULLY_CONNECTED; + m_ipversion = (m_Ipv4InternetState == INTERNET_FULLY_CONNECTED) ? IP_ADDRESS_V4 : IP_ADDRESS_V6; + } + else if (m_Ipv4InternetState == INTERNET_CAPTIVE_PORTAL || m_Ipv6InternetState == INTERNET_CAPTIVE_PORTAL) + { + currentInternetState = INTERNET_CAPTIVE_PORTAL; + m_ipversion = (m_Ipv4InternetState == INTERNET_CAPTIVE_PORTAL) ? IP_ADDRESS_V4 : IP_ADDRESS_V6; + } else if (m_Ipv4InternetState == INTERNET_LIMITED || m_Ipv6InternetState == INTERNET_LIMITED) { + currentInternetState = INTERNET_LIMITED; + m_ipversion = (m_Ipv4InternetState == INTERNET_LIMITED) ? IP_ADDRESS_V4 : IP_ADDRESS_V6; + } else { + currentInternetState = INTERNET_NOT_AVAILABLE; + m_ipversion = IP_ADDRESS_V4; + } + + if (InitialRetryCount == 0) + m_notify = true; + + if (currentInternetState != m_InternetState) { + NMLOG_DEBUG("initial connectivity state change %s", getInternetStateString(m_InternetState)); + m_InternetState = currentInternetState; + InitialRetryCount = 1; // reset retry count to get continuous 3 same state + } + InitialRetryCount++; } - else - { - notifyPreRetry = 1; - TempInterval = continuousMonitorTimeout.load(); + + if (InitialRetryCount > NM_CONNECTIVITY_MONITOR_RETRY_COUNT) { + m_switchToInitial = false; + m_notify = true; + InitialRetryCount = 0; + IdealRetryCount = 0; } } + // Ideal case monitoring else { - notifyPreRetry = 1; - TempInterval = continuousMonitorTimeout.load(); - } - - if(m_InternetState != currentInternetState) - { - /* Notify Internet state change */ - notifyInternetStatusChangedEvent(currentInternetState); - } - - //NMLOG_INFO("icm %d, ccm %d", doConnectivityMonitor.load(), doContinuousMonitor.load()); - if(!doContinuousMonitor) - break; - /* wait for next interval */ - std::unique_lock lock(connMutex); - if (cvContinuousMonitor.wait_for(lock, std::chrono::seconds(TempInterval)) != std::cv_status::timeout) - NMLOG_INFO("continous connectivity monitor recieved signal. skping %d sec interval", TempInterval); + timeoutInSec = NMCONNECTIVITY_MONITOR_RETRY_INTERVAL; + InitialRetryCount = 0; - } while(doContinuousMonitor); - - m_Ipv4InternetState = nsm_internetState::UNKNOWN; - m_Ipv6InternetState = nsm_internetState::UNKNOWN; - NMLOG_DEBUG("continous connectivity monitor exit"); - } + TestConnectivity testInternet(m_endpoint(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, + NMCONNECTIVITY_CURL_HEAD_REQUEST, m_ipversion); + currentInternetState = testInternet.getInternetState(); - void ConnectivityMonitor::connectivityMonitorFunction() - { - int TempInterval = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; - std::mutex connMutex; - bool notifyNow = true; - int notifyPreRetry = 1; - nsm_internetState currentInternetState = nsm_internetState::UNKNOWN; - nsm_internetState tempInternetState = nsm_internetState::UNKNOWN; - - do - { - TestConnectivity testInternet(getConnectivityMonitorEndpoints(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, - NMCONNECTIVITY_CURL_GET_REQUEST, NSM_IPRESOLVE_WHATEVER); - currentInternetState = testInternet.getInternetState(); - if(currentInternetState == CAPTIVE_PORTAL) - { - /* set to every 30 sec interval */ - TempInterval = NMCONNECTIVITY_CONN_MONITOR_RETRY_INTERVAL; - } - else if(currentInternetState == LIMITED_INTERNET) - { - TempInterval = NMCONNECTIVITY_CONN_MONITOR_RETRY_INTERVAL; - } - else // fullyconnect / noInternet - { - if(notifyPreRetry <= NMCONNECTIVITY_CONN_MONITOR_RETRY_COUNT - 1) - { - if(tempInternetState != currentInternetState ) // check for continous same state - { - tempInternetState = currentInternetState; - notifyPreRetry = 1; - NMLOG_INFO("Connectivity check retrying %d ...", notifyPreRetry); - } - else - { - notifyPreRetry++; - NMLOG_INFO("Connectivity check retrying %d ...", notifyPreRetry); - } + if (currentInternetState == INTERNET_CAPTIVE_PORTAL) // if captive portal found copy the URL + m_captiveURI = testInternet.getCaptivePortal(); - if(m_InternetState != nsm_internetState::UNKNOWN) - currentInternetState = m_InternetState; - TempInterval = 5; - } - else if(tempInternetState != currentInternetState) // last state have change + if (currentInternetState != m_InternetState) { - tempInternetState = currentInternetState; - notifyPreRetry = 1; - TempInterval = 5; - NMLOG_INFO("Connectivity check retrying %d ...", notifyPreRetry); - } - else - { - if(currentInternetState == FULLY_CONNECTED) - { - doConnectivityMonitor = false; // self exit - notifyNow = true; // post current state when retry complete - } - else if(_instance != nullptr && (_instance->m_ethConnected | _instance->m_wlanConnected)) + if (currentInternetState == INTERNET_NOT_AVAILABLE && m_InternetState == INTERNET_FULLY_CONNECTED) { - /* interface is connected and still no internet, continue check every 30 sec */ - TempInterval = NMCONNECTIVITY_CONN_MONITOR_RETRY_INTERVAL; - /* notify if retry completed and state stil no internet state */ - if(notifyPreRetry == NMCONNECTIVITY_CONN_MONITOR_RETRY_COUNT) + DnsResolver dnsResolver(getConnectivityMonitorEndpoints()[0], m_ipversion, testInternet.getCurlError() ); // only first endpoint with specific ipversion + if (dnsResolver()) { + NMLOG_INFO("DNS resolved, success !!!"); + IdealRetryCount = 0; + currentInternetState = INTERNET_FULLY_CONNECTED; + } + else { - notifyPreRetry++; - notifyNow = true; + NMLOG_WARNING("DNS resolve failed !!!"); + timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; // retry in 5 sec + IdealRetryCount++; + if (IdealRetryCount >= NM_CONNECTIVITY_MONITOR_RETRY_COUNT) { + IdealRetryCount = 0; + m_InternetState = INTERNET_NOT_AVAILABLE; + m_Ipv4InternetState = INTERNET_NOT_AVAILABLE; + m_Ipv6InternetState = INTERNET_NOT_AVAILABLE; // reset all states to NO_INTERNET + currentInternetState = INTERNET_NOT_AVAILABLE; + m_switchToInitial = true; // switch to initial check after 3 retries + InitialRetryCount = 1; // reset initial retry count it will not post the event + m_notify = true; + NMLOG_DEBUG("No internet retrying completed notifying !!!"); + } else { + NMLOG_INFO("No internet retrying connection check %d ...", IdealRetryCount); + } } + } else { + // a state change happened but it is not fully connected to no internet + // switch to initial check to get the correct state + m_switchToInitial = true; + InitialRetryCount = 0; + IdealRetryCount = 0; + timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; // retry in 5 sec + + if (m_ipversion == IP_ADDRESS_V4) + m_Ipv4InternetState = currentInternetState; + else if (m_ipversion == IP_ADDRESS_V6) + m_Ipv6InternetState = currentInternetState; + else + m_InternetState = currentInternetState; } - else // no interface connected - { - doConnectivityMonitor = false; - notifyNow = true; - } + } else { // ideal case no change in network state + IdealRetryCount = 0; + m_InternetState = currentInternetState; } } - if(m_InternetState != currentInternetState || notifyNow) - { - notifyNow = false; - notifyInternetStatusChangedEvent(currentInternetState); + if (m_notify) { + m_InternetState = currentInternetState; + notifyInternetStatusChangedEvent(m_InternetState); + m_notify = false; } - if(!doConnectivityMonitor) + if (!m_cmRunning) break; - /* wait for next interval */ - std::unique_lock lock(connMutex); - if (cvConnectivityMonitor.wait_for(lock, std::chrono::seconds(TempInterval)) != std::cv_status::timeout) { - NMLOG_INFO("connectivity monitor recieved signal. skping %d sec interval", TempInterval); - notifyPreRetry = 1; - notifyNow = true; // new signal came should notify in next check - } - - } while(doConnectivityMonitor); - if(!doContinuousMonitor) - m_InternetState = nsm_internetState::UNKNOWN; // no continous monitor running reset to unknow - NMLOG_DEBUG("initial connectivity monitor exit"); + // Wait for next interval + std::unique_lock lock(m_cmMutex); + if (m_cmCv.wait_for(lock, std::chrono::seconds(timeoutInSec)) != std::cv_status::timeout) { + NMLOG_INFO("connectivity monitor received signal. skipping %d sec interval", timeoutInSec); + } + } } } // namespace Plugin diff --git a/NetworkManagerConnectivity.h b/NetworkManagerConnectivity.h index e9840035..38e12ebb 100644 --- a/NetworkManagerConnectivity.h +++ b/NetworkManagerConnectivity.h @@ -19,35 +19,16 @@ #pragma once -#include #include #include #include -#include -#include -#include #include #include #include #include #include -#include -#include -enum nsm_ipversion -{ - NSM_IPRESOLVE_WHATEVER = 0, /* default, resolves addresses to all IP*/ - NSM_IPRESOLVE_V4 = 1, /* resolve to IPv4 addresses */ - NSM_IPRESOLVE_V6 = 2 /* resolve to IPv6 addresses */ -}; - -enum nsm_internetState { - NO_INTERNET, - LIMITED_INTERNET, - CAPTIVE_PORTAL, - FULLY_CONNECTED, - UNKNOWN, -}; +#include "INetworkManager.h" enum nsm_connectivity_httpcode { HttpStatus_response_error = 99, @@ -64,30 +45,50 @@ enum nsm_connectivity_httpcode { #define NMCONNECTIVITY_CURL_HEAD_REQUEST true #define NMCONNECTIVITY_CURL_GET_REQUEST false - -#define NMCONNECTIVITY_MONITOR_DEFAULT_INTERVAL 60 // sec -#define NMCONNECTIVITY_MONITOR_MIN_INTERVAL 5 // sec -#define NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS 5000 // ms -#define NMCONNECTIVITY_NO_INTERNET_RETRY_COUNT 4 // 4 retry -#define NMCONNECTIVITY_CONN_MONITOR_RETRY_COUNT 3 // 3 retry -#define NMCONNECTIVITY_CAPTIVE_MONITOR_INTERVAL 30 // sec -#define NMCONNECTIVITY_CONN_MONITOR_RETRY_INTERVAL 30 // sec +#define NMCONNECTIVITY_MONITOR_CACHE_FILE "/tmp/nm.plugin.endpoints" +#define NMCONNECTIVITY_MONITOR_MIN_INTERVAL 5 // sec +#define NMCONNECTIVITY_MONITOR_RETRY_INTERVAL 30 // sec +#define NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS 5000 // ms +#define NM_CONNECTIVITY_MONITOR_RETRY_COUNT 3 // 3 retry namespace WPEFramework { namespace Plugin { - /* save user specific endponint in to a chache file and load form the file if monitorEndpoints are empty case wpeframework restared */ - class EndpointCache { + + class DnsResolver + { public: - bool isEndpointCashFileExist(); - void writeEnpointsToFile(const std::vector& endpoints); - std::vector readEnpointsFromFile(); + DnsResolver(std::string url, Exchange::INetworkManager::IPVersion ipversion, int curlErrorCode); + ~DnsResolver(){}; + bool operator()() { return (ipv6Resolved || ipv4Resolved);} - EndpointCache() : CachefilePath("/tmp/nm.plugin.endpoints") {} - ~EndpointCache(){} private: - std::string CachefilePath; + std::string m_domain{}; + bool ipv4Resolved = false; + bool ipv6Resolved = false; + std::string convertUrIToDomainName(std::string& url); + bool resolveIP(std::string& uri, Exchange::INetworkManager::IPVersion& ipversion); + }; + + /* + * Save user specific endpoint into a cache file and load from the file + * if endpoints are empty in case plugin is restarted. + */ + class EndpointManager { + public: + EndpointManager(); + ~EndpointManager() {} + void writeEndpointsToFile(const std::vector& endpoints); + std::vector readEndpointsFromFile(); + void setConnectivityMonitorEndpoints(const std::vector& endpoints); + std::vector getConnectivityMonitorEndpoints(); + std::vector operator()() { return getConnectivityMonitorEndpoints(); } + + private: + std::string m_CachefilePath; + std::vector m_Endpoints; + std::mutex m_endpointMutex; }; class TestConnectivity @@ -96,15 +97,17 @@ namespace WPEFramework const TestConnectivity& operator=(const TestConnectivity&) = delete; public: - TestConnectivity(const std::vector& endpoints, long timeout_ms = 2000, bool = true, nsm_ipversion ipversion = NSM_IPRESOLVE_WHATEVER); + TestConnectivity(const std::vector& endpoints, long timeout_ms, bool headReq, Exchange::INetworkManager::IPVersion ipversion); ~TestConnectivity(){} std::string getCaptivePortal() {return captivePortalURI;} - nsm_internetState getInternetState(){return internetSate;} + Exchange::INetworkManager::InternetStatus getInternetState(){return internetSate;} + int getCurlError(){return curlErrorCode;} private: - nsm_internetState checkCurlResponse(const std::vector& endpoints, long timeout_ms, bool headReq, nsm_ipversion ipversion); - nsm_internetState checkInternetStateFromResponseCode(const std::vector& responses); + Exchange::INetworkManager::InternetStatus checkCurlResponse(const std::vector& endpoints, long timeout_ms, bool headReq, Exchange::INetworkManager::IPVersion ipversion); + Exchange::INetworkManager::InternetStatus checkInternetStateFromResponseCode(const std::vector& responses); std::string captivePortalURI; - nsm_internetState internetSate; + Exchange::INetworkManager::InternetStatus internetSate; + int curlErrorCode = 0; }; class ConnectivityMonitor @@ -112,37 +115,33 @@ namespace WPEFramework public: ConnectivityMonitor(); ~ConnectivityMonitor(); - bool startContinuousConnectivityMonitor(int timeoutInSeconds); - bool stopContinuousConnectivityMonitor(); + bool stopConnectivityMonitor(); bool startConnectivityMonitor(); + bool switchToInitialCheck(); void setConnectivityMonitorEndpoints(const std::vector &endpoints); std::vector getConnectivityMonitorEndpoints(); - bool isConnectedToInternet(nsm_ipversion ipversion); - nsm_internetState getInternetState(nsm_ipversion& ipversion); + Exchange::INetworkManager::InternetStatus getInternetState(Exchange::INetworkManager::IPVersion& ipversion, bool ipVersionNotSpecified = false); std::string getCaptivePortalURI(); private: ConnectivityMonitor(const ConnectivityMonitor&) = delete; ConnectivityMonitor& operator=(const ConnectivityMonitor&) = delete; void connectivityMonitorFunction(); - void notifyInternetStatusChangedEvent(nsm_internetState newState); + void notifyInternetStatusChangedEvent(Exchange::INetworkManager::InternetStatus newState); /* connectivity monitor */ - std::thread connectivityMonitorThrd; - std::condition_variable cvConnectivityMonitor; - std::atomic continuousMonitorTimeout; - std::atomic doConnectivityMonitor; - std::vector connectivityMonitorEndpt; - /*continuous connectivity monitor */ - std::atomic doContinuousMonitor; - std::thread continuousMonitorThrd; - std::condition_variable cvContinuousMonitor; - void continuousMonitorFunction(); - - EndpointCache endpointCache; - std::mutex endpointMutex; - std::atomic m_InternetState; - std::atomic m_Ipv4InternetState; - std::atomic m_Ipv6InternetState; + std::thread m_cmThrdID; + std::atomic m_cmRunning; + std::condition_variable m_cmCv; + std::mutex m_cmMutex; + std::atomic m_notify; + std::atomic m_switchToInitial; + std::string m_captiveURI; + std::atomic m_InternetState; // IPv4 or IPv6 + std::atomic m_Ipv4InternetState; // IPv4 + std::atomic m_Ipv6InternetState; // IPv6 + std::atomic m_ipversion; // IPv6 + /* manages endpoints */ + EndpointManager m_endpoint; }; } // namespace Plugin } // namespace WPEFramework diff --git a/NetworkManagerImplementation.cpp b/NetworkManagerImplementation.cpp index 5719c718..ee6b3687 100644 --- a/NetworkManagerImplementation.cpp +++ b/NetworkManagerImplementation.cpp @@ -53,11 +53,11 @@ namespace WPEFramework NetworkManagerImplementation::~NetworkManagerImplementation() { LOG_ENTRY_FUNCTION(); + if(m_registrationThread.joinable()) { m_registrationThread.join(); } - connectivityMonitor.stopContinuousConnectivityMonitor(); } /** @@ -244,27 +244,20 @@ namespace WPEFramework } /* @brief Get Internet Connectivty Status */ - uint32_t NetworkManagerImplementation::IsConnectedToInternet(string &ipversion /* @in */, InternetStatus &result /* @out */) + uint32_t NetworkManagerImplementation::IsConnectedToInternet(string &ipversion /* @inout */, InternetStatus &result /* @out */) { LOG_ENTRY_FUNCTION(); - nsm_internetState isconnected; - nsm_ipversion tmpVersion = NSM_IPRESOLVE_WHATEVER; + Exchange::INetworkManager::IPVersion curlIPversion = Exchange::INetworkManager::IP_ADDRESS_V4; + bool ipVersionNotSpecified = false; if(0 == strcasecmp("IPv4", ipversion.c_str())) - tmpVersion = NSM_IPRESOLVE_V4; + curlIPversion = Exchange::INetworkManager::IP_ADDRESS_V4; else if(0 == strcasecmp("IPv6", ipversion.c_str())) - tmpVersion = NSM_IPRESOLVE_V6; - - isconnected = connectivityMonitor.getInternetState(tmpVersion); - if (FULLY_CONNECTED == isconnected) - result = INTERNET_FULLY_CONNECTED; - else if (CAPTIVE_PORTAL == isconnected) - result = INTERNET_CAPTIVE_PORTAL; - else if (LIMITED_INTERNET == isconnected) - result = INTERNET_LIMITED; + curlIPversion = Exchange::INetworkManager::IP_ADDRESS_V6; else - result = INTERNET_NOT_AVAILABLE; + ipVersionNotSpecified = true; - if (NSM_IPRESOLVE_V6 == tmpVersion) + result = connectivityMonitor.getInternetState(curlIPversion, ipVersionNotSpecified); + if (Exchange::INetworkManager::IP_ADDRESS_V6 == curlIPversion) ipversion = "IPv6"; else ipversion = "IPv4"; @@ -280,26 +273,6 @@ namespace WPEFramework return Core::ERROR_NONE; } - /* @brief Start The Internet Connectivity Monitoring */ - uint32_t NetworkManagerImplementation::StartConnectivityMonitoring(const uint32_t interval/* @in */) - { - LOG_ENTRY_FUNCTION(); - if (connectivityMonitor.startContinuousConnectivityMonitor(interval)) - return Core::ERROR_NONE; - else - return Core::ERROR_GENERAL; - } - - /* @brief Stop The Internet Connectivity Monitoring */ - uint32_t NetworkManagerImplementation::StopConnectivityMonitoring(void) const - { - LOG_ENTRY_FUNCTION(); - if (connectivityMonitor.stopContinuousConnectivityMonitor()) - return Core::ERROR_NONE; - else - return Core::ERROR_GENERAL; - } - /* @brief Get the Public IP used for external world communication */ uint32_t NetworkManagerImplementation::GetPublicIP (string& interface /* @inout */, string &ipversion /* @inout */, string& ipaddress /* @out */) { @@ -614,8 +587,7 @@ namespace WPEFramework m_ethConnected = false; else if(interface == "wlan0") m_wlanConnected = false; - - connectivityMonitor.startConnectivityMonitor(); + connectivityMonitor.switchToInitialCheck(); } /* Only the Ethernet connection status is changing here. The WiFi status is updated in the WiFi state callback. */ @@ -653,6 +625,7 @@ namespace WPEFramework { LOG_ENTRY_FUNCTION(); if (Exchange::INetworkManager::IP_ACQUIRED == status) { + // Switch the connectivity monitor to initial check // if ipaddress is aquired means there should be interface connected if(interface == "eth0") m_ethConnected = true; @@ -665,9 +638,7 @@ namespace WPEFramework else m_defaultInterface = interface; - // Start the connectivity monitor with 'true' to indicate the interface is up. - // The monitor will conntinoue even after no internet retry completed, Exit when fully connectd. - connectivityMonitor.startConnectivityMonitor(); + connectivityMonitor.switchToInitialCheck(); } _notificationLock.Lock(); diff --git a/NetworkManagerImplementation.h b/NetworkManagerImplementation.h index 0c1d0645..16fd2f79 100644 --- a/NetworkManagerImplementation.h +++ b/NetworkManagerImplementation.h @@ -224,11 +224,6 @@ namespace WPEFramework /* @brief Get Authentication URL if the device is behind Captive Portal */ uint32_t GetCaptivePortalURI(string &endpoints/* @out */) const override; - /* @brief Start The Internet Connectivity Monitoring */ - uint32_t StartConnectivityMonitoring(const uint32_t interval/* @in */) override; - /* @brief Stop The Internet Connectivity Monitoring */ - uint32_t StopConnectivityMonitoring(void) const override; - /* @brief Get the Public IP used for external world communication */ uint32_t GetPublicIP (string& interface /* @inout */, string &ipversion /* @inout */, string& ipaddress /* @out */) override; diff --git a/NetworkManagerJsonRpc.cpp b/NetworkManagerJsonRpc.cpp index f1269af1..55be805b 100644 --- a/NetworkManagerJsonRpc.cpp +++ b/NetworkManagerJsonRpc.cpp @@ -67,8 +67,6 @@ namespace WPEFramework Register("SetConnectivityTestEndpoints", &NetworkManager::SetConnectivityTestEndpoints, this); Register("IsConnectedToInternet", &NetworkManager::IsConnectedToInternet, this); Register("GetCaptivePortalURI", &NetworkManager::GetCaptivePortalURI, this); - Register("StartConnectivityMonitoring", &NetworkManager::StartConnectivityMonitoring, this); - Register("StopConnectivityMonitoring", &NetworkManager::StopConnectivityMonitoring, this); Register("GetPublicIP", &NetworkManager::GetPublicIP, this); Register("Ping", &NetworkManager::Ping, this); Register("Trace", &NetworkManager::Trace, this); @@ -106,8 +104,6 @@ namespace WPEFramework Unregister("SetConnectivityTestEndpoints"); Unregister("IsConnectedToInternet"); Unregister("GetCaptivePortalURI"); - Unregister("StartConnectivityMonitoring"); - Unregister("StopConnectivityMonitoring"); Unregister("GetPublicIP"); Unregister("Ping"); Unregister("Trace"); @@ -503,34 +499,6 @@ namespace WPEFramework returnJson(rc); } - uint32_t NetworkManager::StartConnectivityMonitoring(const JsonObject& parameters, JsonObject& response) - { - LOG_INPARAM(); - uint32_t rc = Core::ERROR_GENERAL; - uint32_t interval = parameters["interval"].Number(); - - NMLOG_DEBUG("connectivity interval = %d", interval); - if (_networkManager) - rc = _networkManager->StartConnectivityMonitoring(interval); - else - rc = Core::ERROR_UNAVAILABLE; - - returnJson(rc); - } - - uint32_t NetworkManager::StopConnectivityMonitoring(const JsonObject& parameters, JsonObject& response) - { - LOG_INPARAM(); - uint32_t rc = Core::ERROR_GENERAL; - - if (_networkManager) - rc = _networkManager->StopConnectivityMonitoring(); - else - rc = Core::ERROR_UNAVAILABLE; - - returnJson(rc); - } - uint32_t NetworkManager::GetPublicIP(const JsonObject& parameters, JsonObject& response) { LOG_INPARAM(); diff --git a/NetworkManagerRDKProxy.cpp b/NetworkManagerRDKProxy.cpp index bdb16ed8..d4f17630 100644 --- a/NetworkManagerRDKProxy.cpp +++ b/NetworkManagerRDKProxy.cpp @@ -689,7 +689,6 @@ namespace WPEFramework */ getInitialConnectionState(); } - } uint32_t NetworkManagerImplementation::GetAvailableInterfaces (Exchange::INetworkManager::IInterfaceDetailsIterator*& interfacesItr/* @out */) diff --git a/Tests/unit_test/test_NetworkManagerConnectivity.cpp b/Tests/unit_test/test_NetworkManagerConnectivity.cpp index 1b59920f..2f6cf144 100644 --- a/Tests/unit_test/test_NetworkManagerConnectivity.cpp +++ b/Tests/unit_test/test_NetworkManagerConnectivity.cpp @@ -29,77 +29,11 @@ class ConnectivityMonitorTest : public ::testing::Test { WPEFramework::Plugin::ConnectivityMonitor cm; }; -TEST_F(ConnectivityMonitorTest, StartContinuousMonitor_Success) { - int timeout = 30; - bool result = cm.startContinuousConnectivityMonitor(timeout); - EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, StartContinuousMonitor_FailureNegativeTimeout) { - int timeout = -1; - bool result = cm.startContinuousConnectivityMonitor(timeout); - EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, StartMonitorWithTimeoutLessThanMinimum) { - int timeout = 3; - bool result = cm.startContinuousConnectivityMonitor(timeout); - EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, MonitorFailsToStart) { - int timeout = 0; - bool result = cm.startContinuousConnectivityMonitor(timeout); - EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, StopContinuousMonitor_WhenStarted) { - int timeout = 30; - cm.startContinuousConnectivityMonitor(timeout); - bool result = cm.stopContinuousConnectivityMonitor(); - EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, StopContinuousMonitor_WhenNotStarted) { - bool result = cm.stopContinuousConnectivityMonitor(); - EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, StopContinuousMonitor_AfterMultipleStartsAndStops) { - int timeout = 30; - cm.startContinuousConnectivityMonitor(timeout); - bool result = cm.stopContinuousConnectivityMonitor(); - EXPECT_TRUE(result); - - cm.startContinuousConnectivityMonitor(timeout); - result = cm.stopContinuousConnectivityMonitor(); - EXPECT_TRUE(result); - - cm.startContinuousConnectivityMonitor(timeout); - result = cm.stopContinuousConnectivityMonitor(); - EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, StopContinuousMonitor_LongRunningMonitor) { - int timeout = 1000; - cm.startContinuousConnectivityMonitor(timeout); - std::this_thread::sleep_for(std::chrono::seconds(2)); - - bool result = cm.stopContinuousConnectivityMonitor(); - EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, StartMonitor_WithInterfaceStatus) { +TEST_F(ConnectivityMonitorTest, StartConnectivityMonitor_Success) { bool result = cm.startConnectivityMonitor(); EXPECT_TRUE(result); -} - -TEST_F(ConnectivityMonitorTest, StartMonitor_NotifyIfAlreadyMonitoring) { - bool result = false; result = cm.startConnectivityMonitor(); EXPECT_TRUE(result); - result = cm.startConnectivityMonitor(); - EXPECT_TRUE(result); } TEST_F(ConnectivityMonitorTest, SetEndpoints_Valid) { @@ -108,12 +42,6 @@ TEST_F(ConnectivityMonitorTest, SetEndpoints_Valid) { EXPECT_EQ(cm.getConnectivityMonitorEndpoints(), endpoints); } -TEST_F(ConnectivityMonitorTest, SetEndpoints_EmptyList) { - std::vector endpoints; - cm.setConnectivityMonitorEndpoints(endpoints); - EXPECT_TRUE(cm.getConnectivityMonitorEndpoints().empty()); -} - TEST_F(ConnectivityMonitorTest, SetEndpoints_InvalidShortEndpoints) { std::vector endpoints = {"ab", "htt", "xyz"}; cm.setConnectivityMonitorEndpoints(endpoints); diff --git a/docs/NetworkManagerPlugin.md b/docs/NetworkManagerPlugin.md index 66203f5f..3af6eff5 100644 --- a/docs/NetworkManagerPlugin.md +++ b/docs/NetworkManagerPlugin.md @@ -87,8 +87,6 @@ NetworkManager interface methods: | [SetConnectivityTestEndpoints](#method.SetConnectivityTestEndpoints) | This method used to set up to 5 endpoints for a connectivity test | | [IsConnectedToInternet](#method.IsConnectedToInternet) | Seeks whether the device has internet connectivity | | [GetCaptivePortalURI](#method.GetCaptivePortalURI) | Gets the captive portal URI if connected to any captive portal network | -| [StartConnectivityMonitoring](#method.StartConnectivityMonitoring) | Enable a continuous monitoring of internet connectivity with heart beat interval thats given | -| [StopConnectivityMonitoring](#method.StopConnectivityMonitoring) | Stops the connectivity monitoring | | [GetPublicIP](#method.GetPublicIP) | Gets the internet/public IP Address of the device | | [Ping](#method.Ping) | Pings the specified endpoint with the specified number of packets | | [Trace](#method.Trace) | Traces the specified endpoint with the specified number of packets using `traceroute` | @@ -404,7 +402,7 @@ Gets the current Status of the specified interface. | Name | Type | Description | | :-------- | :-------- | :-------- | | params | object | | -| params.interface | string | Disable the specified interface | +| params.interface | string | An interface, such as `eth0` or `wlan0`, depending upon availability of the given interface | ### Result @@ -686,8 +684,8 @@ This method takes no parameters. | Name | Type | Description | | :-------- | :-------- | :-------- | | result | object | | -| result.endpoints | array | | -| result.endpoints[#] | string | | +| result.endpoints | array | A list of endpoint URLs used | +| result.endpoints[#] | string | The endpoint URL | | result.success | boolean | Whether the request succeeded | ### Example @@ -728,7 +726,7 @@ This method used to set up to 5 endpoints for a connectivity test. Successful co | :-------- | :-------- | :-------- | | params | object | | | params.endpoints | array | A list of endpoints to test | -| params.endpoints[#] | string | | +| params.endpoints[#] | string | The endpoint URL | ### Result @@ -862,94 +860,6 @@ This method takes no parameters. } ``` - -## *StartConnectivityMonitoring [method](#head.Methods)* - -Enable a continuous monitoring of internet connectivity with heart beat interval thats given. If the monitoring is already happening, it will be restarted with new given interval. When the interval is not passed, it will be 60s by default. - -Also see: [onInternetStatusChange](#event.onInternetStatusChange) - -### Parameters - -| Name | Type | Description | -| :-------- | :-------- | :-------- | -| params | object | | -| params?.interval | integer | *(optional)* Interval in sec | - -### Result - -| Name | Type | Description | -| :-------- | :-------- | :-------- | -| result | object | | -| result.success | boolean | Whether the request succeeded | - -### Example - -#### Request - -```json -{ - "jsonrpc": "2.0", - "id": 42, - "method": "org.rdk.NetworkManager.1.StartConnectivityMonitoring", - "params": { - "interval": 30 - } -} -``` - -#### Response - -```json -{ - "jsonrpc": "2.0", - "id": 42, - "result": { - "success": true - } -} -``` - - -## *StopConnectivityMonitoring [method](#head.Methods)* - -Stops the connectivity monitoring. - -### Parameters - -This method takes no parameters. - -### Result - -| Name | Type | Description | -| :-------- | :-------- | :-------- | -| result | object | | -| result.success | boolean | Whether the request succeeded | - -### Example - -#### Request - -```json -{ - "jsonrpc": "2.0", - "id": 42, - "method": "org.rdk.NetworkManager.1.StopConnectivityMonitoring" -} -``` - -#### Response - -```json -{ - "jsonrpc": "2.0", - "id": 42, - "result": { - "success": true - } -} -``` - ## *GetPublicIP [method](#head.Methods)* @@ -1150,7 +1060,7 @@ Also see: [onAvailableSSIDs](#event.onAvailableSSIDs) | params | object | | | params?.frequency | string | *(optional)* The frequency to scan. An empty or `null` value scans all frequencies | | params?.ssids | array | *(optional)* The list of SSIDs to be scanned | -| params?.ssids[#] | string | *(optional)* | +| params?.ssids[#] | string | *(optional)* The SSID to scan | ### Result @@ -1243,8 +1153,8 @@ This method takes no parameters. | Name | Type | Description | | :-------- | :-------- | :-------- | | result | object | | -| result.ssids | array | Known SSIDS | -| result.ssids[#] | string | | +| result.ssids | array | A list of known SSIDs | +| result.ssids[#] | string | The WiFi SSID Name | | result.success | boolean | Whether the request succeeded | ### Example @@ -1284,7 +1194,7 @@ Saves the SSID, passphrase, and security mode for upcoming and future sessions. | Name | Type | Description | | :-------- | :-------- | :-------- | | params | object | | -| params.ssid | string | The paired SSID | +| params.ssid | string | The WiFi SSID Name | | params.passphrase | string | The access point password | | params.security | integer | The security mode. See `getSupportedsecurityModes` | @@ -1305,7 +1215,7 @@ Saves the SSID, passphrase, and security mode for upcoming and future sessions. "id": 42, "method": "org.rdk.NetworkManager.1.AddToKnownSSIDs", "params": { - "ssid": "123412341234", + "ssid": "myHomeSSID", "passphrase": "password", "security": 6 } @@ -1336,7 +1246,7 @@ Also see: [onWiFiStateChange](#event.onWiFiStateChange), [onAddressChange](#even | Name | Type | Description | | :-------- | :-------- | :-------- | | params | object | | -| params.ssid | string | The paired SSID | +| params.ssid | string | The WiFi SSID Name | ### Result @@ -1355,7 +1265,7 @@ Also see: [onWiFiStateChange](#event.onWiFiStateChange), [onAddressChange](#even "id": 42, "method": "org.rdk.NetworkManager.1.RemoveKnownSSID", "params": { - "ssid": "123412341234" + "ssid": "myHomeSSID" } } ``` @@ -1384,7 +1294,7 @@ Also see: [onWiFiStateChange](#event.onWiFiStateChange) | Name | Type | Description | | :-------- | :-------- | :-------- | | params | object | | -| params.ssid | string | The paired SSID | +| params.ssid | string | The WiFi SSID Name | | params.passphrase | string | The access point password | | params.security | integer | The security mode. See `getSupportedsecurityModes` | | params?.ca_cert | string | *(optional)* The ca_cert to be used for EAP | @@ -1415,7 +1325,7 @@ Also see: [onWiFiStateChange](#event.onWiFiStateChange) "id": 42, "method": "org.rdk.NetworkManager.1.WiFiConnect", "params": { - "ssid": "123412341234", + "ssid": "myHomeSSID", "passphrase": "password", "security": 6, "ca_cert": "...", @@ -1500,10 +1410,10 @@ This method takes no parameters. | Name | Type | Description | | :-------- | :-------- | :-------- | | result | object | | -| result.ssid | string | The paired SSID | -| result.bssid | string | The paired BSSID | +| result.ssid | string | The WiFi SSID Name | +| result.bssid | string | The BSSID of given SSID | | result.security | string | The security mode. See the `connect` method | -| result.strength | string | The RSSI value in dBm | +| result.strength | string | The Signal RSSI value in dBm | | result.frequency | string | The supported frequency for this SSID in GHz | | result.rate | string | The physical data rate in Mbps | | result.noise | string | The average noise strength in dBm | @@ -1528,8 +1438,8 @@ This method takes no parameters. "jsonrpc": "2.0", "id": 42, "result": { - "ssid": "123412341234", - "bssid": "ff:ff:ff:ff:ff:ff", + "ssid": "myHomeSSID", + "bssid": "AA:BB:CC:DD:EE:FF", "security": "5", "strength": "-27.000000", "frequency": "2.442000", @@ -1658,8 +1568,8 @@ This method takes no parameters. | Name | Type | Description | | :-------- | :-------- | :-------- | | result | object | | -| result.ssid | string | The paired SSID | -| result.strength | string | The RSSI value in dBm | +| result.ssid | string | The WiFi SSID Name | +| result.strength | string | The Signal RSSI value in dBm | | result.quality | string | Signal strength Quality | | result.success | boolean | Whether the request succeeded | @@ -1682,7 +1592,7 @@ This method takes no parameters. "jsonrpc": "2.0", "id": 42, "result": { - "ssid": "123412341234", + "ssid": "myHomeSSID", "strength": "-27.000000", "quality": "Excellent", "success": true @@ -1974,10 +1884,10 @@ Triggered when scan completes or when scan cancelled. | params | object | | | params.ssids | array | On Available SSID's | | params.ssids[#] | object | | -| params.ssids[#].ssid | string | Ssid | -| params.ssids[#].security | integer | Security | -| params.ssids[#].strength | string | Strength | -| params.ssids[#].frequency | string | Frequency | +| params.ssids[#].ssid | string | Discovered SSID | +| params.ssids[#].security | integer | The security mode. See `getSupportedsecurityModes` | +| params.ssids[#].strength | string | The Signal RSSI value in dBm | +| params.ssids[#].frequency | string | The supported frequency for this SSID in GHz | ### Example @@ -2034,9 +1944,9 @@ Triggered when WIFI connection Signal Strength get changed. | Name | Type | Description | | :-------- | :-------- | :-------- | | params | object | | -| params.ssid | string | Signal Strength changed SSID | -| params.strength | string | Signal Strength | -| params.quality | string | Signal quality | +| params.ssid | string | The WiFi SSID Name | +| params.strength | string | The Signal RSSI value in dBm | +| params.quality | string | Signal strength Quality | ### Example @@ -2045,7 +1955,7 @@ Triggered when WIFI connection Signal Strength get changed. "jsonrpc": "2.0", "method": "client.events.1.onWiFiSignalStrengthChange", "params": { - "ssid": "home-new_123", + "ssid": "myHomeSSID", "strength": "-27.000000", "quality": "Excellent" } From 632de5e6ad9efe54d88532f4a27b9fa558c37319 Mon Sep 17 00:00:00 2001 From: gururaajar <83449026+gururaajar@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:24:04 -0500 Subject: [PATCH 2/3] RDKEMW-1271 - Address coverity issues (#80) * RDKEMW-1271 - Address coverity issues Reason for change: For addressing the network manager coverity issues Test Procedure: Build and verified with curl commands Risks: Low Priority: P1 Signed-off-by: Gururaaja ESR --- NetworkManagerConnectivity.cpp | 27 ++++++++++++++------------- NetworkManagerConnectivity.h | 10 ++++++++++ NetworkManagerLogger.cpp | 9 --------- NetworkManagerRDKProxy.cpp | 7 +++---- NetworkManagerStunClient.cpp | 4 ++-- WiFiSignalStrengthMonitor.h | 2 +- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/NetworkManagerConnectivity.cpp b/NetworkManagerConnectivity.cpp index 8140b2e9..39a19a4d 100644 --- a/NetworkManagerConnectivity.cpp +++ b/NetworkManagerConnectivity.cpp @@ -17,12 +17,10 @@ * limitations under the License. **/ -#include #include #include #include #include -#include #include #include @@ -106,7 +104,7 @@ namespace WPEFramework } m_Endpoints.clear(); - for (auto endpoint : endpoints) { + for (const auto &endpoint : endpoints) { if(!endpoint.empty() && endpoint.size() > 3) m_Endpoints.push_back(endpoint.c_str()); else @@ -293,31 +291,33 @@ namespace WPEFramework NMLOG_ERROR("endpoint = <%s> curl_easy_init returned NULL", endpoint.c_str()); continue; } - curl_easy_setopt(curl_easy_handle, CURLOPT_URL, endpoint.c_str()); - curl_easy_setopt(curl_easy_handle, CURLOPT_PRIVATE, endpoint.c_str()); + curlSetOpt(curl_easy_handle, CURLOPT_URL, endpoint.c_str()); + curlSetOpt(curl_easy_handle, CURLOPT_PRIVATE, endpoint.c_str()); /* set our custom set of headers */ - curl_easy_setopt(curl_easy_handle, CURLOPT_HTTPHEADER, chunk); - curl_easy_setopt(curl_easy_handle, CURLOPT_USERAGENT, "RDKCaptiveCheck/1.0"); + curlSetOpt(curl_easy_handle, CURLOPT_HTTPHEADER, chunk); + curlSetOpt(curl_easy_handle, CURLOPT_USERAGENT, "RDKCaptiveCheck/1.0"); if(!headReq) { /* HTTPGET request added insted of HTTPHEAD request fix for DELIA-61526 */ - curl_easy_setopt(curl_easy_handle, CURLOPT_HTTPGET, 1L); + curlSetOpt(curl_easy_handle, CURLOPT_HTTPGET, 1L); } - curl_easy_setopt(curl_easy_handle, CURLOPT_WRITEFUNCTION, writeFunction); - curl_easy_setopt(curl_easy_handle, CURLOPT_TIMEOUT_MS, deadline - current_time()); + curlSetOpt(curl_easy_handle, CURLOPT_WRITEFUNCTION, writeFunction); + curlSetOpt(curl_easy_handle, CURLOPT_TIMEOUT_MS, deadline - current_time()); if (IP_ADDRESS_V4 == ipversion) { - curl_easy_setopt(curl_easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + curlSetOpt(curl_easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); NMLOG_DEBUG("curlopt ipversion = IPv4 reqtyp = %s", headReq? "HEAD":"GET"); } else if (IP_ADDRESS_V6 == ipversion) { - curl_easy_setopt(curl_easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); + curlSetOpt(curl_easy_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); NMLOG_DEBUG("curlopt ipversion = IPv6 reqtyp = %s", headReq? "HEAD":"GET"); } else NMLOG_DEBUG("curlopt ipversion = whatever reqtyp = %s", headReq? "HEAD":"GET"); if(curlVerboseEnabled()) - curl_easy_setopt(curl_easy_handle, CURLOPT_VERBOSE, 1L); + { + curlSetOpt(curl_easy_handle, CURLOPT_VERBOSE, 1L); + } if (CURLM_OK != (mc = curl_multi_add_handle(curl_multi_handle, curl_easy_handle))) { NMLOG_ERROR("endpoint = <%s> curl_multi_add_handle returned %d (%s)", endpoint.c_str(), mc, curl_multi_strerror(mc)); @@ -472,6 +472,7 @@ namespace WPEFramework m_cmRunning = false; m_notify = true; m_InternetState = INTERNET_UNKNOWN; + m_ipversion = IP_ADDRESS_V4; m_Ipv4InternetState = INTERNET_UNKNOWN; m_Ipv6InternetState = INTERNET_UNKNOWN; startConnectivityMonitor(); diff --git a/NetworkManagerConnectivity.h b/NetworkManagerConnectivity.h index 38e12ebb..6a9f7f19 100644 --- a/NetworkManagerConnectivity.h +++ b/NetworkManagerConnectivity.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "INetworkManager.h" @@ -108,6 +109,15 @@ namespace WPEFramework std::string captivePortalURI; Exchange::INetworkManager::InternetStatus internetSate; int curlErrorCode = 0; + template + void curlSetOpt(CURL *curl, CURLoption option, curlValue value) + { + CURLcode response = curl_easy_setopt(curl, option, value); + if (response != CURLE_OK) { + NMLOG_ERROR("Error setting option %d with error: %s", option, curl_easy_strerror(response)); + } + return; + } }; class ConnectivityMonitor diff --git a/NetworkManagerLogger.cpp b/NetworkManagerLogger.cpp index 5dc6dfe5..342a140a 100644 --- a/NetworkManagerLogger.cpp +++ b/NetworkManagerLogger.cpp @@ -75,15 +75,6 @@ namespace NetworkManagerLogger { return t; } - const char* methodName(const std::string& prettyFunction) - { - size_t colons = prettyFunction.find("::"); - size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1; - size_t end = prettyFunction.rfind("(") - begin; - - return prettyFunction.substr(begin,end).c_str(); - } - void Init() { #ifdef USE_RDK_LOGGER diff --git a/NetworkManagerRDKProxy.cpp b/NetworkManagerRDKProxy.cpp index d4f17630..4e43c341 100644 --- a/NetworkManagerRDKProxy.cpp +++ b/NetworkManagerRDKProxy.cpp @@ -499,9 +499,9 @@ namespace WPEFramework 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") - oldInterface == ""; /* assigning "null" if the interface is not eth0 or wlan0 */ + oldInterface = ""; /* assigning "null" if the interface is not eth0 or wlan0 */ if(newInterface != "eth0" || newInterface != "wlan0") - newInterface == ""; /* assigning "null" if the interface is not eth0 or wlan0 */ + newInterface = ""; /* assigning "null" if the interface is not eth0 or wlan0 */ ::_instance->ReportActiveInterfaceChange(oldInterface, newInterface); break; @@ -922,6 +922,7 @@ namespace WPEFramework address.prefix = std::atoi(iarmData.netmask); } + rc = Core::ERROR_NONE; /* Return the default interface information */ if (interface.empty()) { @@ -933,8 +934,6 @@ namespace WPEFramework else rc = Core::ERROR_BAD_REQUEST; } - - rc = Core::ERROR_NONE; } else { diff --git a/NetworkManagerStunClient.cpp b/NetworkManagerStunClient.cpp index cb656295..05ac8f4a 100644 --- a/NetworkManagerStunClient.cpp +++ b/NetworkManagerStunClient.cpp @@ -370,7 +370,7 @@ bool client::bind( auto time_in_cache = std::chrono::duration_cast( std::chrono::steady_clock::now() - m_last_cache_time); - NMLOG_DEBUG("client::bind cache time=%ld", time_in_cache.count()); + NMLOG_DEBUG("client::bind cache time=%lld", time_in_cache.count()); if(time_in_cache.count() < m_cache_timeout) { @@ -668,7 +668,7 @@ std::unique_ptr client::send_binding_request(std::chrono::milliseconds std::unique_ptr client::send_binding_request(sockaddr_storage const & addr, std::chrono::milliseconds wait_time) { - NMLOG_DEBUG("sending binding request with wait time:%ld ms", wait_time.count()); + NMLOG_DEBUG("sending binding request with wait time:%lld ms", wait_time.count()); this->create_udp_socket(addr.ss_family); std::unique_ptr binding_request(message_factory::create_binding_request()); std::unique_ptr binding_response(this->send_message(addr, *binding_request, wait_time)); diff --git a/WiFiSignalStrengthMonitor.h b/WiFiSignalStrengthMonitor.h index c3772f2d..4ce84e7c 100644 --- a/WiFiSignalStrengthMonitor.h +++ b/WiFiSignalStrengthMonitor.h @@ -35,7 +35,7 @@ namespace WPEFramework class WiFiSignalStrengthMonitor { public: - WiFiSignalStrengthMonitor():isRunning(false) {} + WiFiSignalStrengthMonitor():isRunning(false), stopThread(false) {} ~WiFiSignalStrengthMonitor(){ NMLOG_INFO("~WiFiSignalStrengthMonitor"); } void startWiFiSignalStrengthMonitor(int interval); void getSignalData(std::string &ssid, Exchange::INetworkManager::WiFiSignalQuality &quality, std::string &strengthOut); From 5e78de9929bbf70febb599be210d24ccbbb1455c Mon Sep 17 00:00:00 2001 From: gururaajar <83449026+gururaajar@users.noreply.github.com> Date: Wed, 22 Jan 2025 21:44:03 -0500 Subject: [PATCH 3/3] RDKEMW-777 - Implement GNOME support via direct G-DBus Network APIs (#81) Reason for change: Added the gdbus implementation for Network APIs Test Procedure: Build and verified with ubuntu desktop Risks: Low Priority: P1 Signed-off-by: Gururaaja ESR Gururaja_ErodeSriranganRamlingham@comcast.com --- CMakeLists.txt | 1 + Tests/raspberrypi/NetworkManagerGdbusTest.cpp | 160 ++- gdbus/NetworkManagerGdbusClient.cpp | 1121 ++++++++++++++++- gdbus/NetworkManagerGdbusClient.h | 9 + gdbus/NetworkManagerGdbusMgr.cpp | 71 +- gdbus/NetworkManagerGdbusMgr.h | 3 + gdbus/NetworkManagerGdbusProxy.cpp | 53 +- gdbus/NetworkManagerGdbusUtils.cpp | 271 +++- gdbus/NetworkManagerGdbusUtils.h | 10 + 9 files changed, 1646 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b4666ae..ef239925 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ add_definitions(-DPLUGIN_BUILD_REFERENCE=${PLUGIN_BUILD_REFERENCE}) if(ENABLE_GNOME_NETWORKMANAGER) pkg_check_modules(GLIB REQUIRED glib-2.0) pkg_check_modules(LIBNM REQUIRED libnm) +pkg_check_modules(GLIB REQUIRED gio-2.0) else() find_package(IARMBus REQUIRED) endif () diff --git a/Tests/raspberrypi/NetworkManagerGdbusTest.cpp b/Tests/raspberrypi/NetworkManagerGdbusTest.cpp index b65e2385..5c0b34ea 100644 --- a/Tests/raspberrypi/NetworkManagerGdbusTest.cpp +++ b/Tests/raspberrypi/NetworkManagerGdbusTest.cpp @@ -55,7 +55,7 @@ namespace WPEFramework { NMLOG_INFO("calling 'ReportInternetStatusChange' cb"); } - void NetworkManagerImplementation::ReportAvailableSSIDs(JsonArray &arrayofWiFiScanResults) + void NetworkManagerImplementation::ReportAvailableSSIDs(const JsonArray &arrayofWiFiScanResults) { NMLOG_INFO("calling 'ReportAvailableSSIDs' cb"); } @@ -85,6 +85,13 @@ void displayMenu() std::cout << "8. WiFi Disconnect" << std::endl; std::cout << "9. Get WiFi State" << std::endl; std::cout << "10. Get WiFi Signal Strength" << std::endl; + std::cout << "11. GetAvailableInterface" << std::endl; + std::cout << "12. SetPrimaryInterface" << std::endl; + std::cout << "13. SetInterfaceState" << std::endl; + std::cout << "14. SetIPSettings" << std::endl; + std::cout << "15. GetPrimaryInterface" << std::endl; + std::cout << "16. GetInterfaceState" << std::endl; + std::cout << "17. GetIPSettings" << std::endl; std::cout << "0. Exit" << std::endl; std::cout << "-------------------------------------" << std::endl; } @@ -275,6 +282,157 @@ int main() } break; } + case 11: { + std::vector interfaceList; + if(nmClient->getAvailableInterfaces(interfaceList)){ + for (const auto& interface : interfaceList) { + NMLOG_INFO("interface.type = %d interface.name = %s interface.mac = %s interface.enabled = %d interface.connected = %d", interface.type, interface.name.c_str(), interface.mac.c_str(), interface.enabled, interface.connected); + } + } + else + { + NMLOG_ERROR("Failed to get Available Interfaces"); + } + break; + } + case 12: { + std::string interface; + std::cout << "Enter interface name to set as primary: "; + std::cin.ignore(); + std::getline(std::cin, interface); + + if(nmClient->setPrimaryInterface(interface)){ + NMLOG_INFO("setPrimaryInterface successful"); + } + else + { + NMLOG_ERROR("Failed to set Primary Interface"); + } + break; + } + case 13: { + std::string interface; + std::string input; + bool enable; + std::cout << "Enter interface name to change the state: "; + std::cin.ignore(); + std::getline(std::cin, interface); + std::cout << "Enable Interface(input true/false): "; + std::getline(std::cin, input); + enable = (input == "true")? true: false; + + if(nmClient->setInterfaceState(interface, enable)){ + NMLOG_INFO("setInterfaceState successful"); + } + else + { + NMLOG_ERROR("Failed to set Interface State"); + } + break; + } + case 14: { + std::string interface; + std::string ipVersion; + std::string input; + bool autoConfig; + std::string ipAddress; + uint32_t prefix = 0; + std::string gateway; + std::string primarydns; + std::string secondarydns; + Exchange::INetworkManager::IPAddress address; + std::cout << "Enter interface: "; + std::cin.ignore(); + std::getline(std::cin, interface); + + std::cout << "Enter IP version: (IPv4/IPv6)"; + std::getline(std::cin, ipVersion); + + std::cout << "Enter auto configuration setting(input true/false): "; + std::getline(std::cin, input); + autoConfig = (input == "true")? true: false; + + if(!autoConfig) + { + std::cout << "Enter IP address: "; + std::getline(std::cin, ipAddress); + + // For prefix, use std::cin because it's a uint32_t + std::cout << "Enter prefix length: "; + std::cin >> prefix; + std::cin.ignore(std::numeric_limits::max(), '\n'); // Ignore leftover newline + + std::cout << "Enter gateway: "; + std::getline(std::cin, gateway); + + std::cout << "Enter primary DNS: "; + std::getline(std::cin, primarydns); + + std::cout << "Enter secondary DNS: "; + std::getline(std::cin, secondarydns); + } + address.ipversion = ipVersion; + address.autoconfig = autoConfig; + address.ipaddress = ipAddress; + address.prefix = prefix; + address.gateway = gateway; + address.primarydns = primarydns; + address.secondarydns = secondarydns; + if(nmClient->setIPSettings(interface, address)){ + NMLOG_INFO("setIPSettings successful"); + } + else + { + NMLOG_ERROR("Failed to set IP settings"); + } + break; + } + case 15: { + std::string interface; + + if(nmClient->getPrimaryInterface(interface)){ + NMLOG_INFO("Primary Interface = %s", interface.c_str()); + } + else + { + NMLOG_ERROR("Failed to Get Primary Interface"); + } + break; + } + case 16: { + std::string interface; + bool isEnabled; + std::cout << "Enter interface: "; + std::cin.ignore(); + std::getline(std::cin, interface); + if(nmClient->getInterfaceState(interface, isEnabled)){ + NMLOG_INFO("Interface %s is %s", interface.c_str(), isEnabled ? "enabled": "disabled"); + } + else + { + NMLOG_ERROR("Failed to Get Interface state"); + } + break; + } + case 17: { + std::string interface; + std::string ipVersion; + Exchange::INetworkManager::IPAddress result; + std::cout << "Enter interface: "; + std::cin.ignore(); + std::getline(std::cin, interface); + std::cout << "Enter IP version(IPv4/IPv6): "; + std::getline(std::cin, ipVersion); + if(nmClient->getIPSettings(interface, ipVersion, result)){ + NMLOG_INFO("\nresult.ipversion = %s\n result.autoconfig = %d\n result.dhcpserver = %s\n result.ula = %s\n result.ipaddress = %s\n result.prefix = %d\nresult.gateway = %s\n result.primarydns = %s\n result.secondarydns = %s\n", result.ipversion.c_str(), result.autoconfig, result.dhcpserver.c_str(), result.ula.c_str(), result.ipaddress.c_str(), result.prefix, result.gateway.c_str(), result.primarydns.c_str(), result.secondarydns.c_str()); + } + else + { + NMLOG_ERROR("Failed to get IP Settings"); + } + break; + } + case 0: std::cout << "Exiting program." << std::endl; diff --git a/gdbus/NetworkManagerGdbusClient.cpp b/gdbus/NetworkManagerGdbusClient.cpp index c99a56f3..5e6f6a00 100644 --- a/gdbus/NetworkManagerGdbusClient.cpp +++ b/gdbus/NetworkManagerGdbusClient.cpp @@ -41,6 +41,1125 @@ namespace WPEFramework NMLOG_INFO("~NetworkManagerClient"); } + bool updateRouteMetric(DbusMgr& m_dbus, const std::string& connectionPath, gint64 route_metric, const gchar* interface, const std::string& activeConnectionPath) + { + GError *error = nullptr; + deviceInfo devInfo{}; + if(!GnomeUtils::getDeviceInfoByIfname(m_dbus, interface, devInfo)) + return false; + GDBusProxy *settingsProxy = m_dbus.getNetworkManagerSettingsConnectionProxy(connectionPath.c_str()); + + if (settingsProxy == nullptr) { + NMLOG_ERROR("Error creating connection settings proxy"); + return false; + } + + GVariant *connectionSettings = g_dbus_proxy_call_sync( + settingsProxy, + "GetSettings", + nullptr, + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error); + + if (connectionSettings == nullptr) { + NMLOG_ERROR("Error retrieving connection settings: %s", error->message); + g_error_free(error); + g_object_unref(settingsProxy); + return false; + } + + GVariantIter *iterator; + GVariant *settingsDict; + const gchar *settingsKey; + const gchar *existingId = nullptr; + const gchar *existingType = nullptr; + const gchar *existingIPv4Method = nullptr; + const gchar *existingIPv6Method = nullptr; + const gchar *existingInterfaceName = nullptr; + + const gchar *existingKeyMgmt = nullptr; + const gchar *existingPSK = nullptr; + const gchar *existingSSID = nullptr; + GVariant *existingIPv4Settings = nullptr; + GVariant *existingIPv6Settings = nullptr; + + g_variant_get(connectionSettings, "(a{sa{sv}})", &iterator); + while (g_variant_iter_loop(iterator, "{&s@a{sv}}", &settingsKey, &settingsDict)) { + GVariantIter settingsIter; + const gchar *key; + GVariant *value; + + g_variant_iter_init(&settingsIter, settingsDict); + while (g_variant_iter_loop(&settingsIter, "{&sv}", &key, &value)) { + if (g_strcmp0(key, "id") == 0) { + existingId = g_variant_get_string(value, NULL); + NMLOG_DEBUG("Connection ID: %s\n", existingId); + } else if (g_strcmp0(key, "type") == 0) { + existingType = g_variant_get_string(value, NULL); + NMLOG_DEBUG("Connection Type: %s\n", existingType); + } else if (g_strcmp0(key, "interface-name") == 0) { + existingInterfaceName = g_variant_get_string(value, NULL); + NMLOG_DEBUG("Interface Name: %s\n", existingInterfaceName); + } else if (g_strcmp0(key, "method") == 0) { + if(g_strcmp0(settingsKey, "ipv4") == 0) + { + existingIPv4Method = g_variant_get_string(value, NULL); + NMLOG_DEBUG("IPV4 Method: %s\n", existingIPv4Method); + } + else if(g_strcmp0(settingsKey, "ipv6") == 0) + { + existingIPv6Method = g_variant_get_string(value, NULL); + NMLOG_DEBUG("IPV6 Method: %s\n", existingIPv6Method); + } + } else if (g_strcmp0(key, "ssid") == 0) { + gsize size; + const guint8 *ssid = (const guint8 *) g_variant_get_fixed_array(value, &size, sizeof(guint8)); + // Convert the ssid to a null-terminated string + existingSSID = g_strndup((const gchar *)ssid, size); + } else if (g_strcmp0(key, "key-mgmt") == 0) { + existingKeyMgmt = g_variant_get_string(value, NULL); + NMLOG_DEBUG("Key Management: %s\n", existingKeyMgmt); + } else if (g_strcmp0(key, "psk") == 0) { + existingPSK = g_variant_get_string(value, NULL); + NMLOG_DEBUG("psk: %s\n", existingPSK); + } else if (g_strcmp0(settingsKey, "ipv4") == 0) { + existingIPv4Settings = g_variant_ref(settingsDict); + } else if (g_strcmp0(settingsKey, "ipv6") == 0) { + existingIPv6Settings = g_variant_ref(settingsDict); + } + + } + } + g_variant_iter_free(iterator); + + GVariantBuilder connectionBuilder; + + GVariantBuilder wifiBuilder; + GVariantBuilder settingsBuilder; + GVariantBuilder wifiSecurityBuilder; + g_variant_builder_init(&settingsBuilder, G_VARIANT_TYPE("a{sa{sv}}")); + // Define the 'connection' dictionary with connection details + g_variant_builder_init(&connectionBuilder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&connectionBuilder, "{sv}", "id", g_variant_new_string(existingId)); + g_variant_builder_add(&connectionBuilder, "{sv}", "type", g_variant_new_string(existingType)); + g_variant_builder_add(&connectionBuilder, "{sv}", "interface-name", g_variant_new_string(existingInterfaceName)); + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "connection", &connectionBuilder); + + if (g_strcmp0(interface, GnomeUtils::getWifiIfname()) == 0) { + // Define the '802-11-wireless' dictionary with Wi-Fi specific details + g_variant_builder_init(&wifiBuilder, G_VARIANT_TYPE("a{sv}")); + GVariantBuilder ssidBuilder; + g_variant_builder_init(&ssidBuilder, G_VARIANT_TYPE("ay")); + while (*existingSSID) { + g_variant_builder_add(&ssidBuilder, "y", *(existingSSID++)); + } + g_variant_builder_add(&wifiBuilder, "{sv}", "ssid", g_variant_builder_end(&ssidBuilder)); + g_variant_builder_add(&wifiBuilder, "{sv}", "mode", g_variant_new_string("infrastructure")); // Set Wi-Fi mode + g_variant_builder_add(&wifiBuilder, "{sv}", "security", g_variant_new_string("802-11-wireless-security")); // Security type + + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "802-11-wireless", &wifiBuilder); + + // Define the '802-11-wireless-security' dictionary with security details + g_variant_builder_init(&wifiSecurityBuilder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&wifiSecurityBuilder, "{sv}", "key-mgmt", g_variant_new_string(existingKeyMgmt)); // Key management + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "802-11-wireless-security", &wifiSecurityBuilder); + } + + + GVariantBuilder ipv4Builder; + g_variant_builder_init(&ipv4Builder, G_VARIANT_TYPE("a{sv}")); + GVariantBuilder ipv6Builder; + g_variant_builder_init(&ipv6Builder, G_VARIANT_TYPE("a{sv}")); + + GnomeUtils::addGvariantToBuilder(existingIPv4Settings, &ipv4Builder, true); + GnomeUtils::addGvariantToBuilder(existingIPv6Settings, &ipv6Builder, true); + /*g_variant_builder_add(&ipv4Builder, "{sv}", "method", g_variant_new_string(existingIPv4Method)); + g_variant_builder_add(&ipv6Builder, "{sv}", "method", g_variant_new_string(existingIPv6Method));*/ + g_variant_builder_add(&ipv4Builder, "{sv}", "route-metric", g_variant_new_int64(route_metric)); + g_variant_builder_add(&ipv6Builder, "{sv}", "route-metric", g_variant_new_int64(route_metric)); + + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "ipv4", &ipv4Builder); + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "ipv6", &ipv6Builder); + + g_dbus_proxy_call_sync( + settingsProxy, + "Update", + g_variant_new("(a{sa{sv}})", &settingsBuilder), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error); + + if (error) { + NMLOG_ERROR("Error updating connection settings: %s", error->message); + g_error_free(error); + } else { + NMLOG_DEBUG("Successfully updated IPv4 settings for %s interface", interface); + } + if(!GnomeUtils::activateConnection(m_dbus, connectionPath, devInfo.path)) + { + NMLOG_INFO("activateConnection not successful"); + return false; + } + else + NMLOG_INFO("activateConnection successful"); + + g_variant_unref(connectionSettings); + g_object_unref(settingsProxy); + return true; + } + + bool updateIPSettings(DbusMgr& m_dbus, const std::string& connectionPath, const Exchange::INetworkManager::IPAddress& address, const std::string& interface) + { + GError *error = nullptr; + deviceInfo devInfo{}; + if(!GnomeUtils::getDeviceInfoByIfname(m_dbus, interface.c_str(), devInfo)) + return false; + GDBusProxy *settingsProxy = m_dbus.getNetworkManagerSettingsConnectionProxy(connectionPath.c_str()); + + if (settingsProxy == nullptr) { + NMLOG_ERROR("Error creating connection settings proxy"); + return false; + } + + GVariant *connectionSettings = g_dbus_proxy_call_sync( + settingsProxy, + "GetSettings", + nullptr, + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error); + + if (connectionSettings == nullptr) { + NMLOG_ERROR("Error retrieving connection settings: %s", error->message); + g_error_free(error); + g_object_unref(settingsProxy); + return false; + } + + GVariantIter *iterator; + GVariant *settingsDict; + const gchar *settingsKey; + const gchar *existingId = nullptr; + const gchar *existingType = nullptr; + const gchar *existingInterfaceName = nullptr; + + const gchar *existingKeyMgmt = nullptr; + const gchar *existingPSK = nullptr; + const gchar *existingSSID = nullptr; + GVariant *existingIPv4Settings = nullptr; + GVariant *existingIPv6Settings = nullptr; + + + g_variant_get(connectionSettings, "(a{sa{sv}})", &iterator); + while (g_variant_iter_loop(iterator, "{&s@a{sv}}", &settingsKey, &settingsDict)) { + GVariantIter settingsIter; + const gchar *key; + GVariant *value; + + g_variant_iter_init(&settingsIter, settingsDict); + while (g_variant_iter_loop(&settingsIter, "{&sv}", &key, &value)) { + if (g_strcmp0(key, "id") == 0) { + existingId = g_variant_get_string(value, NULL); + NMLOG_DEBUG("Connection ID: %s\n", existingId); + } else if (g_strcmp0(key, "type") == 0) { + existingType = g_variant_get_string(value, NULL); + NMLOG_DEBUG("Connection Type: %s\n", existingType); + } else if (g_strcmp0(key, "interface-name") == 0) { + existingInterfaceName = g_variant_get_string(value, NULL); + NMLOG_DEBUG("Interface Name: %s\n", existingInterfaceName); + } else if (g_strcmp0(key, "ssid") == 0) { + gsize size; + const guint8 *ssid = (const guint8 *) g_variant_get_fixed_array(value, &size, sizeof(guint8)); + // Convert the ssid to a null-terminated string + existingSSID = g_strndup((const gchar *)ssid, size); + } else if (g_strcmp0(key, "key-mgmt") == 0) { + existingKeyMgmt = g_variant_get_string(value, NULL); + NMLOG_DEBUG("Key Management: %s\n", existingKeyMgmt); + } else if (g_strcmp0(key, "psk") == 0) { + existingPSK = g_variant_get_string(value, NULL); + NMLOG_DEBUG("psk: %s\n", existingPSK); + } else if (g_strcmp0(settingsKey, "ipv4") == 0) { + existingIPv4Settings = g_variant_ref(settingsDict); + } else if (g_strcmp0(settingsKey, "ipv6") == 0) { + existingIPv6Settings = g_variant_ref(settingsDict); + } + } + } + g_variant_iter_free(iterator); + + GVariantBuilder connectionBuilder; + + GVariantBuilder wifiBuilder; + GVariantBuilder settingsBuilder; + GVariantBuilder wifiSecurityBuilder; + GVariantBuilder addressesBuilder; + GVariantBuilder addressEntryBuilder; + GVariantBuilder dnsBuilder; + g_variant_builder_init(&settingsBuilder, G_VARIANT_TYPE("a{sa{sv}}")); + // Define the 'connection' dictionary with connection details + g_variant_builder_init(&connectionBuilder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&connectionBuilder, "{sv}", "id", g_variant_new_string(existingId)); + g_variant_builder_add(&connectionBuilder, "{sv}", "type", g_variant_new_string(existingType)); + g_variant_builder_add(&connectionBuilder, "{sv}", "interface-name", g_variant_new_string(existingInterfaceName)); + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "connection", &connectionBuilder); + + if (g_strcmp0(interface.c_str(), GnomeUtils::getWifiIfname()) == 0) { + // Define the '802-11-wireless' dictionary with Wi-Fi specific details + g_variant_builder_init(&wifiBuilder, G_VARIANT_TYPE("a{sv}")); + GVariantBuilder ssidBuilder; + g_variant_builder_init(&ssidBuilder, G_VARIANT_TYPE("ay")); + while (*existingSSID) { + g_variant_builder_add(&ssidBuilder, "y", *(existingSSID++)); + } + g_variant_builder_add(&wifiBuilder, "{sv}", "ssid", g_variant_builder_end(&ssidBuilder)); + g_variant_builder_add(&wifiBuilder, "{sv}", "mode", g_variant_new_string("infrastructure")); // Set Wi-Fi mode + g_variant_builder_add(&wifiBuilder, "{sv}", "security", g_variant_new_string("802-11-wireless-security")); // Security type + + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "802-11-wireless", &wifiBuilder); + + // Define the '802-11-wireless-security' dictionary with security details + g_variant_builder_init(&wifiSecurityBuilder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&wifiSecurityBuilder, "{sv}", "key-mgmt", g_variant_new_string(existingKeyMgmt)); // Key management + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "802-11-wireless-security", &wifiSecurityBuilder); + } + + GVariantBuilder ipv4Builder; + GVariantBuilder ipv6Builder; + + g_variant_builder_init(&ipv4Builder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_init(&ipv6Builder, G_VARIANT_TYPE("a{sv}")); + if (g_strcmp0(address.ipversion.c_str(), "IPv4") == 0) + { + g_variant_builder_add(&ipv4Builder, "{sv}", "method", g_variant_new_string(address.autoconfig ? "auto" : "manual")); + if(!address.autoconfig) + { + // addresses + g_variant_builder_init(&addressesBuilder, G_VARIANT_TYPE("aau")); + + g_variant_builder_init(&addressEntryBuilder, G_VARIANT_TYPE("au")); + + g_variant_builder_add(&addressEntryBuilder, "u", GnomeUtils::ip4StrToNBO(address.ipaddress)); + g_variant_builder_add(&addressEntryBuilder, "u", address.prefix); + g_variant_builder_add(&addressEntryBuilder, "u", GnomeUtils::ip4StrToNBO(address.gateway)); + g_variant_builder_add_value(&addressesBuilder, g_variant_builder_end(&addressEntryBuilder)); + + g_variant_builder_add(&ipv4Builder, "{sv}", "addresses", g_variant_builder_end(&addressesBuilder)); + + // dns + g_variant_builder_init(&dnsBuilder, G_VARIANT_TYPE("au")); + g_variant_builder_add(&dnsBuilder, "u", GnomeUtils::ip4StrToNBO(address.primarydns)); + g_variant_builder_add(&dnsBuilder, "u", GnomeUtils::ip4StrToNBO(address.secondarydns)); + + g_variant_builder_add(&ipv4Builder, "{sv}", "dns", g_variant_builder_end(&dnsBuilder)); + // Add gateway + g_variant_builder_add(&ipv4Builder, "{sv}", "gateway", g_variant_new_string(address.gateway.c_str())); + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "ipv4", &ipv4Builder); + } + if (existingIPv6Settings) { + GnomeUtils::addGvariantToBuilder(existingIPv6Settings, &ipv6Builder, false); + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "ipv6", &ipv6Builder); + g_variant_unref(existingIPv6Settings); + } + } + else if (g_strcmp0(address.ipversion.c_str(), "IPv6") == 0) + { + g_variant_builder_add(&ipv6Builder, "{sv}", "method", g_variant_new_string(address.autoconfig ? "auto" : "manual")); + if(!address.autoconfig) + { + // addresses + g_variant_builder_init(&addressesBuilder, G_VARIANT_TYPE("a(ayuay)")); + + g_variant_builder_init(&addressEntryBuilder, G_VARIANT_TYPE("(ayuay)")); + std::array ip6 = GnomeUtils::ip6StrToNBO(address.ipaddress); + std::array gateway6 = GnomeUtils::ip6StrToNBO(address.gateway); + g_variant_builder_add_value(&addressEntryBuilder, g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, ip6.data(), ip6.size(), sizeof(guint8))); + g_variant_builder_add(&addressEntryBuilder, "u", address.prefix); + g_variant_builder_add_value(&addressEntryBuilder, g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, gateway6.data(), gateway6.size(), sizeof(guint8))); + g_variant_builder_add_value(&addressesBuilder, g_variant_builder_end(&addressEntryBuilder)); + g_variant_builder_add(&ipv6Builder, "{sv}", "addresses", g_variant_builder_end(&addressesBuilder)); + + //DNS + g_variant_builder_init(&dnsBuilder, G_VARIANT_TYPE("aay")); + std::array primaryDns6 = GnomeUtils::ip6StrToNBO(address.primarydns); + std::array secondaryDns6 = GnomeUtils::ip6StrToNBO(address.secondarydns); + g_variant_builder_add_value(&dnsBuilder, g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, primaryDns6.data(), primaryDns6.size(), sizeof(guint8))); + g_variant_builder_add_value(&dnsBuilder, g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, secondaryDns6.data(), secondaryDns6.size(), sizeof(guint8))); + g_variant_builder_add(&ipv6Builder, "{sv}", "dns", g_variant_builder_end(&dnsBuilder)); + // Add gateway + g_variant_builder_add(&ipv6Builder, "{sv}", "gateway", g_variant_new_string(address.gateway.c_str())); + + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "ipv6", &ipv6Builder); + } + if (existingIPv4Settings) { + GnomeUtils::addGvariantToBuilder(existingIPv4Settings, &ipv4Builder, false); + g_variant_builder_add(&settingsBuilder, "{sa{sv}}", "ipv4", &ipv4Builder); + g_variant_unref(existingIPv4Settings); + } + } + + g_dbus_proxy_call_sync( + settingsProxy, + "Update", + g_variant_new("(a{sa{sv}})", &settingsBuilder), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error); + + if (error) { + NMLOG_ERROR("Error updating connection settings: %s", error->message); + g_error_free(error); + } else { + NMLOG_DEBUG("Successfully updated IPv4 settings for %s interface", interface.c_str()); + } + if(!GnomeUtils::activateConnection(m_dbus, connectionPath, devInfo.path)) + { + NMLOG_INFO("activateConnection not successful"); + return false; + } + else + NMLOG_INFO("activateConnection successful"); + + g_variant_unref(connectionSettings); + g_object_unref(settingsProxy); + return true; + } + + bool NetworkManagerClient::getAvailableInterfaces(std::vector& interfacesList) + { + deviceInfo ethDevInfo{}; + deviceInfo wifiDevInfo{}; + Exchange::INetworkManager::InterfaceDetails ethInterface; + Exchange::INetworkManager::InterfaceDetails wifiInterface; + if(!GnomeUtils::getDeviceInfoByIfname(m_dbus, GnomeUtils::getEthIfname(), ethDevInfo)) + return false; + ethInterface.type = Exchange::INetworkManager::InterfaceType::INTERFACE_TYPE_ETHERNET; + ethInterface.name = ethDevInfo.interface; + ethInterface.mac = ethDevInfo.MAC; + ethInterface.enabled = ethDevInfo.managed?true:false; + ethInterface.connected = ethDevInfo.state == NM_DEVICE_STATE_ACTIVATED?true:false; + interfacesList.push_back(ethInterface); + if(!GnomeUtils::getDeviceInfoByIfname(m_dbus, GnomeUtils::getWifiIfname(), wifiDevInfo)) + return false; + wifiInterface.type = Exchange::INetworkManager::InterfaceType::INTERFACE_TYPE_WIFI; + wifiInterface.name = wifiDevInfo.interface; + wifiInterface.mac = wifiDevInfo.MAC; + wifiInterface.enabled = wifiDevInfo.managed?true:false; + wifiInterface.connected = wifiDevInfo.state == NM_DEVICE_STATE_ACTIVATED?true:false; + interfacesList.push_back(wifiInterface); + + return true; + } + + bool NetworkManagerClient::setPrimaryInterface(const std::string& interface) + { + GError *error = nullptr; + GDBusProxy *nmProxy = nullptr; + std::string connectionPath; + nmProxy = m_dbus.getNetworkManagerProxy(); + if(nmProxy == nullptr) + return false; + GVariant *activeConnections = g_dbus_proxy_get_cached_property(nmProxy, "ActiveConnections"); + if (activeConnections == nullptr) { + NMLOG_ERROR("Error retrieving active connections"); + g_object_unref(nmProxy); + return false; + } + + GVariantIter iter; + g_variant_iter_init(&iter, activeConnections); + gchar *activeConnectionPath = nullptr; + gint64 routeMetric; + while (g_variant_iter_loop(&iter, "o", &activeConnectionPath)) { + GDBusProxy *activeConnectionProxy = m_dbus.getNetworkManagerActiveConnProxy(activeConnectionPath); + + if (activeConnectionProxy == nullptr) { + NMLOG_ERROR("Error creating active connection proxy"); + continue; + } + + GVariant *devicesVar = g_dbus_proxy_get_cached_property(activeConnectionProxy, "Devices"); + if (devicesVar == nullptr) { + NMLOG_ERROR("Error retrieving devices property"); + g_object_unref(activeConnectionProxy); + continue; + } + + GVariantIter devicesIter; + g_variant_iter_init(&devicesIter, devicesVar); + gchar *devicePath = nullptr; + + while (g_variant_iter_loop(&devicesIter, "o", &devicePath)) { + GDBusProxy *deviceProxy = m_dbus.getNetworkManagerDeviceProxy(devicePath); + + if (deviceProxy == nullptr) { + NMLOG_ERROR("Error creating device proxy: %s", error->message); + g_error_free(error); + continue; + } + + GVariant *ifaceProperty = g_dbus_proxy_get_cached_property(deviceProxy, "Interface"); + if (ifaceProperty) { + const gchar *iface = g_variant_get_string(ifaceProperty, nullptr); + GVariant *connectionProperty = g_dbus_proxy_get_cached_property(activeConnectionProxy, "Connection"); + if (connectionProperty) { + connectionPath = g_variant_get_string(connectionProperty, nullptr); + g_variant_unref(connectionProperty); + } else { + NMLOG_ERROR("Error retrieving connection property"); + } + if (!g_strcmp0(iface, GnomeUtils::getWifiIfname()) || !g_strcmp0(iface, GnomeUtils::getEthIfname())) { + if(interface == iface) + routeMetric = ROUTE_METRIC_PRIORITY_HIGH; + else + routeMetric = ROUTE_METRIC_PRIORITY_LOW; + if(!updateRouteMetric(m_dbus, connectionPath, routeMetric, iface, activeConnectionPath)) + { + NMLOG_ERROR("Error: Failed to update route metric for Interface %s", iface); + return false; + } + } + g_variant_unref(ifaceProperty); + g_object_unref(deviceProxy); + break; + } + g_variant_unref(ifaceProperty); + } + + g_variant_unref(devicesVar); + g_object_unref(activeConnectionProxy); + } + + g_variant_unref(activeConnections); + g_object_unref(nmProxy); + + return true; + } + + bool NetworkManagerClient::getPrimaryInterface(std::string& interface) + { + GError* error = nullptr; + std::string primaryConnectionPath; + GDBusProxy *nmProxy = nullptr; + nmProxy = m_dbus.getNetworkManagerPropertyProxy("/org/freedesktop/NetworkManager"); + if(nmProxy == nullptr) + return false; + + GVariant* result = g_dbus_proxy_call_sync( + nmProxy, + "Get", + g_variant_new("(ss)", "org.freedesktop.NetworkManager", "PrimaryConnection"), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error + ); + + if (error) { + NMLOG_ERROR("Error: Getting primary connection path %s",error->message); + g_error_free(error); + return false; + } + + if (result != NULL) { + GVariant* value; + g_variant_get(result, "(v)", &value); + if (g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH)) { + primaryConnectionPath = g_variant_get_string(value, nullptr); + } else { + NMLOG_ERROR("Expected object path but got different type"); + } + g_variant_unref(value); + g_variant_unref(result); + } + + GDBusProxy* deviceProxy = m_dbus.getNetworkManagerPropertyProxy(primaryConnectionPath.c_str()); + if(deviceProxy == NULL) + return false; + + std::string defaultDevicePath; + + result = g_dbus_proxy_call_sync( + deviceProxy, + "Get", + g_variant_new("(ss)", "org.freedesktop.NetworkManager.Connection.Active", "Devices"), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error + ); + + if (error) { + NMLOG_ERROR("Error: Getting default device path %s", error->message); + g_error_free(error); + return false; + } + + if (result != nullptr) { + GVariant* value; + g_variant_get(result, "(v)", &value); + if (g_variant_is_of_type(value, G_VARIANT_TYPE_ARRAY)) { + GVariantIter* iter; + const gchar* devicePath; + g_variant_get(value, "ao", &iter); + + if (g_variant_iter_loop(iter, "o", &devicePath)) { + defaultDevicePath = devicePath; + } + g_variant_iter_free(iter); + } else { + NMLOG_ERROR("Expected array of object paths but got different type"); + } + g_variant_unref(value); + g_variant_unref(result); + } + GDBusProxy* defaultDeviceProxy = m_dbus.getNetworkManagerPropertyProxy(defaultDevicePath.c_str()); + if(defaultDeviceProxy == NULL) + return false; + + error = nullptr; + result = g_dbus_proxy_call_sync( + defaultDeviceProxy, + "Get", + g_variant_new("(ss)", "org.freedesktop.NetworkManager.Device", "Interface"), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error + ); + + if (error) { + NMLOG_ERROR("Error: Getting primary interface %s", error->message); + g_error_free(error); + return false; + } + + if (result != nullptr) { + GVariant* value; + g_variant_get(result, "(v)", &value); + if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { + interface = g_variant_get_string(value, nullptr); + } else { + NMLOG_ERROR("Expected string but got different type"); + } + g_variant_unref(value); + g_variant_unref(result); + } + + g_object_unref(defaultDeviceProxy); + g_object_unref(deviceProxy); + g_object_unref(nmProxy); + return true; + } + + bool NetworkManagerClient::setInterfaceState(const std::string& interface, bool enable) + { + deviceInfo devInfo{}; + GError* error = nullptr; + if(!GnomeUtils::getDeviceInfoByIfname(m_dbus, interface.c_str(), devInfo)) + return false; + + GDBusProxy* deviceProxy = m_dbus.getNetworkManagerPropertyProxy(devInfo.path.c_str()); + if(deviceProxy == NULL) + return false; + + GVariant* result = g_dbus_proxy_call_sync( + deviceProxy, + "Set", + g_variant_new("(ssv)", "org.freedesktop.NetworkManager.Device", "Managed", g_variant_new_boolean(enable)), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error + ); + + if (error) { + NMLOG_ERROR("Error %s network interface: %s", (enable ? "enabling" : "disabling"), error->message); + g_error_free(error); + } else { + NMLOG_DEBUG("Network interface %s successfully %s", (enable ? "enabled" : "disabled"), devInfo.path.c_str()); + if (result != nullptr) { + g_variant_unref(result); + } + } + g_object_unref(deviceProxy); + return true; + } + + bool NetworkManagerClient::getInterfaceState(const std::string& interface, bool& isEnabled) + { + deviceInfo devInfo{}; + if(!GnomeUtils::getDeviceInfoByIfname(m_dbus, interface.c_str(), devInfo)) + return false; + + GError* error = nullptr; + GDBusProxy* deviceProxy = m_dbus.getNetworkManagerPropertyProxy(devInfo.path.c_str()); + if(deviceProxy == nullptr) + return false; + + // Call the "Get" method using the proxy + GVariant* result = g_dbus_proxy_call_sync( + deviceProxy, + "Get", + g_variant_new("(ss)", "org.freedesktop.NetworkManager.Device", "Managed"), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error + ); + + if (error != nullptr) { + NMLOG_ERROR("Error getting network interface state: %s", error->message); + g_error_free(error); + } else { + NMLOG_DEBUG("Network interface state retrieved successfully: %s",devInfo.path.c_str()); + GVariant* managedVariant; + g_variant_get(result, "(v)", &managedVariant); + + isEnabled = g_variant_get_boolean(managedVariant); + g_variant_unref(managedVariant); + + NMLOG_DEBUG("Interface %s is %s", interface.c_str(), isEnabled ? "enabled" : "disabled"); + + g_variant_unref(result); + } + + return true; + } + + bool NetworkManagerClient::setIPSettings(const std::string& interface, const Exchange::INetworkManager::IPAddress& address) + { + std::string connectionPath; + if (!GnomeUtils::getSettingsConnectionPath(m_dbus, connectionPath, interface)) + { + NMLOG_ERROR("Error: connection path not found for interface %s", interface.c_str()); + return false; + } + if (connectionPath.empty()) { + NMLOG_ERROR("Error: Interface %s not found in active connections", interface.c_str()); + return false; + } + if(!updateIPSettings(m_dbus, connectionPath, address, interface)) + { + NMLOG_ERROR("Error: Failed to update route metric for Interface %s", interface.c_str()); + return false; + } + + return true; + } + + bool NetworkManagerClient::getIPSettings(const std::string& interface, const std::string& ipversion, Exchange::INetworkManager::IPAddress& result) + { + std::string devicePath; + std::string addressStr; + guint32 prefix = 0; + const gchar *gatewayIp = nullptr; + gchar *dhcpServerIp = nullptr; + gchar **dnsList = nullptr; + gchar *ip4ConfigPath = nullptr; + gchar *dhcp4ConfigPath = nullptr; + gchar *dnsAddresses = nullptr; + gchar *dhcp6ConfigPath = nullptr; + gchar *ip6ConfigPath = nullptr; + GDBusProxy* ipv4Proxy = nullptr; + GDBusProxy* ipv6Proxy = nullptr; + const gchar *IPv4Method = nullptr; + const gchar *IPv6Method = nullptr; + deviceInfo devInfo{}; + GError *error = nullptr; + if(!GnomeUtils::getDeviceByIpIface(m_dbus, interface.c_str(), devicePath)) + return false; + GDBusProxy *deviceProxy = m_dbus.getNetworkManagerDeviceProxy(devicePath.c_str()); + if(deviceProxy == nullptr) + return false; + if (g_strcmp0(ipversion.c_str(), "IPv4") == 0) + { + GVariant *ip4Property = g_dbus_proxy_get_cached_property(deviceProxy, "Ip4Config"); + if (ip4Property != nullptr) + { + g_variant_get(ip4Property, "o", &ip4ConfigPath); + g_variant_unref(ip4Property); + } + else + { + NMLOG_ERROR("Failed to get Ip4Config property"); + g_object_unref(deviceProxy); + } + + GVariant *dhcp4Property = g_dbus_proxy_get_cached_property(deviceProxy, "Dhcp4Config"); + if (dhcp4Property != nullptr) + { + g_variant_get(dhcp4Property, "o", &dhcp4ConfigPath); + g_variant_unref(dhcp4Property); + } + else + { + NMLOG_ERROR("Failed to get Dhcp4Config property"); + g_object_unref(deviceProxy); + } + + ipv4Proxy = m_dbus.getNetworkManagerIpv4Proxy(ip4ConfigPath); + g_free(ip4ConfigPath); + // Get the 'Addresses' property + if(ipv4Proxy != nullptr) + { + GVariant *addressesProperty = g_dbus_proxy_get_cached_property(ipv4Proxy, "Addresses"); + + if(addressesProperty != nullptr) + { + gsize numAddresses = g_variant_n_children(addressesProperty); + for (gsize i = 0; i < numAddresses; ++i) { + GVariant *addressArray = g_variant_get_child_value(addressesProperty, i); + GVariantIter iter; + guint32 addr; + + g_variant_iter_init(&iter, addressArray); + + if (g_variant_iter_next(&iter, "u", &addr)) { + addressStr = GnomeUtils::ip4ToString(addr); + NMLOG_DEBUG("IP Address: %s", addressStr.c_str()); + } + if (g_variant_iter_next(&iter, "u", &prefix)) { + NMLOG_DEBUG("Prefix: %d", prefix); + } + + g_variant_unref(addressArray); + } + + g_variant_unref(addressesProperty); + } + else + { + NMLOG_ERROR("Failed to get Addresses property"); + g_object_unref(ipv4Proxy); + } + + // Get the 'Gateway' property + GVariant *gatewayProperty = g_dbus_proxy_get_cached_property(ipv4Proxy, "Gateway"); + if (gatewayProperty != nullptr) { + // Fetch and print the Gateway IP + gatewayIp = g_variant_get_string(gatewayProperty, nullptr); + NMLOG_DEBUG("Gateway: %s", gatewayIp); + g_variant_unref(gatewayProperty); + } + else + { + NMLOG_ERROR("Failed to get Gateway property"); + g_variant_unref(addressesProperty); + g_object_unref(ipv4Proxy); + } + } + GDBusProxy* dhcpv4Proxy = m_dbus.getNetworkManagerDhcpv4Proxy(dhcp4ConfigPath); + g_free(dhcp4ConfigPath); + + if(dhcpv4Proxy != nullptr) + { + // Get the 'Options' property + GVariant *optionsProperty = g_dbus_proxy_get_cached_property(dhcpv4Proxy, "Options"); + + if (optionsProperty != nullptr) { + + GVariantIter *iter; + gchar *key; + GVariant *value; + + // Print the whole options property for debugging + gchar *optionsStr = g_variant_print(optionsProperty, TRUE); + NMLOG_DEBUG("Options property: %s", optionsStr); + g_free(optionsStr); + + g_variant_get(optionsProperty, "a{sv}", &iter); + + while (g_variant_iter_next(iter, "{&sv}", &key, &value)) { + if (g_strcmp0(key, "dhcp_server_identifier") == 0) { + dhcpServerIp = g_strdup(g_variant_get_string(value, nullptr)); + } else if (g_strcmp0(key, "domain_name_servers") == 0) { + dnsAddresses = g_strdup(g_variant_get_string(value, nullptr)); + } + g_variant_unref(value); + + if (dhcpServerIp && dnsAddresses) { + break; + } + } + + g_variant_iter_free(iter); + g_variant_unref(optionsProperty); + g_object_unref(dhcpv4Proxy); + + if (dhcpServerIp) { + NMLOG_DEBUG("DHCP server IP address: %s", dhcpServerIp); + } else { + NMLOG_DEBUG("Failed to find DHCP server IP address"); + } + if (dnsAddresses) { + // DNS addresses are space-separated, we need to split them + dnsList = g_strsplit(dnsAddresses, " ", -1); + if (dnsList[0] != nullptr) { + NMLOG_DEBUG("Primary DNS: %s", dnsList[0]); + if (dnsList[1] != nullptr) { + NMLOG_DEBUG("Secondary DNS: %s", dnsList[1]); + } else { + NMLOG_DEBUG("Secondary DNS: Not available"); + } + } else { + NMLOG_DEBUG("Failed to parse DNS addresses"); + } + } else { + NMLOG_DEBUG("Failed to find DNS addresses"); + } + } + else + { + NMLOG_ERROR("Failed to get Options property"); + g_object_unref(dhcpv4Proxy); + } + } + } + else if (g_strcmp0(ipversion.c_str(), "IPv6") == 0) + { + GVariant *ip6Property = g_dbus_proxy_get_cached_property(deviceProxy, "Ip6Config"); + if (ip6Property != nullptr) { + g_variant_get(ip6Property, "o", &ip6ConfigPath); + g_variant_unref(ip6Property); + } + else + { + NMLOG_ERROR("Failed to get Ip6Config property"); + g_object_unref(deviceProxy); + } + + GVariant *dhcp6Property = g_dbus_proxy_get_cached_property(deviceProxy, "Dhcp6Config"); + if (dhcp6Property != nullptr) { + g_variant_get(dhcp6Property, "o", &dhcp6ConfigPath); + g_variant_unref(dhcp6Property); + } + else + { + NMLOG_ERROR("Failed to get Dhcp6Config property"); + g_object_unref(deviceProxy); + } + + + ipv6Proxy = m_dbus.getNetworkManagerIpv6Proxy(ip6ConfigPath); + g_free(ip6ConfigPath); + if(ipv6Proxy != nullptr) + { + // Get the 'Addresses' property + GVariant *addressesProperty = g_dbus_proxy_get_cached_property(ipv6Proxy, "Addresses"); + if (addressesProperty != nullptr) + { + gsize numAddresses = g_variant_n_children(addressesProperty); + for (gsize i = 0; i < numAddresses; ++i) { + GVariant *addressTuple = g_variant_get_child_value(addressesProperty, i); + GVariant *addressArray = g_variant_get_child_value(addressTuple, 0); // Get the first byte array (IPv6 address) + GVariant *prefixVariant = g_variant_get_child_value(addressTuple, 1); // Get the prefix + prefix = g_variant_get_uint32(prefixVariant); + + uint8_t ipv6Addr[16]; + gsize addrLen; + gconstpointer addrData = g_variant_get_fixed_array(addressArray, &addrLen, 1); + if (addrLen == 16) { + memcpy(ipv6Addr, addrData, addrLen); + addressStr = GnomeUtils::ip6ToString(ipv6Addr); + if ((ipv6Addr[0] & 0xE0) == 0x20) // Check if the first three bits are within the range for global + { + break; + } + NMLOG_DEBUG("IPv6 Address: %s Prefix: %d", addressStr.c_str(), prefix); + } + + g_variant_unref(addressArray); + g_variant_unref(prefixVariant); + g_variant_unref(addressTuple); + } + } + else + { + NMLOG_ERROR("Failed to get Addresses property for IPv6"); + g_object_unref(ipv6Proxy); + } + g_variant_unref(addressesProperty); + + // Get the 'Gateway' property + GVariant *gatewayProperty = g_dbus_proxy_get_cached_property(ipv6Proxy, "Gateway"); + if (gatewayProperty != nullptr) + { + // Fetch and print the Gateway IP + gatewayIp = g_variant_get_string(gatewayProperty, nullptr); + NMLOG_DEBUG("IPv6 Gateway: %s", gatewayIp); + g_variant_unref(gatewayProperty); + } + else + { + NMLOG_ERROR("Failed to get Gateway property for IPv6"); + g_object_unref(ipv6Proxy); + } + } + GDBusProxy* dhcpv6Proxy = m_dbus.getNetworkManagerDhcpv6Proxy(dhcp6ConfigPath); + g_free(dhcp6ConfigPath); + if(dhcpv6Proxy != nullptr) + { + // Get the 'Options' property + GVariant *optionsProperty = g_dbus_proxy_get_cached_property(dhcpv6Proxy, "Options"); + if (optionsProperty != nullptr) { + + GVariantIter *iter; + gchar *key; + GVariant *value; + gchar *ip6Address = nullptr; + + // Print the whole options property for debugging + gchar *optionsStr = g_variant_print(optionsProperty, TRUE); + NMLOG_DEBUG("Options property: %s", optionsStr); + g_free(optionsStr); + + g_variant_get(optionsProperty, "a{sv}", &iter); + + while (g_variant_iter_next(iter, "{&sv}", &key, &value)) { + gchar *valueStr = g_variant_print(value, TRUE); + NMLOG_DEBUG("Key: %s Value: %s", key, valueStr); + g_free(valueStr); + + if (g_strcmp0(key, "dhcp6_name_servers") == 0) { + dnsAddresses = g_strdup(g_variant_get_string(value, nullptr)); + } else if (g_strcmp0(key, "ip6_address") == 0) { + ip6Address = g_strdup(g_variant_get_string(value, nullptr)); + } + g_variant_unref(value); + } + + g_variant_iter_free(iter); + g_variant_unref(optionsProperty); + g_object_unref(dhcpv6Proxy); + + if (ip6Address) { + NMLOG_DEBUG("IPv6 Address: %s", ip6Address); + g_free(ip6Address); + } else { + NMLOG_ERROR("Failed to find the IPv6 address"); + } + + if (dnsAddresses) { + // DNS addresses are space-separated, we need to split them + dnsList = g_strsplit(dnsAddresses, " ", -1); + if (dnsList[0] != nullptr) { + NMLOG_DEBUG("Primary DNS: %s", dnsList[0]); + if (dnsList[1] != nullptr) { + NMLOG_DEBUG("Secondary DNS: %s ", dnsList[1]); + } else { + NMLOG_DEBUG("Secondary DNS: Not available"); + } + } else { + NMLOG_ERROR("Failed to parse DNS addresses"); + } + } else { + std::cerr << "Failed to find DNS addresses" << std::endl; + } + } + else + { + NMLOG_ERROR("Failed to get Options property for DHCP6"); + g_object_unref(dhcpv6Proxy); + } + } + } + std::string connectionPath; + if (!GnomeUtils::getSettingsConnectionPath(m_dbus, connectionPath, interface)) + { + NMLOG_ERROR("Error: connection path not found for interface %s", interface.c_str()); + return false; + } + + if(!GnomeUtils::getDeviceInfoByIfname(m_dbus, interface.c_str(), devInfo)) + return false; + GDBusProxy *settingsProxy = m_dbus.getNetworkManagerSettingsConnectionProxy(connectionPath.c_str()); + + if (settingsProxy == nullptr) { + NMLOG_ERROR("Error creating connection settings proxy: %s",error->message); + g_error_free(error); + return false; + } + + GVariant *connectionSettings = g_dbus_proxy_call_sync( + settingsProxy, + "GetSettings", + nullptr, + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error); + + if (connectionSettings == nullptr) { + NMLOG_ERROR("Error retrieving connection settings: %s", error->message); + g_error_free(error); + g_object_unref(settingsProxy); + return false; + } + + GVariantIter *iterator; + GVariant *settingsDict; + const gchar *settingsKey; + + g_variant_get(connectionSettings, "(a{sa{sv}})", &iterator); + while (g_variant_iter_loop(iterator, "{&s@a{sv}}", &settingsKey, &settingsDict)) { + GVariantIter settingsIter; + const gchar *key; + GVariant *value; + + g_variant_iter_init(&settingsIter, settingsDict); + while (g_variant_iter_loop(&settingsIter, "{&sv}", &key, &value)) { + if (g_strcmp0(key, "method") == 0) { + if(g_strcmp0(settingsKey, "ipv4") == 0) + { + IPv4Method = g_variant_get_string(value, NULL); + NMLOG_DEBUG("IPV4 Method: %s\n", IPv4Method); + } + else if(g_strcmp0(settingsKey, "ipv6") == 0) + { + IPv6Method = g_variant_get_string(value, NULL); + NMLOG_DEBUG("IPV6 Method: %s\n", IPv6Method); + } + } + } + } + + result.ipversion = ipversion; + result.autoconfig = true; + if(g_strcmp0(ipversion.c_str(), "IPv4") == 0) + result.autoconfig = (g_strcmp0(IPv4Method, "auto") == 0); + else if(g_strcmp0(ipversion.c_str(), "IPv6") == 0) + result.autoconfig = (g_strcmp0(IPv6Method, "auto") == 0); + result.ipaddress = addressStr; + result.prefix = prefix; + result.ula = ""; + result.dhcpserver = (dhcpServerIp != NULL) ? std::string(dhcpServerIp) : ""; + result.gateway = (gatewayIp != NULL) ? std::string(gatewayIp) : ""; + if (dnsList != NULL) + { + result.primarydns = (dnsList[0] != NULL) ? std::string(dnsList[0]) : ""; + result.secondarydns = (dnsList[1] != NULL) ? std::string(dnsList[1]) : ""; + } + else + { + result.primarydns = ""; + result.secondarydns = ""; + } + if(ipv4Proxy != NULL) + g_object_unref(ipv4Proxy); + if(ipv6Proxy != NULL) + g_object_unref(ipv6Proxy); + g_strfreev(dnsList); + g_free(dnsAddresses); + g_free(dhcpServerIp); + + return true; + } + static bool getSSIDFromConnection(DbusMgr &m_dbus, const std::string connPath, std::string& ssid) { GError *error = NULL; @@ -735,7 +1854,7 @@ namespace WPEFramework ssid = ssidInfo.ssid; signalStrength = ssidInfo.strength; - float signalStrengthFloat = 0.0f; + float signalStrengthFloat = 0.0f; if(!signalStrength.empty()) signalStrengthFloat = std::stof(signalStrength.c_str()); diff --git a/gdbus/NetworkManagerGdbusClient.h b/gdbus/NetworkManagerGdbusClient.h index 7e646652..d1a4bb8a 100644 --- a/gdbus/NetworkManagerGdbusClient.h +++ b/gdbus/NetworkManagerGdbusClient.h @@ -27,6 +27,8 @@ #include "NetworkManagerGdbusMgr.h" #include "INetworkManager.h" +#define ROUTE_METRIC_PRIORITY_HIGH 10 +#define ROUTE_METRIC_PRIORITY_LOW 100 namespace WPEFramework { namespace Plugin @@ -44,6 +46,13 @@ namespace WPEFramework NetworkManagerClient(const NetworkManagerClient&) = delete; NetworkManagerClient& operator=(const NetworkManagerClient&) = delete; + bool getAvailableInterfaces(std::vector& interfaceList); + bool setPrimaryInterface(const std::string& interface); + bool setInterfaceState(const std::string& interface, bool enable); + bool setIPSettings(const std::string& interface, const Exchange::INetworkManager::IPAddress& address); + bool getPrimaryInterface(std::string& interface); + bool getInterfaceState(const std::string& interface, bool& isEnabled); + bool getIPSettings(const std::string& interface, const std::string& ipversion, Exchange::INetworkManager::IPAddress& result); bool getKnownSSIDs(std::list& ssids); bool getAvailableSSIDs(std::list& ssids); bool getConnectedSSID(Exchange::INetworkManager::WiFiSSIDInfo& ssidinfo); diff --git a/gdbus/NetworkManagerGdbusMgr.cpp b/gdbus/NetworkManagerGdbusMgr.cpp index 310b025d..71d3374e 100644 --- a/gdbus/NetworkManagerGdbusMgr.cpp +++ b/gdbus/NetworkManagerGdbusMgr.cpp @@ -38,7 +38,7 @@ namespace WPEFramework NMLOG_FATAL("Error connecting to system D-Bus bus: %s ", error->message); g_error_free(error); } - flags = static_cast(G_DBUS_PROXY_FLAGS_NONE); + flags = G_DBUS_PROXY_FLAGS_NONE; } DbusMgr::~DbusMgr() { @@ -63,7 +63,7 @@ namespace WPEFramework return NULL; } - flags = static_cast(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START); + flags = G_DBUS_PROXY_FLAGS_NONE; return connection; } @@ -257,6 +257,73 @@ namespace WPEFramework return proxy; } + GDBusProxy* DbusMgr::getNetworkManagerDhcpv4Proxy(const char* dhcpConfigPath) + { + GError* error = nullptr; + GDBusProxy *proxy = g_dbus_proxy_new_sync( + getConnection(), + flags, + nullptr, + "org.freedesktop.NetworkManager", + dhcpConfigPath, + "org.freedesktop.NetworkManager.DHCP4Config", + nullptr, + &error); + + if (proxy == nullptr) { + g_dbus_error_strip_remote_error(error); + NMLOG_FATAL("Error creating dhcpv4 proxy: %s", error->message); + g_clear_error(&error); + return nullptr; + } + return proxy; + } + + GDBusProxy* DbusMgr::getNetworkManagerDhcpv6Proxy(const char* dhcpConfigPath) + { + GError* error = nullptr; + GDBusProxy *proxy = g_dbus_proxy_new_sync( + getConnection(), + flags, + nullptr, + "org.freedesktop.NetworkManager", + dhcpConfigPath, + "org.freedesktop.NetworkManager.DHCP6Config", + nullptr, + &error); + + if (proxy == nullptr) { + g_dbus_error_strip_remote_error(error); + NMLOG_FATAL("Error creating dhcpv6 proxy: %s", error->message); + g_clear_error(&error); + return nullptr; + } + return proxy; + } + + GDBusProxy* DbusMgr::getNetworkManagerPropertyProxy(const char* devicePath) + { + GError* error = nullptr; + GDBusProxy* proxy = g_dbus_proxy_new_sync( + getConnection(), + flags, + nullptr, + "org.freedesktop.NetworkManager", + devicePath, + "org.freedesktop.DBus.Properties", + nullptr, + &error + ); + + if (proxy == nullptr) { + g_dbus_error_strip_remote_error(error); + NMLOG_ERROR("Failed to create property proxy: %s", error->message); + g_clear_error(&error); + return nullptr; + } + return proxy; + } + } // Plugin } // WPEFramework diff --git a/gdbus/NetworkManagerGdbusMgr.h b/gdbus/NetworkManagerGdbusMgr.h index 8e00c897..a6c2f81e 100644 --- a/gdbus/NetworkManagerGdbusMgr.h +++ b/gdbus/NetworkManagerGdbusMgr.h @@ -45,6 +45,9 @@ namespace WPEFramework GDBusProxy* getNetworkManagerActiveConnProxy(const char* activePath); GDBusProxy* getNetworkManagerAccessPointProxy(const char* apPath); GDBusConnection* getConnection(); + GDBusProxy* getNetworkManagerPropertyProxy(const char* devicePath); + GDBusProxy* getNetworkManagerDhcpv4Proxy(const char* dhcpConfigPath); + GDBusProxy* getNetworkManagerDhcpv6Proxy(const char* dhcpConfigPath); private: GDBusConnection* connection; diff --git a/gdbus/NetworkManagerGdbusProxy.cpp b/gdbus/NetworkManagerGdbusProxy.cpp index 57665412..2c68201b 100644 --- a/gdbus/NetworkManagerGdbusProxy.cpp +++ b/gdbus/NetworkManagerGdbusProxy.cpp @@ -46,38 +46,77 @@ namespace WPEFramework uint32_t NetworkManagerImplementation::GetAvailableInterfaces (Exchange::INetworkManager::IInterfaceDetailsIterator*& interfacesItr/* @out */) { - return Core::ERROR_NONE; + uint32_t rc = Core::ERROR_GENERAL; + std::vector interfaceList; + if(_nmGdbusClient->getAvailableInterfaces(interfaceList)) + rc = Core::ERROR_NONE; + else + NMLOG_ERROR("GetAvailableInterfaces failed"); + using Implementation = RPC::IteratorType; + interfacesItr = Core::Service::Create(interfaceList); + + return rc; } uint32_t NetworkManagerImplementation::GetPrimaryInterface (string& interface /* @out */) { - return Core::ERROR_NONE; + uint32_t rc = Core::ERROR_GENERAL; + if(_nmGdbusClient->getPrimaryInterface(interface)) + rc = Core::ERROR_NONE; + else + NMLOG_ERROR("GetPrimaryInterface failed"); + return rc; } uint32_t NetworkManagerImplementation::SetPrimaryInterface (const string& interface/* @in */) { - return Core::ERROR_NONE; + uint32_t rc = Core::ERROR_GENERAL; + if(_nmGdbusClient->setPrimaryInterface(interface)) + rc = Core::ERROR_NONE; + else + NMLOG_ERROR("SetPrimaryInterface failed"); + return rc; } uint32_t NetworkManagerImplementation::SetInterfaceState(const string& interface/* @in */, const bool enabled /* @in */) { - return Core::ERROR_NONE; + uint32_t rc = Core::ERROR_GENERAL; + if(_nmGdbusClient->setInterfaceState(interface, enabled)) + rc = Core::ERROR_NONE; + else + NMLOG_ERROR("SetInterfaceState failed"); + return rc; } uint32_t NetworkManagerImplementation::GetInterfaceState(const string& interface/* @in */, bool& isEnabled /* @out */) { - return Core::ERROR_NONE; + uint32_t rc = Core::ERROR_GENERAL; + if(_nmGdbusClient->getInterfaceState(interface, isEnabled)) + rc = Core::ERROR_NONE; + else + NMLOG_ERROR("GetInterfaceState failed"); + return rc; } /* @brief Get IP Address Of the Interface */ uint32_t NetworkManagerImplementation::GetIPSettings(string& interface /* @inout */, const string &ipversion /* @in */, IPAddress& result /* @out */) { - return Core::ERROR_NONE; + uint32_t rc = Core::ERROR_GENERAL; + if(_nmGdbusClient->getIPSettings(interface, ipversion, result)) + rc = Core::ERROR_NONE; + else + NMLOG_ERROR("GetIPSettings failed"); + return rc; } /* @brief Set IP Address Of the Interface */ uint32_t NetworkManagerImplementation::SetIPSettings(const string& interface /* @in */, const IPAddress& address /* @in */) { - return Core::ERROR_NONE; + uint32_t rc = Core::ERROR_GENERAL; + if(_nmGdbusClient->setIPSettings(interface, address)) + rc = Core::ERROR_NONE; + else + NMLOG_ERROR("SetIPSettings failed"); + return rc; } uint32_t NetworkManagerImplementation::StartWiFiScan(const string& frequency /* @in */, IStringIterator* const ssids/* @in */) diff --git a/gdbus/NetworkManagerGdbusUtils.cpp b/gdbus/NetworkManagerGdbusUtils.cpp index dc893292..ad1ee6d8 100644 --- a/gdbus/NetworkManagerGdbusUtils.cpp +++ b/gdbus/NetworkManagerGdbusUtils.cpp @@ -20,12 +20,14 @@ #include #include #include +#include #include #include "NetworkManagerLogger.h" #include "NetworkManagerGdbusUtils.h" #include "NetworkManagerGdbusMgr.h" #include +#include // for struct in_addr namespace WPEFramework { @@ -214,20 +216,55 @@ namespace WPEFramework return true; } + bool GnomeUtils::getCachedPropertyBoolean(GDBusProxy* proxy, const char* property, bool *value) + { + GVariant* result = nullptr; + result = g_dbus_proxy_get_cached_property(proxy, property); + if (result == nullptr) { + NMLOG_ERROR("Failed to get '%s' properties", property); + return false; + } + + if (g_variant_is_of_type(result, G_VARIANT_TYPE_BOOLEAN)) { + *value = g_variant_get_boolean(result); + } + else + NMLOG_WARNING("Unexpected type returned property: %s", g_variant_get_type_string(result)); + g_variant_unref(result); + return true; + } + bool GnomeUtils::getDevicePropertiesByPath(DbusMgr& m_dbus, const char* devicePath, deviceInfo& properties) { GVariant *devicesVar = NULL; GDBusProxy* nmProxy = NULL; - u_int32_t value; + u_int32_t value = 0; + bool managedValue; nmProxy = m_dbus.getNetworkManagerDeviceProxy(devicePath); if(nmProxy == NULL) return false; if(GnomeUtils::getCachedPropertyU(nmProxy, "DeviceType", &value)) - properties.deviceType = static_cast(value); + properties.deviceType = static_cast(value); + else + NMLOG_ERROR("'DeviceType' property failed"); + + if(GnomeUtils::getCachedPropertyBoolean(nmProxy, "Managed", &managedValue)) + properties.managed = managedValue; else - NMLOG_ERROR("'DeviceType' property failed"); + NMLOG_ERROR("'Managed' property failed"); + devicesVar = g_dbus_proxy_get_cached_property(nmProxy, "HwAddress"); + if (devicesVar) { + const gchar *mac = g_variant_get_string(devicesVar, NULL); + if(mac != NULL) + { + properties.MAC = mac; + } + g_variant_unref(devicesVar); + } + else + NMLOG_ERROR("'mac' property failed"); devicesVar = g_dbus_proxy_get_cached_property(nmProxy, "Interface"); if (devicesVar) { @@ -236,7 +273,6 @@ namespace WPEFramework { properties.interface = iface; } - //NMLOG_DEBUG("Interface: %s", iface); g_variant_unref(devicesVar); } else @@ -302,49 +338,39 @@ namespace WPEFramework return ret; } - bool GnomeUtils::getDeviceByIpIface(DbusMgr& m_dbus, const gchar *iface_name, std::string& path) + bool GnomeUtils::getDeviceByIpIface(DbusMgr& m_dbus, const gchar *ifaceName, std::string& path) { - // TODO Fix Error calling method: - // GDBus.Error:org.freedesktop.NetworkManager.UnknownDevice: No device found for the requested iface - // in wsl linux - GError *error = NULL; - GVariant *result; - gchar *device_path = NULL; - bool ret = false; + GError *error = nullptr; + GDBusProxy* nmProxy = m_dbus.getNetworkManagerProxy(); + if(nmProxy == NULL) + return false; - result = g_dbus_connection_call_sync( - m_dbus.getConnection(), - "org.freedesktop.NetworkManager", // D-Bus name - "/org/freedesktop/NetworkManager", // Object path - "org.freedesktop.NetworkManager", // Interface - "GetDeviceByIpIface", // Method name - g_variant_new("(s)", iface_name), // Input parameter (the interface name) - G_VARIANT_TYPE("(o)"), // Expected return type (object path) - G_DBUS_CALL_FLAGS_NONE, - -1, // Default timeout - NULL, - &error - ); - - if (error != NULL) { - NMLOG_ERROR("calling GetDeviceByIpIface: %s", error->message); - g_error_free(error); - return ret; + GVariant *result = g_dbus_proxy_call_sync( + nmProxy, + "GetDeviceByIpIface", + g_variant_new("(s)", ifaceName), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error); + + if (result == nullptr) { + NMLOG_ERROR("Error calling GetDeviceByIpIface: %s", error->message); + g_clear_error(&error); + g_object_unref(nmProxy); + return false; } - if (g_variant_is_of_type (result, (const GVariantType *) "(o)")) - { - g_variant_get(result, "(o)", &device_path); - if(device_path != NULL) - { - path = std::string(device_path); - ret = true; - g_free(device_path); - } - } - //NMLOG_DEBUG("%s device path %s", iface_name, path.c_str()); + gchar *devicePath; + g_variant_get(result, "(o)", &devicePath); + g_variant_unref(result); - return ret; + g_object_unref(nmProxy); + + path = std::string(devicePath); + g_free(devicePath); + + return true; } bool GnomeUtils::getApDetails(DbusMgr& m_dbus, const char* apPath, Exchange::INetworkManager::WiFiSSIDInfo& wifiInfo) @@ -546,6 +572,167 @@ namespace WPEFramework return true; } + bool GnomeUtils::activateConnection(DbusMgr& m_dbus, const std::string& connectionProfile, const std::string& devicePath) + { + GError* error = nullptr; + GDBusProxy* nmProxy = m_dbus.getNetworkManagerProxy(); + if(nmProxy == NULL) + return false; + + GVariant* result = g_dbus_proxy_call_sync( + nmProxy, + "ActivateConnection", + g_variant_new("(ooo)", connectionProfile.c_str(), devicePath.c_str(), "/"), + G_DBUS_CALL_FLAGS_NONE, + -1, + nullptr, + &error + ); + + if (error) { + NMLOG_ERROR("ActivateConnection Error: %s", error->message); + g_error_free(error); + } else if (result != nullptr) { + g_variant_unref(result); + } + return true; + } + + bool GnomeUtils::getSettingsConnectionPath(DbusMgr &m_dbus, std::string& connectionPath, const std::string& interface) + { + GDBusProxy *nmProxy = nullptr; + bool found = false; + nmProxy = m_dbus.getNetworkManagerProxy(); + if(nmProxy == nullptr) + return false; + GVariant *activeConnections = g_dbus_proxy_get_cached_property(nmProxy, "ActiveConnections"); + if (activeConnections == nullptr) { + NMLOG_ERROR("Error retrieving active connections"); + g_object_unref(nmProxy); + return false; + } + + GVariantIter iter; + g_variant_iter_init(&iter, activeConnections); + gchar *activeConnectionPath = nullptr; + while (g_variant_iter_loop(&iter, "o", &activeConnectionPath)) { + GDBusProxy *activeConnectionProxy = m_dbus.getNetworkManagerActiveConnProxy(activeConnectionPath); + + if (activeConnectionProxy == nullptr) { + NMLOG_ERROR("Error creating active connection proxy"); + continue; + } + + GVariant *devicesVar = g_dbus_proxy_get_cached_property(activeConnectionProxy, "Devices"); + if (devicesVar == nullptr) { + NMLOG_ERROR("Error retrieving devices property"); + g_object_unref(activeConnectionProxy); + continue; + } + + GVariantIter devicesIter; + g_variant_iter_init(&devicesIter, devicesVar); + gchar *devicePath = nullptr; + + while (g_variant_iter_loop(&devicesIter, "o", &devicePath)) { + GDBusProxy *deviceProxy = m_dbus.getNetworkManagerDeviceProxy(devicePath); + + if (deviceProxy == nullptr) { + NMLOG_ERROR("Error creating device proxy"); + continue; + } + + GVariant *ifaceProperty = g_dbus_proxy_get_cached_property(deviceProxy, "Interface"); + if (ifaceProperty) { + const gchar *iface = g_variant_get_string(ifaceProperty, nullptr); + if (interface == iface) { + found = true; + GVariant *connectionProperty = g_dbus_proxy_get_cached_property(activeConnectionProxy, "Connection"); + if (connectionProperty) { + connectionPath = g_variant_get_string(connectionProperty, nullptr); + g_variant_unref(connectionProperty); + } else { + NMLOG_ERROR("Error retrieving connection property"); + } + + g_variant_unref(ifaceProperty); + g_object_unref(deviceProxy); + break; + } + g_variant_unref(ifaceProperty); + } + + g_object_unref(deviceProxy); + } + g_variant_unref(devicesVar); + g_object_unref(activeConnectionProxy); + + if (found) { + break; + } + } + + g_variant_unref(activeConnections); + g_object_unref(nmProxy); + return true; + } + + // Convert IPv4 string to network byte order (NBO) + uint32_t GnomeUtils::ip4StrToNBO(const std::string &ipAddress) + { + struct in_addr addr; + if (inet_pton(AF_INET, ipAddress.c_str(), &addr) != 1) { + NMLOG_ERROR("Invalid IPv4 address format: %s", ipAddress.c_str()); + } + return addr.s_addr; + } + + // Convert an IPv6 string address to an array of bytes + std::array GnomeUtils::ip6StrToNBO(const std::string &ipAddress) + { + struct in6_addr addr6; + inet_pton(AF_INET6, ipAddress.c_str(), &addr6); + std::array ip6{}; + std::memcpy(ip6.data(), &addr6, 16); + return ip6; + } + + // Helper function to convert a raw IPv4 address to human-readable format + std::string GnomeUtils::ip4ToString(uint32_t ip) { + ip = ntohl(ip); // Convert from network to host byte order + char buf[INET_ADDRSTRLEN] = {0}; + snprintf(buf, sizeof(buf), "%u.%u.%u.%u", + (ip >> 24) & 0xFF, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + ip & 0xFF); + return std::string(buf); + } + + // Helper function to convert a raw IPv6 address to human-readable format + std::string GnomeUtils::ip6ToString(const uint8_t *ipv6) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, ipv6, buf, sizeof(buf)); + return std::string(buf); + } + + // Helper function to add elements from GVariant to GVariantBuilder + void GnomeUtils::addGvariantToBuilder(GVariant *variant, GVariantBuilder *builder, gboolean excludeRouteMetric) { + GVariantIter iter; + + const gchar *key; + GVariant *value; + g_variant_iter_init(&iter, variant); + + // Iterate through key-value pairs in the dictionary + while (g_variant_iter_loop(&iter, "{&sv}", &key, &value)) { + if (excludeRouteMetric && strcmp(key, "route-metric") == 0) { + // Skip adding this key-value pair if exclude_route_metric is TRUE and key is "route-metric" + continue; + } + g_variant_builder_add(builder, "{sv}", key, value); + } + } } // Plugin } // WPEFramework diff --git a/gdbus/NetworkManagerGdbusUtils.h b/gdbus/NetworkManagerGdbusUtils.h index 6366ff71..40f5d345 100644 --- a/gdbus/NetworkManagerGdbusUtils.h +++ b/gdbus/NetworkManagerGdbusUtils.h @@ -48,6 +48,8 @@ struct deviceInfo std::string interface; std::string activeConnPath; std::string path; + std::string MAC; + bool managed; NMDeviceState state; NMDeviceStateReason stateReason; NMDeviceType deviceType; @@ -72,8 +74,16 @@ namespace WPEFramework static bool getDevicePropertiesByPath(DbusMgr& m_dbus, const char* devPath, deviceInfo& properties); static bool getDeviceInfoByIfname(DbusMgr& m_dbus, const char* ifname, deviceInfo& properties); static bool getCachedPropertyU(GDBusProxy* proxy, const char* propertiy, uint32_t *value); + static bool getCachedPropertyBoolean(GDBusProxy* proxy, const char* property, bool *value); static bool getIPv4AddrFromIPv4ConfigProxy(GDBusProxy *ipProxy, std::string& ipAddr, uint32_t& prifix); static bool getIPv6AddrFromIPv6ConfigProxy(GDBusProxy *ipProxy, std::string& ipAddr, uint32_t& prifix); + static bool activateConnection(DbusMgr& m_dbus, const std::string& connectionProfile, const std::string& devicePath); + static bool getSettingsConnectionPath(DbusMgr &m_dbus, std::string& connectionPath, const std::string& interface); + static uint32_t ip4StrToNBO(const std::string &ipAddress); + static std::array ip6StrToNBO(const std::string &ipAddress); + static std::string ip4ToString(uint32_t ip); + static std::string ip6ToString(const uint8_t *ipv6); + static void addGvariantToBuilder(GVariant *variant, GVariantBuilder *builder, gboolean excludeRouteMetric); static bool convertSsidInfoToJsonObject(Exchange::INetworkManager::WiFiSSIDInfo& wifiInfo, JsonObject& ssidObj); static const char* convertPercentageToSignalStrengtStr(int percentage);