From 368f98405adde356f4235f07e9bb811ed869db03 Mon Sep 17 00:00:00 2001 From: David Llewellyn-Jones Date: Fri, 6 Dec 2019 15:56:20 +0000 Subject: [PATCH] [libconnman-qt] Convert VPN routes to/from dbus. Contributes to JB#46120 The userRoutes and serverRoutes VPN properties are passed to connman via dbus in the following form. Variant array [struct {array [ dict entry( string "ProtocolFamily" variant int32 4 ) dict entry( string "Network" variant string "172.18.13.1" ) dict entry( string "Netmask" variant string "255.255.255.255" ) dict entry( string "Gateway" variant string "172.18.13.5" ) ]}] These need to be converted to and from the appropriate datatypes used in QML and javascript. This change adds the conversion functions needed for this. --- libconnman-qt/marshalutils.cpp | 119 ++++++++++++++++++++++++++------ libconnman-qt/marshalutils.h | 4 +- libconnman-qt/vpnconnection.cpp | 6 +- libconnman-qt/vpnconnection.h | 23 ++++-- 4 files changed, 122 insertions(+), 30 deletions(-) diff --git a/libconnman-qt/marshalutils.cpp b/libconnman-qt/marshalutils.cpp index 5236966..79ba4bd 100644 --- a/libconnman-qt/marshalutils.cpp +++ b/libconnman-qt/marshalutils.cpp @@ -31,10 +31,99 @@ */ #include +#include #include "vpnconnection.h" #include "marshalutils.h" +// Empty namespace for local static functions +namespace { + +// Marshall the RouteStructure data into a D-Bus argument +QDBusArgument &operator<<(QDBusArgument &argument, const RouteStructure &routestruct) +{ + QVariantMap dict; + dict.insert("ProtocolFamily", routestruct.protocolFamily); + dict.insert("Network", routestruct.network); + dict.insert("Netmask", routestruct.netmask); + dict.insert("Gateway", routestruct.gateway); + + argument.beginStructure(); + argument << dict; + argument.endStructure(); + return argument; +} + +// Retrieve the RouteStructure data from the D-Bus argument +const QDBusArgument &operator>>(const QDBusArgument &argument, RouteStructure &routestruct) +{ + QVariantMap dict; + argument.beginStructure(); + argument >> dict; + argument.endStructure(); + + routestruct.protocolFamily = dict.value("ProtocolFamily", 0).toInt(); + routestruct.network = dict.value("Network").toString(); + routestruct.netmask = dict.value("Netmask").toString(); + routestruct.gateway = dict.value("Gateway").toString(); + + return argument; +} + +QVariant convertState (const QString &key, const QVariant &value, bool toDBus) +{ + QList > states; + states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("idle")), QVariant::fromValue(static_cast(VpnConnection::Idle)))); + states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("failure")), QVariant::fromValue(static_cast(VpnConnection::Failure)))); + states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("configuration")), QVariant::fromValue(static_cast(VpnConnection::Configuration)))); + states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("ready")), QVariant::fromValue(static_cast(VpnConnection::Ready)))); + states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("disconnect")), QVariant::fromValue(static_cast(VpnConnection::Disconnect)))); + + auto lit = std::find_if(states.cbegin(), states.cend(), [value, toDBus](const QPair &pair) { return value == (toDBus ? pair.second : pair.first); }); + if (lit != states.end()) { + return toDBus ? (*lit).first : (*lit).second; + } + qDebug() << "No conversion found for" << (toDBus ? "QML" : "DBus") << "value:" << value << key; + return value; +} + +QVariant convertRoutes (const QString &, const QVariant &value, bool toDBus) { + // We use qDBusRegisterMetaType in VpnConnections to convert automatically + // between QList and QDBusArgument, but we still need to + // convert to/from suitable Javascript structures + QVariant variant; + if (toDBus) { + QVariantList in = value.toList(); + QList out; + for (QVariant item : in) { + QVariantMap jsRoute = item.toMap(); + RouteStructure route; + route.protocolFamily = jsRoute.value("ProtocolFamily", 0).toInt(); + route.network = jsRoute.value("Network").toString(); + route.netmask = jsRoute.value("Netmask").toString(); + route.gateway = jsRoute.value("Gateway").toString(); + out << route; + } + variant.setValue(out); + } + else { + QList in = qdbus_cast>(value.value()); + QVariantList out; + for (RouteStructure route : in) { + QVariantMap jsRoute; + jsRoute.insert("ProtocolFamily", route.protocolFamily); + jsRoute.insert("Network", route.network); + jsRoute.insert("Netmask", route.netmask); + jsRoute.insert("Gateway", route.gateway); + out << jsRoute; + } + variant.setValue(out); + } + return variant; +} + +} // Empty namespace + template inline QVariant extract(const QDBusArgument &arg) { @@ -82,9 +171,6 @@ QVariantMap MarshalUtils::propertiesToQml(const QVariantMap &fromDBus) // iPv4 becomes ipv4 and iPv6 becomes ipv6 key = key.toLower(); value = extract(value.value()); - } else if (key == QStringLiteral("serverRoutes") || - key == QStringLiteral("userRoutes")) { - value = extractArray(value.value()); } rv.insert(key, convertToQml(key, value)); @@ -98,34 +184,27 @@ QVariantMap MarshalUtils::propertiesToQml(const QVariantMap &fromDBus) } // Conversion to/from DBus/QML -QHash > > MarshalUtils::propertyConversions() +QHash MarshalUtils::propertyConversions() { - QHash > > rv; + qDBusRegisterMetaType(); + qDBusRegisterMetaType>(); - QList > states; - states.push_back(qMakePair(QVariant::fromValue(QString("idle")), QVariant::fromValue(static_cast(VpnConnection::Idle)))); - states.push_back(qMakePair(QVariant::fromValue(QString("failure")), QVariant::fromValue(static_cast(VpnConnection::Failure)))); - states.push_back(qMakePair(QVariant::fromValue(QString("configuration")), QVariant::fromValue(static_cast(VpnConnection::Configuration)))); - states.push_back(qMakePair(QVariant::fromValue(QString("ready")), QVariant::fromValue(static_cast(VpnConnection::Ready)))); - states.push_back(qMakePair(QVariant::fromValue(QString("disconnect")), QVariant::fromValue(static_cast(VpnConnection::Disconnect)))); - rv.insert(QString("state"), states); + QHash rv; + + rv.insert(QStringLiteral("state"), convertState); + rv.insert(QStringLiteral("userroutes"), convertRoutes); + rv.insert(QStringLiteral("serverroutes"), convertRoutes); return rv; } QVariant MarshalUtils::convertValue(const QString &key, const QVariant &value, bool toDBus) { - static const QHash > > conversions(propertyConversions()); + static const QHash conversions(propertyConversions()); auto it = conversions.find(key.toLower()); if (it != conversions.end()) { - const QList > &list(it.value()); - auto lit = std::find_if(list.cbegin(), list.cend(), [value, toDBus](const QPair &pair) { return value == (toDBus ? pair.second : pair.first); }); - if (lit != list.end()) { - return toDBus ? (*lit).first : (*lit).second; - } else { - qDebug() << "No conversion found for" << (toDBus ? "QML" : "DBus") << "value:" << value << key; - } + return it.value()(key, value, toDBus); } return value; diff --git a/libconnman-qt/marshalutils.h b/libconnman-qt/marshalutils.h index da00b0c..b4c86e3 100644 --- a/libconnman-qt/marshalutils.h +++ b/libconnman-qt/marshalutils.h @@ -51,8 +51,10 @@ namespace MarshalUtils } + typedef QVariant (*conversionFunction)(const QString &key, const QVariant &value, bool toDBus); + QVariantMap propertiesToQml(const QVariantMap &fromDBus); - QHash > > propertyConversions(); + QHash propertyConversions(); QVariant convertValue(const QString &key, const QVariant &value, bool toDBus); QVariant convertToQml(const QString &key, const QVariant &value); QVariant convertToDBus(const QString &key, const QVariant &value); diff --git a/libconnman-qt/vpnconnection.cpp b/libconnman-qt/vpnconnection.cpp index 72ec1b0..7d0caf2 100644 --- a/libconnman-qt/vpnconnection.cpp +++ b/libconnman-qt/vpnconnection.cpp @@ -233,7 +233,7 @@ void VpnConnection::update(const QVariantMap &updateProperties) d->checkChanged(properties, emissions, "ipv4", &VpnConnection::ipv4Changed); d->checkChanged(properties, emissions, "ipv6", &VpnConnection::ipv6Changed); d->checkChanged(properties, emissions, "nameservers", &VpnConnection::nameserversChanged); - d->checkChanged(properties, emissions, "usreRoutes", &VpnConnection::userRoutesChanged); + d->checkChanged(properties, emissions, "userRoutes", &VpnConnection::userRoutesChanged); d->checkChanged(properties, emissions, "serverRoutes", &VpnConnection::serverRoutesChanged); d->updateVariable(properties, emissions, "autoConnect", &d->m_autoConnect, &VpnConnection::autoConnectChanged); @@ -332,8 +332,8 @@ DEFAULT_PROPERTY_METHODS(int, int, Index, index) DEFAULT_PROPERTY_METHODS(QVariantMap &, QVariantMap, Ipv4, ipv4) DEFAULT_PROPERTY_METHODS(QVariantMap &, QVariantMap, Ipv6, ipv6) DEFAULT_PROPERTY_METHODS(QStringList &, QStringList, Nameservers, nameservers) -DEFAULT_PROPERTY_METHODS(QVariantList &, QVariantList, UserRoutes, userRoutes) -DEFAULT_PROPERTY_METHODS(QVariantList &, QVariantList, ServerRoutes, serverRoutes) +DEFAULT_PROPERTY_METHODS(QVariant &, QVariant, UserRoutes, userRoutes) +DEFAULT_PROPERTY_METHODS(QVariant &, QVariant, ServerRoutes, serverRoutes) DEFAULT_PROPERTY_METHODS(QVariantMap &, QVariantMap, ProviderProperties, providerProperties) // ========================================================================== diff --git a/libconnman-qt/vpnconnection.h b/libconnman-qt/vpnconnection.h index 5c72f56..4297c04 100644 --- a/libconnman-qt/vpnconnection.h +++ b/libconnman-qt/vpnconnection.h @@ -38,6 +38,17 @@ class VpnConnectionPrivate; +// The userRoutes and serverRoutes properties are QVariants containing a +// QList structure +struct RouteStructure +{ + int protocolFamily; + QString network; + QString netmask; + QString gateway; +}; +Q_DECLARE_METATYPE(RouteStructure) + class VpnConnection : public QObject { Q_OBJECT @@ -58,8 +69,8 @@ class VpnConnection : public QObject Q_PROPERTY(QVariantMap ipv4 READ ipv4 WRITE setIpv4 NOTIFY ipv4Changed) Q_PROPERTY(QVariantMap ipv6 READ ipv6 WRITE setIpv6 NOTIFY ipv6Changed) Q_PROPERTY(QStringList nameservers READ nameservers WRITE setNameservers NOTIFY nameserversChanged) - Q_PROPERTY(QVariantList userRoutes READ userRoutes WRITE setUserRoutes NOTIFY userRoutesChanged) - Q_PROPERTY(QVariantList serverRoutes READ serverRoutes WRITE setServerRoutes NOTIFY serverRoutesChanged) + Q_PROPERTY(QVariant userRoutes READ userRoutes WRITE setUserRoutes NOTIFY userRoutesChanged) + Q_PROPERTY(QVariant serverRoutes READ serverRoutes WRITE setServerRoutes NOTIFY serverRoutesChanged) Q_PROPERTY(QVariantMap properties READ properties WRITE setProperties NOTIFY propertiesChanged) Q_PROPERTY(QVariantMap providerProperties READ providerProperties WRITE setProviderProperties NOTIFY providerPropertiesChanged) @@ -123,11 +134,11 @@ class VpnConnection : public QObject QStringList nameservers() const; void setNameservers(const QStringList &nameservers); - QVariantList userRoutes() const; - void setUserRoutes(const QVariantList &userRoutes); + QVariant userRoutes() const; + void setUserRoutes(const QVariant &userRoutes); - QVariantList serverRoutes() const; - void setServerRoutes(const QVariantList &serverRoutes); + QVariant serverRoutes() const; + void setServerRoutes(const QVariant &serverRoutes); QVariantMap properties() const; void setProperties(const QVariantMap properties);