Skip to content

Commit

Permalink
[libconnman-qt] Add API for accessing connman VPNs. Contributes to JB…
Browse files Browse the repository at this point in the history
…#45378

Connman provides the vpn-manager and vpn-connection dbus interfaces for
managing VPN configurations. These changes provide a Qt API wrapper for
these interfaces, along with a model exending QAbstractListModel of the
available VPN configurations.

Much of the API is modeled on the VpnModel that can be found in
nemo-qml-plugin-systemsettings, stripped back to remove
Settings-specific functionality.
  • Loading branch information
llewelld committed Oct 9, 2019
1 parent 7a0002f commit 2adfe8a
Show file tree
Hide file tree
Showing 17 changed files with 1,937 additions and 8 deletions.
18 changes: 18 additions & 0 deletions libconnman-qt/connman_service.xml
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="net.connman.Service">
<method name="GetProperties">
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg name="properties" type="a{sv}" direction="out"/>
</method>
<method name="SetProperty">
<arg name="name" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
</method>
<signal name="PropertyChanged">
<arg name="name" type="s"/>
<arg name="value" type="v"/>
</signal>
</interface>
</node>
26 changes: 26 additions & 0 deletions libconnman-qt/connman_vpn_connection.xml
@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="net.connman.vpn.Connection">
<method name="GetProperties">
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg name="properties" type="a{sv}" direction="out"/>
</method>
<method name="SetProperty">
<arg name="name" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
</method>
<method name="ClearProperty">
<arg name="name" type="s" direction="in"/>
</method>
<method name="Connect"/>
<method name="Connect2">
<arg name="dbus_sender" type="s" direction="in"/>
</method>
<method name="Disconnect"/>
<signal name="PropertyChanged">
<arg name="name" type="s"/>
<arg name="value" type="v"/>
</signal>
</interface>
</node>
32 changes: 32 additions & 0 deletions libconnman-qt/connman_vpn_manager.xml
@@ -0,0 +1,32 @@
<?xml version="1.0"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="net.connman.vpn.Manager">
<method name="Create">
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
<arg name="properties" type="a{sv}" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="Remove">
<arg name="identifier" type="o" direction="in"/>
</method>
<method name="GetConnections">
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="PathPropertiesArray"/>
<arg name="connections" type="a(oa{sv})" direction="out"/>
</method>
<method name="RegisterAgent">
<arg name="path" type="o" direction="in"/>
</method>
<method name="UnregisterAgent">
<arg name="path" type="o" direction="in"/>
</method>
<signal name="ConnectionAdded">
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
<arg name="identifier" type="o"/>
<arg name="properties" type="a{sv}"/>
</signal>
<signal name="ConnectionRemoved">
<arg name="identifier" type="o"/>
</signal>
</interface>
</node>
32 changes: 25 additions & 7 deletions libconnman-qt/libconnman-qt.pro
Expand Up @@ -38,10 +38,17 @@ CONFIG(debug, debug|release) {
TARGET = $$qtLibraryTarget(connman-$$TARGET_SUFFIX)
headers.path = $$INSTALL_ROOT$$PREFIX/include/connman-$$TARGET_SUFFIX

custom_dbus_interface.files = \
connman_service.xml \
connman_vpn_manager.xml \
connman_vpn_connection.xml
custom_dbus_interface.header_flags = -i qdbusxml2cpp_dbus_types.h

DBUS_INTERFACES = \
connman_clock.xml \
connman_session.xml \
connman_technology.xml \
custom_dbus_interface

PUBLIC_HEADERS += \
networkmanager.h \
Expand All @@ -53,13 +60,24 @@ PUBLIC_HEADERS += \
useragent.h \
sessionagent.h \
networksession.h \
counter.h
counter.h \
vpnconnection.h \
vpnconnection_p.h \
vpnmanager.h \
vpnmanager_p.h \
vpncoremodel.h \
vpncoremodel_p.h

HEADERS += \
$$PUBLIC_HEADERS \
libconnman_p.h \
marshalutils.h \
qdbusxml2cpp_dbus_types.h \
connman_vpn_manager_interface.h \
connman_vpn_connection_interface.h

SOURCES += \
marshalutils.cpp \
networkmanager.cpp \
networktechnology.cpp \
networkservice.cpp \
Expand All @@ -69,7 +87,10 @@ SOURCES += \
useragent.cpp \
sessionagent.cpp \
networksession.cpp \
counter.cpp
counter.cpp \
vpnconnection.cpp \
vpnmanager.cpp \
vpncoremodel.cpp

target.path = $$INSTALL_ROOT$$PREFIX/lib

Expand All @@ -81,8 +102,5 @@ QMAKE_PKGCONFIG_INCDIR = $$headers.path

INSTALLS += target headers

OTHER_FILES = connman_service.xml \
connman_technology.xml \
connman_clock.xml \
connman_session.xml \
connman_notification.xml
OTHER_FILES = connman_notification.xml \
DBUS_INTERFACES
175 changes: 175 additions & 0 deletions libconnman-qt/marshalutils.cpp
@@ -0,0 +1,175 @@
/*
* Copyright (c) 2016 - 2019 Jolla Ltd.
* Copyright (c) 2019 Open Mobile Platform LLC.
*
* You may use this file under the terms of the BSD license as follows:
*
* "Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nemo Mobile nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
*/

#include <QDebug>
#include "vpnconnection.h"

#include "marshalutils.h"

template<typename T>
inline QVariant extract(const QDBusArgument &arg)
{
T rv;
arg >> rv;
return QVariant::fromValue(rv);
}

template<typename T>
inline QVariant extractArray(const QDBusArgument &arg)
{
QVariantList rv;

arg.beginArray();
while (!arg.atEnd()) {
rv.append(extract<T>(arg));
}
arg.endArray();

return QVariant::fromValue(rv);
}

QVariantMap MarshalUtils::propertiesToQml(const QVariantMap &fromDBus)
{
QVariantMap rv;

QVariantMap providerProperties;

for (QVariantMap::const_iterator it = fromDBus.cbegin(), end = fromDBus.cend(); it != end; ++it) {
QString key(it.key());
QVariant value(it.value());

if (key.indexOf(QChar('.')) != -1) {
providerProperties.insert(key, value);
continue;
}

// QML properties must be lowercased
QChar &initial(*key.begin());
initial = initial.toLower();

// Some properties must be extracted manually
if (key == QStringLiteral("iPv4") ||
key == QStringLiteral("iPv6")) {
// 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));
}

if (!providerProperties.isEmpty()) {
rv.insert(QStringLiteral("providerProperties"), QVariant::fromValue(providerProperties));
}

return rv;
}

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

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);

return rv;
}

