From 5ef90db242ad29c9772f2237b477c58ef65545c7 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 28 Jan 2022 16:54:55 -0500 Subject: Re-enable network support Rework network support code to use new connman-glib library instead of the previously disabled agl-service-network API. The only user visible change is that a few extra previously exported header files have been pruned from installation to avoid exposing GLib usage and potentially requiring users needing to build against it. Bug-AGL: SPEC-4182 Signed-off-by: Scott Murray Change-Id: Iab8f3c9d04ee603e06b80dfd92ac03d9d52af477 --- CMakeLists.txt | 2 +- network/CMakeLists.txt | 5 +- network/abstractnetworkmodel.cpp | 55 ++-- network/abstractnetworkmodel.h | 10 +- network/network.cpp | 554 ++++++++++++++++----------------------- network/network.h | 82 +++--- network/networkadapter.h | 11 +- network/networkeventhandler.cpp | 302 +++++++++++++++++++++ network/networkeventhandler.h | 83 ++++++ network/wifiadapter.cpp | 169 +++++++----- network/wifiadapter.h | 29 +- network/wifinetworkmodel.cpp | 115 ++++---- network/wifinetworkmodel.h | 22 +- network/wiredadapter.cpp | 177 ++++++++----- network/wiredadapter.h | 21 +- network/wirednetworkmodel.cpp | 175 +++++++------ network/wirednetworkmodel.h | 20 +- 17 files changed, 1124 insertions(+), 708 deletions(-) create mode 100644 network/networkeventhandler.cpp create mode 100644 network/networkeventhandler.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 38c2c2b..f69e364 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ find_package(Qt5Qml REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(glib REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(bluez_glib REQUIRED IMPORTED_TARGET bluez-glib) -#pkg_check_modules(connman_glib REQUIRED IMPORTED_TARGET connman-glib) +pkg_check_modules(connman_glib REQUIRED IMPORTED_TARGET connman-glib) include(GNUInstallDirs) diff --git a/network/CMakeLists.txt b/network/CMakeLists.txt index b7ae7a1..6627a68 100644 --- a/network/CMakeLists.txt +++ b/network/CMakeLists.txt @@ -4,6 +4,7 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qtappfw-network.pc DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) add_library(qtappfw-network SHARED network.cpp + networkeventhandler.cpp wifiadapter.cpp wiredadapter.cpp wifinetworkmodel.cpp @@ -14,11 +15,11 @@ add_library(qtappfw-network SHARED network.cpp target_include_directories(qtappfw-network PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") target_include_directories(qtappfw-network PUBLIC "${CMAKE_INSTALL_INCLUDEDIR}") -target_link_libraries(qtappfw-network Qt5::Qml) +target_link_libraries(qtappfw-network Qt5::Qml PkgConfig::glib PkgConfig::connman_glib) set_target_properties(qtappfw-network PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 - PUBLIC_HEADER "network.h;networkadapter.h;wifiadapter.h;wiredadapter.h;wifinetworkmodel.h;wirednetworkmodel.h;abstractnetworkmodel.h;connectionprofile.h") + PUBLIC_HEADER "network.h;networkadapter.h;wifiadapter.h;wiredadapter.h") install(TARGETS qtappfw-network LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/network/abstractnetworkmodel.cpp b/network/abstractnetworkmodel.cpp index ad5a31a..d8cd984 100644 --- a/network/abstractnetworkmodel.cpp +++ b/network/abstractnetworkmodel.cpp @@ -10,56 +10,57 @@ AbstractNetworkModel::AbstractNetworkModel(QObject *parent) void AbstractNetworkModel::addNetwork(ConnectionProfile *network) { - beginInsertRows(QModelIndex(), rowCount(), rowCount()); - m_networks.insert(rowCount(), network); - endInsertRows(); + int start_rows = rowCount(); + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + m_networks.insert(rowCount(), network); + endInsertRows(); } void AbstractNetworkModel::removeNetwork(ConnectionProfile *network) { - if (m_networks.isEmpty() || (network == nullptr)) - return; + if (m_networks.isEmpty() || (network == nullptr)) + return; - int row = m_networks.indexOf(network); - beginRemoveRows(QModelIndex(), row, row); - m_networks.removeAt(row); - endRemoveRows(); - delete network; + int row = m_networks.indexOf(network); + beginRemoveRows(QModelIndex(), row, row); + m_networks.removeAt(row); + endRemoveRows(); + delete network; } void AbstractNetworkModel::removeAllNetworks() { - if (m_networks.isEmpty()) - return; + if (m_networks.isEmpty()) + return; - beginRemoveRows(QModelIndex(), 0, m_networks.count() - 1); - qDeleteAll(m_networks.begin(), m_networks.end()); - endRemoveRows(); - m_networks.clear(); + beginRemoveRows(QModelIndex(), 0, m_networks.count() - 1); + qDeleteAll(m_networks.begin(), m_networks.end()); + endRemoveRows(); + m_networks.clear(); } ConnectionProfile *AbstractNetworkModel::getNetwork(QString service) { - if (m_networks.isEmpty()) - return nullptr; + if (m_networks.isEmpty()) + return nullptr; - for (auto network : m_networks) { - if (network->service() == service) - return network; - } + for (auto network : m_networks) { + if (network->service() == service) + return network; + } - return nullptr; + return nullptr; } int AbstractNetworkModel::rowCount(const QModelIndex &parent) const { - Q_UNUSED(parent); - return m_networks.count(); + Q_UNUSED(parent); + return m_networks.count(); } QModelIndex AbstractNetworkModel::indexOf(ConnectionProfile *network) { - int row = m_networks.indexOf(network); + int row = m_networks.indexOf(network); - return index(row); + return index(row); } diff --git a/network/abstractnetworkmodel.h b/network/abstractnetworkmodel.h index 1b0db43..349c109 100644 --- a/network/abstractnetworkmodel.h +++ b/network/abstractnetworkmodel.h @@ -4,15 +4,14 @@ #include #include #include -#include #include "connectionprofile.h" class AbstractNetworkModel : public QAbstractListModel { - Q_OBJECT + Q_OBJECT - public: +public: AbstractNetworkModel(QObject *parent = Q_NULLPTR); virtual QString getType() const = 0; @@ -23,10 +22,11 @@ class AbstractNetworkModel : public QAbstractListModel int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0; - virtual void updateProperties(QString service, QJsonObject properties) =0; + virtual void updateProperties(const QString &service, const QVariantMap &properties) = 0; - protected: +protected: QList m_networks; QModelIndex indexOf(ConnectionProfile *network); }; + #endif // ABSTRACT_NETWORK_MODEL_H diff --git a/network/network.cpp b/network/network.cpp index 937266f..52cafad 100644 --- a/network/network.cpp +++ b/network/network.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2021 Konsulko Group + * Copyright (C) 2018-2022 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,408 +16,316 @@ #include #include +#include +#include -#include "networkadapter.h" +#include "wifiadapter.h" +#include "wiredadapter.h" #include "network.h" +#include "networkeventhandler.h" - -Network::Network (bool register_agent, QQmlContext *context, QObject * parent) : - QObject(parent) +Network::Network(bool register_agent, QQmlContext *context, QObject * parent) : + QObject(parent), + m_agent(register_agent) { - m_adapters.append(new WifiAdapter(this, context, parent)); - m_adapters.append(new WiredAdapter(this, context, parent)); + m_adapters.append(new WifiAdapter(this, context, parent)); + m_adapters.append(new WiredAdapter(this, context, parent)); + + m_event_handler = new NetworkEventHandler(this, register_agent, context, parent); + + // Hook up signals so updates can be made to happen from the UI thread as Qt requires + QObject::connect(m_event_handler, &NetworkEventHandler::adapterStatusChanged, this, &Network::updateAdapterStatus, Qt::QueuedConnection); + QObject::connect(m_event_handler, &NetworkEventHandler::servicePropertiesChanged, this, &Network::updateServiceProperties, Qt::QueuedConnection); + QObject::connect(m_event_handler, &NetworkEventHandler::serviceAdded, this, &Network::addService, Qt::QueuedConnection); + QObject::connect(m_event_handler, &NetworkEventHandler::serviceRemoved, this, &Network::removeService, Qt::QueuedConnection); + QObject::connect(m_event_handler, &NetworkEventHandler::inputRequested, this, &Network::requestInput, Qt::QueuedConnection); + QObject::connect(m_event_handler, &NetworkEventHandler::connectResponseReceived, this, &Network::handleConnectResponse, Qt::QueuedConnection); + + connman_init(register_agent); + + getTechnologies(); } Network::~Network() { - while (!m_adapters.isEmpty()) - m_adapters.takeLast(); + while (!m_adapters.isEmpty()) + m_adapters.takeLast(); } void Network::connect(QString service) { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; + QByteArray service_ba = service.toLocal8Bit(); + const char *service_cstr = service_ba.data(); - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; - - parameter.insert("service", service); - - nmsg->createRequest("network-manager", "connect_service", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + connman_service_connect(service_cstr, m_event_handler->service_connect_cb, m_event_handler); } void Network::disconnect(QString service) { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; + QByteArray service_ba = service.toLocal8Bit(); + const char *service_cstr = service_ba.data(); - parameter.insert("service", service); - - nmsg->createRequest("network-manager", "disconnect_service", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + connman_service_disconnect(service_cstr); } void Network::remove(QString service) { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; + QByteArray service_ba = service.toLocal8Bit(); + const char *service_cstr = service_ba.data(); - parameter.insert("service", service); - - nmsg->createRequest("network-manager", "remove_service", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + connman_service_remove(service_cstr); } void Network::power(bool on, QString type) { - if (on) - enableTechnology(type); - else - disableTechnology(type); + if (on) + enableTechnology(type); + else + disableTechnology(type); } void Network::input(int id, QString passphrase) { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter, fields; - - parameter.insert("id", id); - fields.insert("passphrase", passphrase); - parameter.insert("fields", fields); - - nmsg->createRequest("network-manager", "agent_response", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + QByteArray passphrase_ba = passphrase.toLocal8Bit(); + const char *passphrase_cstr = passphrase_ba.data(); + + // e.g. ({'Passphrase': <'foo'>},) + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&builder, + "{sv}", + "Passphrase", + g_variant_new_string(passphrase_cstr)); + + // Wrap in required tuple + GVariantBuilder builder2; + g_variant_builder_init(&builder2, G_VARIANT_TYPE_TUPLE); + g_variant_builder_add_value(&builder2, + g_variant_builder_end(&builder)); + GVariant *parameters = g_variant_builder_end(&builder2); + + if (parameters) { + connman_agent_response(id, parameters); + } else { + qWarning() << "Could not build response for input request " << id; + } } void Network::configureAddress(QString service, QVariantList paramlist) { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter, type, properties; - QJsonArray values = QJsonArray::fromVariantList(paramlist); - - if (values.isEmpty() || values.count() < 4) { - qWarning("Invalid addressing params"); - return; - } - - properties.insert("method", values[0]); - properties.insert("address", values[1]); - properties.insert("netmask", values[2]); - properties.insert("gateway", values[3]); - type.insert("ipv4.configuration", properties); - parameter.insert("properties", type); - parameter.insert("service", service); - - nmsg->createRequest("network-manager", "set_property", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + if (service.isEmpty() || paramlist.size() < 4) { + qWarning("Invalid addressing params"); + return; + } + + QByteArray path_ba = service.toLocal8Bit(); + + GVariantDict *params_dict = g_variant_dict_new(NULL); + if (!params_dict) { + qWarning() << "g_variant_dict_new failed"; + return; + } + + QByteArray param_ba = paramlist[0].toString().toLocal8Bit(); + g_variant_dict_insert(params_dict, "Method", "s", param_ba.data()); + param_ba = paramlist[1].toString().toLocal8Bit(); + g_variant_dict_insert(params_dict, "Address", "s", param_ba.data()); + param_ba = paramlist[2].toString().toLocal8Bit(); + g_variant_dict_insert(params_dict, "Netmask", "s", param_ba.data()); + param_ba = paramlist[3].toString().toLocal8Bit(); + g_variant_dict_insert(params_dict, "Gateway", "s", param_ba.data()); + GVariant *parameters = g_variant_dict_end(params_dict); + g_variant_dict_unref(params_dict); + + // Need to end up with something like: + // - path = ethernet_525400123502_cable + // - name = IPv4.Configuration + // - parameters = {'Method': <'manual'>, 'Gateway': <'10.0.2.2'>, 'Address': <'10.0.2.15'>, 'Netmask': <'255.255.255'>} + if (!connman_set_property(CONNMAN_PROPERTY_SERVICE, + path_ba.data(), + "IPv4.Configuration", + parameters)) { + qWarning() << "Could not configure address"; + } } void Network::configureNameServer(QString service, QVariantList paramlist) { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter, properties; - QJsonArray values = QJsonArray::fromVariantList(paramlist); - - if (values.isEmpty() || values.count() < 2) { - qWarning("Invalid nameserver params"); - return; - } - - QStringList nslist = values[1].toString().split(' '); - QJsonArray nameservers = QJsonArray::fromStringList(nslist); - - properties.insert("nameservers.configuration", nameservers); - parameter.insert("properties", properties); - parameter.insert("service", service); - - nmsg->createRequest("network-manager", "set_property", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + // paramlist will be 'manual|auto', 'server1'... + // NOTE: currently unclear what should happen for 'auto' case + if (service.isEmpty() || paramlist.size() < 2) { + qWarning("Invalid nameserver params"); + return; + } + + QByteArray path_ba = service.toLocal8Bit(); + + QStringList nslist = paramlist[1].toString().split(' '); + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE("as")); + QStringList::const_iterator iter; + for (iter = nslist.constBegin(); iter != nslist.constEnd(); ++iter) { + g_variant_builder_add(&builder, + "s", + (*iter).toLocal8Bit().constData()); + } + GVariant *parameters = g_variant_builder_end(&builder); + + // Need to end up with something like: + // - path = ethernet_525400123502_cable + // - name = Nameservers.Configuration + // - value = ['8.8.8.8.8'] + if (!connman_set_property(CONNMAN_PROPERTY_SERVICE, + path_ba.data(), + "Nameservers.Configuration", + parameters)) { + qWarning() << "Could not configure nameserver"; + } } void Network::getServices() { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; - - nmsg->createRequest("network-manager", "services", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + GVariant *reply = NULL; + if(!connman_get_services(&reply)) { + qWarning() << "Network::getServices: connman_get_services failed!"; + return; + } + + GVariantIter *array = NULL; + g_variant_get(reply, "(a(oa{sv}))", &array); + const gchar *path = NULL; + GVariant *var = NULL; + while (g_variant_iter_next(array, "(o@a{sv})", &path, &var)) { + QString id = path; + id = id.mid(id.lastIndexOf("/") + 1); + QVariantMap props_map; + if (m_event_handler->populateServiceProperties(var, props_map)) { + QList::iterator iter; + for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) + if ((*iter)->addService(id, props_map)) + break; + } + g_variant_unref(var); + } + g_variant_iter_free(array); + g_variant_unref(reply); } -AdapterIf* Network::findAdapter(QString type) +AdapterIf* Network::findAdapter(const QString &type) { - QList::iterator iter; - for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) - if ((*iter)->getType() == type) - return (*iter); - return nullptr; + QList::iterator iter; + for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) + if ((*iter)->getType() == type) + return (*iter); + return nullptr; } -void Network::updateServiceProperties(QJsonObject data) +void Network::scanServices(const QString &technology) { -#if 0 - QString service = data.value("service").toString(); - QJsonObject properties = data.value("properties").toObject(); - QList::iterator iter; - for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) - (*iter)->updateProperties(service, properties); -#endif -} + QByteArray technology_ba = technology.toLocal8Bit(); + const char *technology_cstr = technology_ba.data(); -bool Network::addService(QJsonObject service) -{ -#if 0 - QString id = service.value("service").toString(); - QJsonObject properties = service.value("properties").toObject(); - QList::iterator iter; - for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) - if ((*iter)->addService(id, properties)) - return true; -#endif - return false; + connman_technology_scan_services(technology_cstr); } -void Network::removeService(QJsonObject service) +void Network::disableTechnology(const QString &technology) { -#if 0 - QString id = service.value("service").toString(); - QList::iterator iter; - for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) - (*iter)->removeService(id); -#endif -} + QByteArray technology_ba = technology.toLocal8Bit(); + const char *technology_cstr = technology_ba.data(); -void Network::addServices(QJsonArray services) -{ - for (auto service : services) - addService(service.toObject()); + connman_technology_disable(technology_cstr); } -void Network::scanServices(QString type) +void Network::enableTechnology(const QString &technology) { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; - - parameter.insert("technology", type); - nmsg->createRequest("network-manager", "scan_services", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif -} + QByteArray technology_ba = technology.toLocal8Bit(); + const char *technology_cstr = technology_ba.data(); -void Network::disableTechnology(QString type) -{ -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; - - parameter.insert("technology", type); - nmsg->createRequest("network-manager", "disable_technology", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + connman_technology_enable(technology_cstr); } -void Network::enableTechnology(QString type) +void Network::getTechnologies() { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; - - parameter.insert("technology", type); - nmsg->createRequest("network-manager", "enable_technology", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + GVariant *reply = NULL; + if(!connman_get_technologies(&reply)) + return; + + GVariantIter *array = NULL; + g_variant_get(reply, "(a(oa{sv}))", &array); + if (!array) { + g_variant_unref(reply); + return; + } + const gchar *path = NULL; + GVariant *properties = NULL; + while (g_variant_iter_next(array, "(o@a{sv})", &path, &properties)) { + GVariantDict *props_dict = g_variant_dict_new(properties); + gchar *type_cstr = NULL; + if (g_variant_dict_lookup(props_dict, "Type", "s", &type_cstr)) { + QString type(type_cstr); + AdapterIf* adapter = findAdapter(type); + if (adapter) { + QVariantMap props_map; + if (m_event_handler->populateAdapterProperties(properties, props_map)) + adapter->updateStatus(props_map); + } + } + g_variant_dict_unref(props_dict); + g_variant_unref(properties); + } + g_variant_iter_free(array); + g_variant_unref(reply); } -void Network::parseTechnologies(QJsonArray technologies) +void Network::updateAdapterStatus(const QString &technology, const QVariantMap &properties) { -#if 0 - for (auto value : technologies) { - QJsonObject technology = value.toObject(); - QJsonObject properties = technology.value("properties").toObject(); - QString type = properties.value("type").toString(); - - AdapterIf* adapter = findAdapter(type); + AdapterIf* adapter = findAdapter(technology); if (adapter) - adapter->updateStatus(properties); - } -#endif + adapter->updateStatus(properties); } -void Network::getTechnologies() +void Network::updateServiceProperties(const QString &service, const QVariantMap &properties) { -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; - - nmsg->createRequest("network-manager", "technologies", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif + QList::iterator iter; + for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) + (*iter)->updateProperties(service, properties); } -#if 0 -void Network::processEvent(std::shared_ptr msg) +void Network::addService(const QString &service, const QVariantMap &properties) { - - std::shared_ptr emsg = std::static_pointer_cast(msg); - QString ename = emsg->eventName(); - QString eapi = emsg->eventApi(); - QJsonObject data = emsg->eventData(); - - if (eapi != "network-manager") - return; - - if (ename == "agent") { - QJsonObject fields = data.value("fields").toObject(); - QJsonObject passphrase = fields.value("passphrase").toObject(); - QString type = passphrase.value("type").toString(); - QString reqmt = passphrase.value("requirement").toString(); - if (((type == "psk") || (type == "wep")) && (reqmt == "mandatory")) { - int id = data.value("id").toInt(); - emit inputRequest(id); - } - } else if (ename == "services") { - QJsonArray services = data.value("values").toArray(); - for (auto value : services) { - QJsonObject service = value.toObject(); - QString action = service.value("action").toString(); - if (action == "changed") { - addService(service); - } else if (action == "removed") { - removeService(service); - } - } - } else if (ename == "service_properties") { - updateServiceProperties(data); - } else if (ename == "technology_properties") { - QJsonObject properties = data.value("properties").toObject(); - QString type = data.value("technology").toString(); - AdapterIf* adapter = findAdapter(type); - if (adapter) - adapter->updateStatus(properties); - } + QList::iterator iter; + for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) + if ((*iter)->addService(service, properties)) + break; } -void Network::processReply(std::shared_ptr msg) +void Network::removeService(const QString &service) { - std::shared_ptr rmsg = std::static_pointer_cast(msg); - QString verb = rmsg->requestVerb(); - QJsonObject data = rmsg->replyData(); - - if (verb == "services") { - addServices(data.value("values").toArray()); - } else if (verb == "technologies") { - parseTechnologies(data.value("values").toArray()); - } else if (verb == "connect_service") { - if (rmsg->replyStatus() == "failed" && rmsg->replyInfo().contains("invalid-key")) { - emit invalidPassphrase(rmsg->requestParameters()["service"].toString()); - } - } + QList::iterator iter; + for (iter = m_adapters.begin(); iter != m_adapters.end(); ++iter) + (*iter)->removeService(service); } -void Network::onMessageReceived(std::shared_ptr msg) +void Network::requestInput(int id, const QVariantMap &properties) { - if (!msg) - return; + QString type; + QString key = "Type"; + if (properties.contains(key)) + type = properties.value(key).toString(); - if (msg->isEvent()) - processEvent(msg); - else if (msg->isReply()) - processReply(msg); -} -#endif + QString reqmt; + key = "Requirement"; + if (properties.contains(key)) + reqmt = properties.value(key).toString(); -void Network::onConnected() -{ -#if 0 - QStringListIterator eventIterator(events); - - while (eventIterator.hasNext()) { - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* nmsg = static_cast(msg.get()); - QJsonObject parameter; - parameter.insert("value", eventIterator.next()); - nmsg->createRequest("network-manager", "subscribe", parameter); - m_mloop->sendMessage(std::move(msg)); - } -#endif - getTechnologies(); + if (((type == "psk") || (type == "wep")) && (reqmt == "mandatory")) { + emit inputRequest(id); + } } -void Network::onDisconnected() +void Network::handleConnectResponse(const QString &service, bool status, const QString &error) { -#if 0 - QStringListIterator eventIterator(events); - - while (eventIterator.hasNext()) { - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - CallMessage *nmsg = static_cast(msg.get()); - QJsonObject parameter; - parameter.insert("value", eventIterator.next()); - nmsg->createRequest("network-manager", "unsubscribe", parameter); - m_mloop->sendMessage(std::move(msg)); - } -#endif - getTechnologies(); + if (!status && error.contains("invalid-key")) { + emit invalidPassphrase(service); + } } diff --git a/network/network.h b/network/network.h index 3321a81..06d1e6f 100644 --- a/network/network.h +++ b/network/network.h @@ -19,66 +19,56 @@ #include #include -#include -#include #include #include -#include "wifiadapter.h" -#include "wiredadapter.h" +class NetworkEventHandler; +class AdapterIf; class Network : public QObject { - Q_OBJECT + Q_OBJECT - public: - explicit Network(bool register_agent, QQmlContext *context, QObject * parent = Q_NULLPTR); - virtual ~Network(); +public: + explicit Network(bool register_agent, QQmlContext *context, QObject * parent = Q_NULLPTR); + virtual ~Network(); - Q_INVOKABLE void connect(QString service); - Q_INVOKABLE void disconnect(QString service); - Q_INVOKABLE void remove(QString service); - Q_INVOKABLE void power(bool on, QString type = "wifi"); - Q_INVOKABLE void input(int id, QString passphrase); - Q_INVOKABLE void configureAddress(QString service, QVariantList paramlist); - Q_INVOKABLE void configureNameServer(QString service, QVariantList paramlist); + Q_INVOKABLE void connect(QString service); + Q_INVOKABLE void disconnect(QString service); + Q_INVOKABLE void remove(QString service); + Q_INVOKABLE void power(bool on, QString type = "wifi"); + Q_INVOKABLE void input(int id, QString passphrase); + Q_INVOKABLE void configureAddress(QString service, QVariantList paramlist); + Q_INVOKABLE void configureNameServer(QString service, QVariantList paramlist); - void getServices(); - AdapterIf* findAdapter(QString type); + AdapterIf* findAdapter(const QString &technology); + void getServices(); - signals: - void inputRequest(int id); - void invalidPassphrase(QString service); - void searchResults(QString name); +signals: + void inputRequest(int id); + void invalidPassphrase(const QString &service); + void searchResults(const QString &name); - private: - QQmlContext *m_context; - QList m_adapters; +private: + NetworkEventHandler *m_event_handler; + bool m_agent; + QList m_adapters; - void updateServiceProperties(QJsonObject data); - bool addService(QJsonObject service); - void removeService(QJsonObject remove); + void scanServices(const QString &technology); + void disableTechnology(const QString &technology); + void enableTechnology(const QString &technology); + void getTechnologies(); - void addServices(QJsonArray services); + friend class NetworkEventHandler; - void scanServices(QString type); - void disableTechnology(QString type); - void enableTechnology(QString type); - void parseTechnologies(QJsonArray technologies); - void getTechnologies(); - - // slots - void onConnected(); - void onDisconnected(); - - const QStringList events { - "agent", - "global_state", - "services", - "service_properties", - "technologies", - "technology_properties", - }; +private slots: + // Invoked by NetworkEventHandler signals to drive model updates on UI thread + void updateAdapterStatus(const QString &technology, const QVariantMap &properties); + void updateServiceProperties(const QString &service, const QVariantMap &properties); + void addService(const QString &service, const QVariantMap &properties); + void removeService(const QString &service); + void requestInput(int id, const QVariantMap &properties); + void handleConnectResponse(const QString &service, bool status, const QString &error); }; #endif // NETWORK_H diff --git a/network/networkadapter.h b/network/networkadapter.h index b3291f0..d808f48 100644 --- a/network/networkadapter.h +++ b/network/networkadapter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Konsulko Group + * Copyright (C) 2019,2022 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ #include #include -#include #include class Network; @@ -31,12 +30,12 @@ class AdapterIf public: virtual ~AdapterIf() {}; - virtual bool addService(QString id, QJsonObject properties) = 0; - virtual void removeService(QString id) = 0; - virtual void updateProperties(QString service, QJsonObject properties) = 0; + virtual bool addService(QString const &id, QVariantMap const &properties) = 0; + virtual void removeService(QString const &id) = 0; + virtual void updateProperties(QString const &service, QVariantMap const &properties) = 0; virtual QString getType() = 0; - virtual void updateStatus(QJsonObject properties) = 0; + virtual void updateStatus(QVariantMap const &properties) = 0; }; Q_DECLARE_INTERFACE(AdapterIf, "AdapterIf") diff --git a/network/networkeventhandler.cpp b/network/networkeventhandler.cpp new file mode 100644 index 0000000..3023e45 --- /dev/null +++ b/network/networkeventhandler.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2022 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "networkeventhandler.h" +#include "network.h" +#include "networkadapter.h" + + +NetworkEventHandler::NetworkEventHandler(Network *network, + bool register_agent, + QQmlContext *context, + QObject * parent) : + QObject(parent), + m_network(network), + m_agent(register_agent) +{ + connman_add_manager_event_callback(manager_event_cb, this); + connman_add_technology_property_event_callback(technology_event_cb, this); + connman_add_service_property_event_callback(service_event_cb, this); + if (register_agent) + connman_add_agent_event_callback(agent_event_cb, this); +} + +NetworkEventHandler::~NetworkEventHandler() +{ +} + +bool NetworkEventHandler::populateAdapterProperties(GVariant *in, QVariantMap &out) +{ + GVariantDict *props_dict = g_variant_dict_new(in); + if (!props_dict) + return false; + + gchar *p = NULL; + gboolean value = FALSE; + if (g_variant_dict_lookup(props_dict, "Connected", "b", &value)) + out.insert(QString("Connected"), QVariant((bool) value)); + + if (g_variant_dict_lookup(props_dict, "Powered", "b", &value)) + out.insert(QString("Powered"), QVariant((bool) value)); + + g_variant_dict_unref(props_dict); + + return true; +} + +bool NetworkEventHandler::populateServiceProperties(GVariant *in, QVariantMap &out) +{ + GVariantDict *props_dict = g_variant_dict_new(in); + if (!props_dict) + return false; + + gchar *p = NULL; + if (g_variant_dict_lookup(props_dict, "Type", "&s", &p)) + out.insert(QString("Type"), QVariant(QString(p))); + + if (g_variant_dict_lookup(props_dict, "Name", "&s", &p)) + out.insert(QString("Name"), QVariant(QString(p))); + + if (g_variant_dict_lookup(props_dict, "State", "&s", &p)) + out.insert(QString("State"), QVariant(QString(p))); + + guchar strength = 0; + if (g_variant_dict_lookup(props_dict, "Strength", "y", &strength)) + out.insert(QString("Strength"), QVariant((int) strength)); + + GVariant *v = NULL; + if (g_variant_dict_lookup(props_dict, "IPv4", "@a{sv}", &v)) { + GVariantDict *ip4_dict = g_variant_dict_new(v); + QVariantMap ip4_map; + + if (g_variant_dict_lookup(ip4_dict, "Address", "&s", &p)) + ip4_map.insert(QString("Address"), QVariant(QString(p))); + + if (g_variant_dict_lookup(ip4_dict, "Netmask", "&s", &p)) + ip4_map.insert(QString("Netmask"), QVariant(QString(p))); + + if (g_variant_dict_lookup(ip4_dict, "Gateway", "&s", &p)) + ip4_map.insert(QString("Gateway"), QVariant(QString(p))); + + if (g_variant_dict_lookup(ip4_dict, "Method", "&s", &p)) + ip4_map.insert(QString("Method"), QVariant(QString(p))); + + g_variant_dict_unref(ip4_dict); + g_variant_unref(v); + + if (!ip4_map.isEmpty()) + out.insert(QString("IPv4"), QVariant(ip4_map)); + } + + if (g_variant_dict_lookup(props_dict, "Nameservers", "&s", &v)) + out.insert(QString("Nameservers"), QVariant(QString(p))); + + GVariantIter *array = NULL; + if (g_variant_dict_lookup(props_dict, "Security", "as", &array)) { + QVariantList security; + + while (g_variant_iter_loop(array, "&s", &p)) + security.push_back(QVariant(QString(p))); + + if (!security.isEmpty()) + out.insert(QString("Security"), QVariant(security)); + + g_variant_iter_free(array); + } + + g_variant_dict_unref(props_dict); + + return !out.isEmpty(); +} + +void NetworkEventHandler::handle_connect_event(const gchar *service, gboolean status, const gchar *error) +{ + if (!status) + qDebug() << "connect failed, error " << error; + + emit connectResponseReceived(QString(service), status, QString(error)); +} + +void NetworkEventHandler::handle_manager_event(const gchar *path, + connman_manager_event_t event, + GVariant *properties) +{ +#if LIBQTAPPFW_NETWORK_DEBUG + QString props("NULL"); + QString event_str(""); + switch(event) { + case CONNMAN_MANAGER_EVENT_TECHNOLOGY_ADD: + event_str = "TECHNOLOGY_ADD"; + break; + case CONNMAN_MANAGER_EVENT_TECHNOLOGY_REMOVE: + event_str = "TECHNOLOGY_REMOVE"; + break; + case CONNMAN_MANAGER_EVENT_SERVICE_CHANGE: + event_str = "SERVICE_CHANGE"; + break; + case CONNMAN_MANAGER_EVENT_SERVICE_REMOVE: + event_str = "SERVICE_REMOVE"; + break; + case CONNMAN_MANAGER_EVENT_PROPERTY_CHANGE: + event_str = "PROPERTY_CHANGE"; + break; + } + if (event != CONNMAN_MANAGER_EVENT_TECHNOLOGY_REMOVE && + event != CONNMAN_MANAGER_EVENT_SERVICE_REMOVE) { + gchar *p = g_variant_print(properties, TRUE); + props = p; + g_free(p); + } + + qDebug() << "NetworkEventHandler::handle_manager_event: received " << + event_str << ", path = " << path << ", properties = " << props; +#endif + + switch(event) { + case CONNMAN_MANAGER_EVENT_TECHNOLOGY_ADD: + case CONNMAN_MANAGER_EVENT_TECHNOLOGY_REMOVE: + break; + case CONNMAN_MANAGER_EVENT_SERVICE_CHANGE: + { + QVariantMap props_map; + if (populateServiceProperties(properties, props_map)) { + emit serviceAdded(path, props_map); + } + } + break; + case CONNMAN_MANAGER_EVENT_SERVICE_REMOVE: + emit serviceRemoved(QString(path)); + break; + case CONNMAN_MANAGER_EVENT_PROPERTY_CHANGE: + break; + default: + break; + } + +} + +void NetworkEventHandler::handle_technology_event(const gchar *technology, + GVariant *property) +{ + if (!(technology && property)) + return; + +#if LIBQTAPPFW_NETWORK_DEBUG + gchar *p = g_variant_print(property, TRUE); + qDebug() << "NetworkEventHandler::handle_technology_event: technology = " << + technology << ", property = " << p; + g_free(p); +#endif + + // Convert (sv) tuple to a a{sv} dict for parsing + const gchar *key = NULL; + GVariant *var = NULL; + g_variant_get(property, "(sv)", &key, &var); + if (!key) + return; + + // Build QVariantMap for updateStatus + QVariantMap props_map; + if ((g_strcmp0(key, "Connected") == 0 || + g_strcmp0(key, "Powered") == 0) && + g_variant_is_of_type(var, G_VARIANT_TYPE_BOOLEAN)) { + gboolean value; + g_variant_get(var, "b", &value); + props_map.insert(QString(key), QVariant((bool) value)); + + // Update properties + emit adapterStatusChanged(QString(technology), props_map); + } + g_variant_unref(var); +} + +void NetworkEventHandler::handle_service_event(const gchar *service, + GVariant *property) +{ + if (!(service && property)) + return; + +#if LIBQTAPPFW_NETWORK_DEBUG + + gchar *p = g_variant_print(property, TRUE); + qDebug() << "NetworkEventHandler::handle_service_event: service = " << + service << ", property = " << p; + g_free(p); +#endif + // Convert (sv) tuple to a a{sv} dict for updateProperties + const gchar *key = NULL; + GVariant *var = NULL; + g_variant_get(property, "(sv)", &key, &var); + if (!key) + return; + GVariantDict *props_dict = g_variant_dict_new(NULL); + if (!props_dict) { + qWarning() << "g_variant_dict_new failed"; + return; + } + g_variant_dict_insert_value(props_dict, key, var); + GVariant *props_var = g_variant_dict_end(props_dict); + g_variant_dict_unref(props_dict); + g_variant_unref(var); + + QVariantMap props_map; + if (populateServiceProperties(props_var, props_map)) { + // Update adapter properties + emit servicePropertiesChanged(QString(service), props_map); + } + g_variant_unref(props_var); +} + +void NetworkEventHandler::handle_agent_event(const gchar *service, + const int id, + GVariant *properties) +{ + if (!(service && properties)) + return; + +#if LIBQTAPPFW_NETWORK_DEBUG + gchar *props = g_variant_print(properties, TRUE); + qDebug() << "Network::handle_agent_event: properties = " << props; + g_free(props); +#endif + + GVariantDict *props_dict = g_variant_dict_new(properties); + if (!props_dict) + return; + + GVariant *v = NULL; + QVariantMap props_map; + if (g_variant_dict_lookup(props_dict, "Passphrase", "@a{sv}", &v)) { + GVariantDict *passphrase_dict = g_variant_dict_new(v); + gchar *p = NULL; + + if (g_variant_dict_lookup(passphrase_dict, "Type", "&s", &p)) + props_map.insert(QString("Type"), QVariant(QString(p))); + + if (g_variant_dict_lookup(passphrase_dict, "Requirement", "&s", &p)) + props_map.insert(QString("Requirement"), QVariant(QString(p))); + + g_variant_dict_unref(passphrase_dict); + g_variant_unref(v); + } + g_variant_dict_unref(props_dict); + + if (!props_map.isEmpty()) + emit inputRequested(id, props_map); +} diff --git a/network/networkeventhandler.h b/network/networkeventhandler.h new file mode 100644 index 0000000..3ef9619 --- /dev/null +++ b/network/networkeventhandler.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NETWORK_EVENT_HANDLER_H +#define NETWORK_EVENT_HANDLER_H + +#include +#include +#include + +class Network; + +class NetworkEventHandler : public QObject +{ + Q_OBJECT + +public: + explicit NetworkEventHandler(Network *network, bool register_agent, QQmlContext *context, QObject * parent = Q_NULLPTR); + + virtual ~NetworkEventHandler(); + + static void service_connect_cb(const gchar *service, gboolean status, const gchar *error, gpointer user_data) { + if (user_data) + ((NetworkEventHandler*) user_data)->handle_connect_event(service, status, error); + } + + bool populateAdapterProperties(GVariant *in, QVariantMap &out); + bool populateServiceProperties(GVariant *in, QVariantMap &out); + +signals: + void adapterStatusChanged(const QString &technology, const QVariantMap &properties); + void servicePropertiesChanged(const QString &service, const QVariantMap &properties); + bool serviceAdded(const QString &service, const QVariantMap &properties); + bool serviceRemoved(const QString &service); + void inputRequested(int id, const QVariantMap &properties); + void connectResponseReceived(const QString &service, bool status, const QString &error); + +private: + Network *m_network; + bool m_agent; + + // Callback functions for connman-glib hooks + static void manager_event_cb(const gchar *path, connman_manager_event_t event, GVariant *properties, gpointer user_data) { + if (user_data) + ((NetworkEventHandler*) user_data)->handle_manager_event(path, event, properties); + } + + static void technology_event_cb(const gchar *technology, GVariant *properties, gpointer user_data) { + if (user_data) + ((NetworkEventHandler*) user_data)->handle_technology_event(technology, properties); + } + + static void service_event_cb(const gchar *service, GVariant *properties, gpointer user_data) { + if (user_data) + ((NetworkEventHandler*) user_data)->handle_service_event(service, properties); + } + + static void agent_event_cb(const gchar *service, const int id, GVariant *properties, gpointer user_data) { + if (user_data) + ((NetworkEventHandler*) user_data)->handle_agent_event(service, id, properties); + } + + void handle_connect_event(const gchar *service, gboolean status, const gchar *error); + void handle_manager_event(const gchar *path, connman_manager_event_t event, GVariant *properties); + void handle_technology_event(const gchar *technology, GVariant *properties); + void handle_service_event(const gchar *service, GVariant *properties); + void handle_agent_event(const gchar *service, const int id, GVariant *properties); +}; + +#endif // NETWORK_EVENT_HANDLER_H diff --git a/network/wifiadapter.cpp b/network/wifiadapter.cpp index 98f73fa..0670eff 100644 --- a/network/wifiadapter.cpp +++ b/network/wifiadapter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Konsulko Group + * Copyright (C) 2019,2022 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,92 +19,133 @@ #include #include "network.h" -#include "networkadapter.h" +#include "wifiadapter.h" #include "wifinetworkmodel.h" #include "connectionprofile.h" WifiAdapter::WifiAdapter(Network *network, QQmlContext *context, QObject *parent) : - QObject(parent), - AdapterIf(), - m_wifiConnected(false), - m_wifiEnabled(false), - m_wifiStrength(0), - m_model(nullptr), - nw(network) + QObject(parent), + AdapterIf(), + m_wifiConnected(false), + m_wifiEnabled(false), + m_wifiStrength(0), + m_model(nullptr), + nw(network) { - m_model = new WifiNetworkModel(); - QSortFilterProxyModel *model = new QSortFilterProxyModel(); - model->setSourceModel(m_model); - model->setSortRole(WifiNetworkModel::WifiNetworkRoles::SsidRole); - model->setSortCaseSensitivity(Qt::CaseInsensitive); - model->sort(0); - - context->setContextProperty("WifiNetworkModel", m_model); - QObject::connect(m_model, &WifiNetworkModel::strengthChanged, this, &WifiAdapter::updateWifiStrength); - context->setContextProperty("WifiAdapter", this); + m_model = new WifiNetworkModel(); + QSortFilterProxyModel *model = new QSortFilterProxyModel(); + model->setSourceModel(m_model); + model->setSortRole(WifiNetworkModel::WifiNetworkRoles::SsidRole); + model->setSortCaseSensitivity(Qt::CaseInsensitive); + model->sort(0); + + context->setContextProperty("WifiNetworkModel", m_model); + QObject::connect(m_model, &WifiNetworkModel::strengthChanged, this, &WifiAdapter::updateWifiStrength); + context->setContextProperty("WifiAdapter", this); } WifiAdapter::~WifiAdapter() { - delete m_model; + delete m_model; } -void WifiAdapter::updateStatus(QJsonObject properties) +void WifiAdapter::updateStatus(const QVariantMap &properties) { - if (properties.contains("connected")) { - m_wifiConnected = properties.value("connected").toBool(); - emit wifiConnectedChanged(m_wifiConnected); - } - - if (properties.contains("powered")) { - m_wifiEnabled = properties.value("powered").toBool(); - emit wifiEnabledChanged(m_wifiEnabled); - if (m_wifiEnabled) - nw->getServices(); - } + QString key = "Connected"; + if (properties.contains(key)) { + m_wifiConnected = properties.value(key).toBool(); + emit wifiConnectedChanged(m_wifiConnected); + } + + key = "Powered"; + if (properties.contains(key)) { + m_wifiEnabled = properties.value(key).toBool(); + emit wifiEnabledChanged(m_wifiEnabled); + if (m_wifiEnabled) + nw->getServices(); + } } void WifiAdapter::updateWifiStrength(int strength) { - m_wifiStrength = strength; - emit wifiStrengthChanged(m_wifiStrength); + m_wifiStrength = strength; + emit wifiStrengthChanged(m_wifiStrength); } -void WifiAdapter::updateProperties(QString id, QJsonObject properties) +void WifiAdapter::updateProperties(const QString &id, const QVariantMap &properties) { - if (m_model->getNetwork(id)) - m_model->updateProperties(id, properties); + if (m_model->getNetwork(id)) + m_model->updateProperties(id, properties); } -bool WifiAdapter::addService(QString id, QJsonObject properties) +bool WifiAdapter::addService(const QString &id, const QVariantMap &properties) { - QString type = properties.value("type").toString(); - if (type != getType()) - return false; - - QString ssid = properties.value("name").toString(); - // Ignore hidden SSIDs or services already added - if (m_model->getNetwork(id) || (ssid == "")) - return false; - - QString state = properties.value("state").toString(); - int strength = properties.value("strength").toInt(); - // Initially support only IPv4 and the first security method found - QString address = properties.value("ipv4").toObject().value("address").toString(); - QString security = properties.value("security").toArray().at(0).toString(); - - ConnectionProfile *network = new ConnectionProfile(address, security, id, state, ssid, - strength, "", "", "", "", ""); - m_model->addNetwork(network); - - if ((state == "ready") || (state == "online")) - updateWifiStrength(strength); - - return true; + QString type; + QString key = "Type"; + if (properties.contains(key)) { + type = properties.value(key).toString(); + if (type != getType()) + return false; + } + + QString ssid; + key = "Name"; + if (properties.contains(key)) + ssid = properties.value(key).toString(); + + // Ignore hidden SSIDs or services already added + if (m_model->getNetwork(id) || (ssid == "")) + return false; + + QString state; + key = "State"; + if (properties.contains(key)) + state = properties.value(key).toString(); + + int strength = 0; + key = "Strength"; + if (properties.contains(key)) + strength = properties.value(key).toInt(); + + // Initially support only IPv4 and the first security method found + QString address; + key = "IPv4"; + if (properties.contains(key)) { + QVariantMap ip4_map = properties.value(key).toMap(); + + key = "Address"; + if (ip4_map.contains(key)) + address = ip4_map.value(key).toString(); + } + + QString security; + key = "Security"; + if (properties.contains(key)) { + QVariantList security_list = properties.value(key).toList(); + + if (!security_list.isEmpty()) + security = security_list[0].toString(); + } + +#if LIBQTAPPFW_NETWORK_DEBUG + qDebug() << "WifiAdapter::addService: address = " << address + << ", id = " << id + << ", state = " << state + << ", ssid = " << ssid + << ", strength = " << strength + << ", security = " << security; +#endif + ConnectionProfile *network = new ConnectionProfile(address, security, id, state, ssid, + strength, "", "", "", "", ""); + m_model->addNetwork(network); + + if ((state == "ready") || (state == "online")) + updateWifiStrength(strength); + + return true; } -void WifiAdapter::removeService(QString id) +void WifiAdapter::removeService(const QString &id) { - m_model->removeNetwork(m_model->getNetwork(id)); - + m_model->removeNetwork(m_model->getNetwork(id)); } diff --git a/network/wifiadapter.h b/network/wifiadapter.h index ddb44fb..f14a07c 100644 --- a/network/wifiadapter.h +++ b/network/wifiadapter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Konsulko Group + * Copyright (C) 2019,2022 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,23 +19,21 @@ #include #include -#include #include #include "networkadapter.h" class Network; class WifiNetworkModel; - class WifiAdapter : public QObject, public AdapterIf { - Q_OBJECT - Q_INTERFACES(AdapterIf) - Q_PROPERTY(bool wifiConnected READ wifiConnected NOTIFY wifiConnectedChanged) - Q_PROPERTY(bool wifiEnabled READ wifiEnabled NOTIFY wifiEnabledChanged) - Q_PROPERTY(int wifiStrength READ wifiStrength NOTIFY wifiStrengthChanged) + Q_OBJECT + Q_INTERFACES(AdapterIf) + Q_PROPERTY(bool wifiConnected READ wifiConnected NOTIFY wifiConnectedChanged) + Q_PROPERTY(bool wifiEnabled READ wifiEnabled NOTIFY wifiEnabledChanged) + Q_PROPERTY(int wifiStrength READ wifiStrength NOTIFY wifiStrengthChanged) - public: +public: explicit WifiAdapter(Network *network, QQmlContext *context, QObject *parent); virtual ~WifiAdapter(); @@ -43,22 +41,21 @@ class WifiAdapter : public QObject, public AdapterIf bool wifiEnabled() const { return m_wifiEnabled; } int wifiStrength() const { return m_wifiStrength; } - bool addService(QString id, QJsonObject properties) override; - void removeService(QString id) override; - void updateProperties(QString service, QJsonObject properties) override; + bool addService(const QString &id, const QVariantMap &properties) override; + void removeService(const QString &id) override; + void updateProperties(const QString &service, const QVariantMap &properties) override; QString getType() override { return "wifi"; } - void updateStatus(QJsonObject properties) override; + void updateStatus(const QVariantMap &properties) override; - //slots void updateWifiStrength(int); - signals: +signals: void wifiConnectedChanged(bool connected); void wifiEnabledChanged(bool enabled); void wifiStrengthChanged(int strength); - private: +private: bool m_wifiConnected; bool m_wifiEnabled; int m_wifiStrength; diff --git a/network/wifinetworkmodel.cpp b/network/wifinetworkmodel.cpp index 7c32779..6df4116 100644 --- a/network/wifinetworkmodel.cpp +++ b/network/wifinetworkmodel.cpp @@ -10,71 +10,86 @@ WifiNetworkModel::WifiNetworkModel(QObject *parent) QVariant WifiNetworkModel::data(const QModelIndex &index, int role) const { - if (index.row() < 0 || index.row() >= m_networks.count()) - return QVariant(); + if (index.row() < 0 || index.row() >= m_networks.count()) + return QVariant(); - ConnectionProfile *network = m_networks[index.row()]; + ConnectionProfile *network = m_networks[index.row()]; - switch (role) { + switch (role) { case AddressRole: - return network->address(); + return network->address(); case SecurityRole: - return network->security(); + return network->security(); case ServiceRole: - return network->service(); + return network->service(); case SsidRole: - return network->ssid(); + return network->ssid(); case StateRole: - return network->state(); + return network->state(); case StrengthRole: - return network->strength(); - } + return network->strength(); + } - return QVariant(); + return QVariant(); } QHash WifiNetworkModel::roleNames() const { - QHash roles; - roles[AddressRole] = "address"; - roles[SecurityRole] = "security"; - roles[ServiceRole] = "service"; - roles[SsidRole] = "ssid"; - roles[StateRole] = "sstate"; - roles[StrengthRole] = "strength"; + QHash roles; + roles[AddressRole] = "address"; + roles[SecurityRole] = "security"; + roles[ServiceRole] = "service"; + roles[SsidRole] = "ssid"; + roles[StateRole] = "sstate"; + roles[StrengthRole] = "strength"; - return roles; + return roles; } -void WifiNetworkModel::updateProperties(QString service, QJsonObject properties) +void WifiNetworkModel::updateProperties(const QString &service, const QVariantMap &properties) { - ConnectionProfile *network; - QVector vroles; - bool sbcast = false; + ConnectionProfile *network; + QVector vroles; + bool sbcast = false; - if ((network = getNetwork(service))) { - if (properties.contains("ipv4")) { - QString address = properties.value("ipv4").toObject().value("address").toString(); - network->setAddress(address); - vroles.push_back(AddressRole); - } - if (properties.contains("state")) { - network->setState(properties.value("state").toString()); - vroles.push_back(StateRole); - if ((network->state() == "ready") || - (network->state() == "online")) - sbcast = true; - } - if (properties.contains("strength")) { - network->setStrength(properties.value("strength").toInt()); - vroles.push_back(StrengthRole); - if ((network->state() == "ready") || - (network->state() == "online")) - sbcast = true; - } - if (!vroles.isEmpty()) { - emit dataChanged(indexOf(network), indexOf(network), vroles); - if (sbcast) - emit strengthChanged(network->strength()); - } - } + network = getNetwork(service); + if (!network) + return; + + QString key = "IPv4"; + if (properties.contains(key)) { + QVariantMap ip4_map = properties.value(key).toMap(); + + key = "Address"; + if (ip4_map.contains(key)) { + QString address = ip4_map.value(key).toString(); + network->setAddress(address); + vroles.push_back(AddressRole); + } + } + + key = "State"; + if (properties.contains(key)) { + QString state = properties.value(key).toString(); + network->setState(state); + vroles.push_back(StateRole); + if ((network->state() == "ready") || + (network->state() == "online")) + sbcast = true; + } + + key = "Strength"; + if (properties.contains(key)) { + int strength = properties.value(key).toInt(); + network->setStrength(strength); + vroles.push_back(StrengthRole); + if ((network->state() == "ready") || + (network->state() == "online")) + sbcast = true; + } + + if (!vroles.isEmpty()) { + emit dataChanged(indexOf(network), indexOf(network), vroles); + if (sbcast) + emit strengthChanged(network->strength()); + } } diff --git a/network/wifinetworkmodel.h b/network/wifinetworkmodel.h index 94cc7f5..3813503 100644 --- a/network/wifinetworkmodel.h +++ b/network/wifinetworkmodel.h @@ -5,28 +5,28 @@ class WifiNetworkModel : public AbstractNetworkModel { - Q_OBJECT + Q_OBJECT - public: +public: enum WifiNetworkRoles { - AddressRole = Qt::UserRole + 1, - SecurityRole, - ServiceRole, - StateRole, - SsidRole, - StrengthRole + AddressRole = Qt::UserRole + 1, + SecurityRole, + ServiceRole, + StateRole, + SsidRole, + StrengthRole }; WifiNetworkModel(QObject *parent = Q_NULLPTR); QString getType() const override { return "wifi"; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - void updateProperties(QString service, QJsonObject properties) override; + void updateProperties(const QString &service, const QVariantMap &properties) override; - signals: +signals: void strengthChanged(int strength); - protected: +protected: QHash roleNames() const; }; diff --git a/network/wiredadapter.cpp b/network/wiredadapter.cpp index 297ba44..57a6678 100644 --- a/network/wiredadapter.cpp +++ b/network/wiredadapter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Konsulko Group + * Copyright (C) 2019,2022 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,87 +19,138 @@ #include #include "network.h" -#include "networkadapter.h" +#include "wiredadapter.h" #include "wirednetworkmodel.h" #include "connectionprofile.h" WiredAdapter::WiredAdapter(Network *network, QQmlContext *context, QObject *parent) : - QObject(parent), - AdapterIf(), - m_wiredConnected(false), - m_wiredEnabled(false), - m_model(nullptr), - nw(network) + QObject(parent), + AdapterIf(), + m_wiredConnected(false), + m_wiredEnabled(false), + m_model(nullptr), + nw(network) { - m_model = new WiredNetworkModel(); - QSortFilterProxyModel *model = new QSortFilterProxyModel(); - model->setSourceModel(m_model); - model->setSortRole(WiredNetworkModel::WiredNetworkRoles::ServiceRole); - model->setSortCaseSensitivity(Qt::CaseInsensitive); - model->sort(0); - - context->setContextProperty("WiredNetworkModel", m_model); - context->setContextProperty("WiredAdapter", this); + m_model = new WiredNetworkModel(); + QSortFilterProxyModel *model = new QSortFilterProxyModel(); + model->setSourceModel(m_model); + model->setSortRole(WiredNetworkModel::WiredNetworkRoles::ServiceRole); + model->setSortCaseSensitivity(Qt::CaseInsensitive); + model->sort(0); + + context->setContextProperty("WiredNetworkModel", m_model); + context->setContextProperty("WiredAdapter", this); } WiredAdapter::~WiredAdapter() { - delete m_model; + delete m_model; } -void WiredAdapter::updateStatus(QJsonObject properties) +void WiredAdapter::updateStatus(const QVariantMap &properties) { - if (properties.contains("connected")) { - m_wiredConnected = properties.value("connected").toBool(); - emit wiredConnectedChanged(m_wiredConnected); - } - - if (properties.contains("powered")) { - m_wiredEnabled = properties.value("powered").toBool(); - emit wiredEnabledChanged(m_wiredEnabled); - if (m_wiredEnabled) - nw->getServices(); - } + QString key = "Connected"; + if (properties.contains(key)) { + m_wiredConnected = properties.value(key).toBool(); + emit wiredConnectedChanged(m_wiredConnected); + } + + key = "Powered"; + if (properties.contains(key)) { + m_wiredEnabled = properties.value(key).toBool(); + emit wiredEnabledChanged(m_wiredEnabled); + if (m_wiredEnabled) + nw->getServices(); + } } -void WiredAdapter::updateProperties(QString id, QJsonObject properties) +void WiredAdapter::updateProperties(const QString &id, const QVariantMap &properties) { - if (m_model->getNetwork(id)) - m_model->updateProperties(id, properties); + if (m_model->getNetwork(id)) + m_model->updateProperties(id, properties); } -bool WiredAdapter::addService(QString id, QJsonObject properties) +bool WiredAdapter::addService(const QString &id, const QVariantMap &properties) { - QString type = properties.value("type").toString(); - if (type != getType()) - return false; - - // Ignore services already added - if (m_model->getNetwork(id)) - return false; - - QString state = properties.value("state").toString(); - // Initially support only IPv4 and the first security method found - QString security = properties.value("security").toArray().at(0).toString(); - QJsonObject ipv4obj = properties.value("ipv4").toObject(); - QString address = ipv4obj.value("address").toString(); - QString netmask = ipv4obj.value("netmask").toString(); - QString gateway = ipv4obj.value("gateway").toString(); - QString amethod = ipv4obj.value("method").toString(); - QString ns = properties.value("nameservers").toString(); - QString nsmethod = (amethod == "dhcp")? "auto" : "manual"; - - ConnectionProfile *network = new ConnectionProfile(address, security, id, - state, "", 0, netmask, - gateway, amethod, ns, - nsmethod); - m_model->addNetwork(network); - - return true; + QString type; + QString key = "Type"; + if (properties.contains(key)) { + type = properties.value(key).toString(); + if (type != getType()) + return false; + } + + // Ignore services already added + if (m_model->getNetwork(id)) + return false; + + QString state; + key = "State"; + if (properties.contains(key)) + state = properties.value(key).toString(); + + // Initially support only IPv4 and the first security method found + QString address; + QString netmask; + QString gateway; + QString amethod; + key = "IPv4"; + if (properties.contains(key)) { + QVariantMap ip4_map = properties.value(key).toMap(); + + key = "Address"; + if (ip4_map.contains(key)) + address = ip4_map.value(key).toString(); + + key = "Netmask"; + if (ip4_map.contains(key)) + netmask = ip4_map.value(key).toString(); + + key = "Gateway"; + if (ip4_map.contains(key)) + gateway = ip4_map.value(key).toString(); + + key = "Method"; + if (ip4_map.contains(key)) + amethod = ip4_map.value(key).toString(); + } + + QString ns; + key = "Nameservers"; + if (properties.contains(key)) + ns = properties.value(key).toString(); + QString nsmethod = (amethod == "dhcp")? "auto" : "manual"; + + QString security; + key = "Security"; + if (properties.contains(key)) { + QVariantList security_list = properties.value(key).toList(); + + if (!security_list.isEmpty()) + security = security_list[0].toString(); + } + +#if LIBQTAPPFW_NETWORK_DEBUG + qDebug() << "WiredAdapter::addService: address = " << address + << ", id = " << id + << ", state = " << state + << ", netmask = " << netmask + << ", gateway = " << gateway + << ", address method = " << amethod + << ", nameservers = " << ns + << ", nameserver method = " << nsmethod + << ", security = " << security; +#endif + ConnectionProfile *network = new ConnectionProfile(address, security, id, + state, "", 0, netmask, + gateway, amethod, ns, + nsmethod); + m_model->addNetwork(network); + + return true; } -void WiredAdapter::removeService(QString id) +void WiredAdapter::removeService(const QString &id) { - m_model->removeNetwork(m_model->getNetwork(id)); - + m_model->removeNetwork(m_model->getNetwork(id)); } diff --git a/network/wiredadapter.h b/network/wiredadapter.h index 141ccfb..6bd3381 100644 --- a/network/wiredadapter.h +++ b/network/wiredadapter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Konsulko Group + * Copyright (C) 2019,2022 Konsulko Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ #include #include -#include #include #include "networkadapter.h" @@ -28,27 +27,27 @@ class WiredNetworkModel; class WiredAdapter : public QObject, public AdapterIf { - Q_OBJECT - Q_INTERFACES(AdapterIf) - public: + Q_OBJECT + Q_INTERFACES(AdapterIf) + public: explicit WiredAdapter(Network *network, QQmlContext *context, QObject *parent); virtual ~WiredAdapter(); bool wiredConnected() const { return m_wiredConnected; } bool wiredEnabled() const { return m_wiredEnabled; } - bool addService(QString id, QJsonObject properties) override; - void removeService(QString id) override; - void updateProperties(QString service, QJsonObject properties) override; + bool addService(const QString &id, const QVariantMap &properties) override; + void removeService(const QString &id) override; + void updateProperties(const QString &service, const QVariantMap &properties) override; QString getType() override { return "ethernet"; } - void updateStatus(QJsonObject properties) override; + void updateStatus(const QVariantMap &properties) override; - signals: +signals: void wiredConnectedChanged(bool connected); void wiredEnabledChanged(bool enabled); - private: +private: bool m_wiredConnected; bool m_wiredEnabled; WiredNetworkModel *m_model; diff --git a/network/wirednetworkmodel.cpp b/network/wirednetworkmodel.cpp index 0d1209e..6fc8151 100644 --- a/network/wirednetworkmodel.cpp +++ b/network/wirednetworkmodel.cpp @@ -10,108 +10,137 @@ WiredNetworkModel::WiredNetworkModel(QObject *parent) QVariantList WiredNetworkModel::readCurrentRouteConfig(const QModelIndex &index) const { - QVariantList ret; + QVariantList ret; - if (!index.isValid()) - return ret; + if (!index.isValid()) + return ret; - if (index.row() < 0 || index.row() >= this->m_networks.count()) - return ret; + if (index.row() < 0 || index.row() >= this->m_networks.count()) + return ret; - const ConnectionProfile *network = this->m_networks[index.row()]; - ret.append(network->addrmethod()); - ret.append(network->address()); - ret.append(network->netmask()); - ret.append(network->gateway()); - return ret; + const ConnectionProfile *network = this->m_networks[index.row()]; + ret.append(network->addrmethod()); + ret.append(network->address()); + ret.append(network->netmask()); + ret.append(network->gateway()); + return ret; } QVariantList WiredNetworkModel::readCurrentNameServerConfig(const QModelIndex &index) const { - QVariantList ret; + QVariantList ret; - if (!index.isValid()) - return ret; + if (!index.isValid()) + return ret; - if (index.row() < 0 || index.row() >= this->m_networks.count()) - return ret; + if (index.row() < 0 || index.row() >= this->m_networks.count()) + return ret; - const ConnectionProfile *network = this->m_networks[index.row()]; - ret.append(network->nsmethod()); - ret.append(network->nameservers()); - return ret; + const ConnectionProfile *network = this->m_networks[index.row()]; + ret.append(network->nsmethod()); + ret.append(network->nameservers()); + return ret; } QVariant WiredNetworkModel::data(const QModelIndex &index, int role) const { - QVariant ret; + QVariant ret; - if (!index.isValid()) - return ret; + if (!index.isValid()) + return ret; - if (index.row() < 0 || index.row() >= m_networks.count()) - return ret; + if (index.row() < 0 || index.row() >= m_networks.count()) + return ret; - const ConnectionProfile *network = m_networks[index.row()]; + const ConnectionProfile *network = m_networks[index.row()]; - switch (role) { + switch (role) { case AddressRole: - return network->address(); + return network->address(); case SecurityRole: - return network->security(); + return network->security(); case ServiceRole: - return network->service(); + return network->service(); case StateRole: - return network->state(); + return network->state(); case RouteRole: - return readCurrentRouteConfig(index); + return readCurrentRouteConfig(index); case NameServerRole: - return readCurrentNameServerConfig(index); - } + return readCurrentNameServerConfig(index); + } - return ret; + return ret; } QHash WiredNetworkModel::roleNames() const { - QHash roles; - roles[AddressRole] = "address"; - roles[SecurityRole] = "security"; - roles[ServiceRole] = "service"; - roles[StateRole] = "sstate"; - roles[RouteRole] = "sroute"; - roles[NameServerRole] = "nservers"; - - return roles; + QHash roles; + roles[AddressRole] = "address"; + roles[SecurityRole] = "security"; + roles[ServiceRole] = "service"; + roles[StateRole] = "sstate"; + roles[RouteRole] = "sroute"; + roles[NameServerRole] = "nservers"; + + return roles; } -void WiredNetworkModel::updateProperties(QString service, QJsonObject properties) +void WiredNetworkModel::updateProperties(const QString &service, const QVariantMap &properties) { - ConnectionProfile *network; - QVector vroles; - - if ((network = getNetwork(service))) { - if (properties.contains("ipv4")) { - QJsonObject ipv4obj = properties.value("ipv4").toObject(); - network->setAddress(ipv4obj.value("address").toString()); - network->setNetmask(ipv4obj.value("netmask").toString()); - network->setGateway(ipv4obj.value("gateway").toString()); - network->setAddrMethod(ipv4obj.value("method").toString()); - vroles.push_back(AddressRole); - vroles.push_back(RouteRole); - } - if (properties.contains("nameservers")) { - QString nservers = properties.value("nameservers").toString(); - network->setNameservers(nservers); - (network->addrmethod() == "dhcp")? network->setNSMethod("auto") : - network->setNSMethod("manual"); - vroles.push_back(NameServerRole); - } - if (properties.contains("state")) { - network->setState(properties.value("state").toString()); - vroles.push_back(StateRole); - } - if (!vroles.isEmpty()) - emit dataChanged(indexOf(network), indexOf(network), vroles); - - } + ConnectionProfile *network; + QVector vroles; + + network = getNetwork(service); + if (!network) + return; + + QString key = "IPv4"; + if (properties.contains(key)) { + QVariantMap ip4_map = properties.value(key).toMap(); + + QString address; + key = "Address"; + if (ip4_map.contains(key)) + address = ip4_map.value(key).toString(); + + QString netmask; + key = "Netmask"; + if (ip4_map.contains(key)) + netmask = ip4_map.value(key).toString(); + + QString gateway; + key = "Gateway"; + if (ip4_map.contains(key)) + gateway = ip4_map.value(key).toString(); + + QString method; + key = "Method"; + if (ip4_map.contains(key)) + method = ip4_map.value(key).toString(); + + network->setAddress(address); + network->setNetmask(netmask); + network->setGateway(gateway); + network->setAddrMethod(method); + vroles.push_back(AddressRole); + vroles.push_back(RouteRole); + } + + key = "Nameservers"; + if (properties.contains(key)) { + QString ns = properties.value(key).toString(); + network->setNameservers(ns); + (network->addrmethod() == "dhcp") ? network->setNSMethod("auto") : + network->setNSMethod("manual"); + vroles.push_back(NameServerRole); + } + + key = "State"; + if (properties.contains(key)) { + QString state = properties.value(key).toString(); + network->setState(state); + vroles.push_back(StateRole); + } + + if (!vroles.isEmpty()) + emit dataChanged(indexOf(network), indexOf(network), vroles); } diff --git a/network/wirednetworkmodel.h b/network/wirednetworkmodel.h index c8ea92d..352d9b3 100644 --- a/network/wirednetworkmodel.h +++ b/network/wirednetworkmodel.h @@ -5,16 +5,16 @@ class WiredNetworkModel : public AbstractNetworkModel { - Q_OBJECT + Q_OBJECT - public: +public: enum WiredNetworkRoles { - AddressRole = Qt::UserRole + 1, - SecurityRole, - ServiceRole, - StateRole, - RouteRole, - NameServerRole, + AddressRole = Qt::UserRole + 1, + SecurityRole, + ServiceRole, + StateRole, + RouteRole, + NameServerRole, }; WiredNetworkModel(QObject *parent = Q_NULLPTR); @@ -23,9 +23,9 @@ class WiredNetworkModel : public AbstractNetworkModel Q_INVOKABLE QVariantList readCurrentNameServerConfig(const QModelIndex &index) const; QString getType() const override { return "wired"; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - void updateProperties(QString service, QJsonObject properties) override; + void updateProperties(const QString &service, const QVariantMap &properties) override; - protected: +protected: QHash roleNames() const; }; -- cgit 1.2.3-korg