Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[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.
  • Loading branch information
llewelld committed Jan 10, 2020
1 parent d2e425b commit 368f984
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 30 deletions.
119 changes: 99 additions & 20 deletions libconnman-qt/marshalutils.cpp
Expand Up @@ -31,10 +31,99 @@
*/

#include <QDebug>
#include <QDBusMetaType>
#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<QPair<QVariant, QVariant> > states;
states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("idle")), QVariant::fromValue(static_cast<int>(VpnConnection::Idle))));
states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("failure")), QVariant::fromValue(static_cast<int>(VpnConnection::Failure))));
states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("configuration")), QVariant::fromValue(static_cast<int>(VpnConnection::Configuration))));
states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("ready")), QVariant::fromValue(static_cast<int>(VpnConnection::Ready))));
states.push_back(qMakePair(QVariant::fromValue(QStringLiteral("disconnect")), QVariant::fromValue(static_cast<int>(VpnConnection::Disconnect))));

auto lit = std::find_if(states.cbegin(), states.cend(), [value, toDBus](const QPair<QVariant, QVariant> &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<RouteStruture> and QDBusArgument, but we still need to
// convert to/from suitable Javascript structures
QVariant variant;
if (toDBus) {
QVariantList in = value.toList();
QList<RouteStructure> 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<RouteStructure> in = qdbus_cast<QList<RouteStructure>>(value.value<QDBusArgument>());
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<typename T>
inline QVariant extract(const QDBusArgument &arg)
{
Expand Down Expand Up @@ -82,9 +171,6 @@ QVariantMap MarshalUtils::propertiesToQml(const QVariantMap &fromDBus)
// iPv4 becomes ipv4 and iPv6 becomes ipv6
key = key.toLower();
value = extract<QVariantMap>(value.value<QDBusArgument>());
} else if (key == QStringLiteral("serverRoutes") ||
key == QStringLiteral("userRoutes")) {
value = extractArray<QVariantMap>(value.value<QDBusArgument>());
}

rv.insert(key, convertToQml(key, value));
Expand All @@ -98,34 +184,27 @@ QVariantMap MarshalUtils::propertiesToQml(const QVariantMap &fromDBus)
}

// Conversion to/from DBus/QML
QHash<QString, QList<QPair<QVariant, QVariant> > > MarshalUtils::propertyConversions()
QHash<QString, MarshalUtils::conversionFunction> MarshalUtils::propertyConversions()
{
QHash<QString, QList<QPair<QVariant, QVariant> > > rv;
qDBusRegisterMetaType<RouteStructure>();
qDBusRegisterMetaType<QList<RouteStructure>>();

QList<QPair<QVariant, QVariant> > states;
states.push_back(qMakePair(QVariant::fromValue(QString("idle")), QVariant::fromValue(static_cast<int>(VpnConnection::Idle))));
states.push_back(qMakePair(QVariant::fromValue(QString("failure")), QVariant::fromValue(static_cast<int>(VpnConnection::Failure))));
states.push_back(qMakePair(QVariant::fromValue(QString("configuration")), QVariant::fromValue(static_cast<int>(VpnConnection::Configuration))));
states.push_back(qMakePair(QVariant::fromValue(QString("ready")), QVariant::fromValue(static_cast<int>(VpnConnection::Ready))));
states.push_back(qMakePair(QVariant::fromValue(QString("disconnect")), QVariant::fromValue(static_cast<int>(VpnConnection::Disconnect))));
rv.insert(QString("state"), states);
QHash<QString, conversionFunction> 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<QString, QList<QPair<QVariant, QVariant> > > conversions(propertyConversions());
static const QHash<QString, conversionFunction> conversions(propertyConversions());

auto it = conversions.find(key.toLower());
if (it != conversions.end()) {
const QList<QPair<QVariant, QVariant> > &list(it.value());
auto lit = std::find_if(list.cbegin(), list.cend(), [value, toDBus](const QPair<QVariant, QVariant> &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;
Expand Down
4 changes: 3 additions & 1 deletion libconnman-qt/marshalutils.h
Expand Up @@ -51,8 +51,10 @@ namespace MarshalUtils

}

typedef QVariant (*conversionFunction)(const QString &key, const QVariant &value, bool toDBus);

QVariantMap propertiesToQml(const QVariantMap &fromDBus);
QHash<QString, QList<QPair<QVariant, QVariant> > > propertyConversions();
QHash<QString, conversionFunction> 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);
Expand Down
6 changes: 3 additions & 3 deletions libconnman-qt/vpnconnection.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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)

// ==========================================================================
Expand Down
23 changes: 17 additions & 6 deletions libconnman-qt/vpnconnection.h
Expand Up @@ -38,6 +38,17 @@

class VpnConnectionPrivate;

// The userRoutes and serverRoutes properties are QVariants containing a
// QList<RouteStructure> structure
struct RouteStructure
{
int protocolFamily;
QString network;
QString netmask;
QString gateway;
};
Q_DECLARE_METATYPE(RouteStructure)

class VpnConnection : public QObject
{
Q_OBJECT
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 368f984

Please sign in to comment.