QVariant MarshalUtils::convertValue(const QString &key, const QVariant &value, bool toDBus)
{
static const QHash<QString, QList<QPair<QVariant, QVariant> > > 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 value;
}

QVariant MarshalUtils::convertToQml(const QString &key, const QVariant &value)
{
return convertValue(key, value, false);
}

QVariant MarshalUtils::convertToDBus(const QString &key, const QVariant &value)
{
return convertValue(key, value, true);
}

QVariantMap MarshalUtils::propertiesToDBus(const QVariantMap &fromQml)
{
QVariantMap rv;

for (QVariantMap::const_iterator it = fromQml.cbegin(), end = fromQml.cend(); it != end; ++it) {
QString key(it.key());
QVariant value(it.value());

if (key == QStringLiteral("providerProperties")) {
const QVariantMap providerProperties(value.value<QVariantMap>());
for (QVariantMap::const_iterator pit = providerProperties.cbegin(), pend = providerProperties.cend(); pit != pend; ++pit) {
rv.insert(pit.key(), pit.value());
}
continue;
}

// The DBus properties are capitalized
QChar &initial(*key.begin());
initial = initial.toUpper();

if (key == QStringLiteral("Ipv4") ||
key == QStringLiteral("Ipv6")) {
// Ipv4 becomes IPv4 and Ipv6 becomes IPv6
key[1] = 'P';
}

rv.insert(key, convertToDBus(key, value));
}

return rv;
}

62 changes: 62 additions & 0 deletions libconnman-qt/marshalutils.h
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2016 - 2019 Jolla Ltd.
* Copyright (c) 2019 Open Mobile Platform LLC.
*
* You may use this file under the terms of the BSD license as follows:
*
* "Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nemo Mobile nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
*/

#ifndef MARSHALUTILS_H
#define MARSHALUTILS_H

#include <QVariant>
#include <QDBusArgument>

namespace MarshalUtils
{
template <typename Argument>
inline Argument demarshallArgument(const QVariant &argument)
{
if (argument.userType() == qMetaTypeId<QDBusArgument>()) {
Argument demarshalled;
argument.value<QDBusArgument>() >> demarshalled;
return demarshalled;
} else {
return argument.value<Argument>();
}

}

QVariantMap propertiesToQml(const QVariantMap &fromDBus);
QHash<QString, QList<QPair<QVariant, QVariant> > > 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);
QVariantMap propertiesToDBus(const QVariantMap &fromQml);
}

#endif // MARSHALUTILS_H

0 comments on commit 2adfe8a

Please sign in to comment.