Error getting DBus interface property using QDBusInterface

I am trying to get network information (IP address, netmask, route, etc.) for all my interfaces in Qt using the NetworkManager DBus interface. The problem is that when I try to access the "Addresses" property of org.freedesktop.NetworkManager.IP4Config, I get the following error:

QDBusAbstractInterface: type QDBusRawType<0x616175>* must be registered with QtDBus before it can be used to read property org.freedesktop.NetworkManager.IP4Config.Addresses Addresses are invalid Error 2 = "Unregistered type QDBusRawType<0x616175>* cannot be handled" 

However, I can get the value of this property using dbus-send with the following command.

 dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \ /org/freedesktop/NetworkManager/IP4Config/0 \ org.freedesktop.DBus.Properties.Get \ string:"org.freedesktop.NetworkManager.IP4Config" \ string:"Addresses" 

I can also get good values ​​for the interface property mentioned above via qtdbusviewer. The following is a snippet of code.

 QDBusInterface interface(NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_IFACE, QDBusConnection::systemBus()); // Get a list of all devices QDBusReply<QList<QDBusObjectPath> > result = interface.call("GetDevices"); foreach (const QDBusObjectPath& connection, result.value()) { QDBusInterface device(NM_DBUS_SERVICE, connection.path(), "org.freedesktop.NetworkManager.Device", QDBusConnection::systemBus()); if ( device.property("DeviceType").toInt() == NM_DEVICE_TYPE_ETHERNET ) { // Get the IPv4 information if the device is active if ( device.property("State").toInt() == NETWORK_DEVICE_CONNECTED ) { QVariant ipv4config = device.property("Ip4Config"); if ( ipv4config.isValid() ) { QDBusObjectPath path = qvariant_cast<QDBusObjectPath>(ipv4config); QDBusInterface ifc(NM_DBUS_SERVICE, path.path(), "org.freedesktop.NetworkManager.IP4Config", QDBusConnection::systemBus()); if ( ifc.isValid() ) { qDebug() << "Error 1 = " << ifc.lastError().message(); // No error. Everything is OK. QVariant addresses = ifc.property("Addresses"); // Throwing the QDBusAbstractInterface Error where the property is good and does exist. if ( addresses.isValid() ) { qDebug () << "Addresses are valid"; } else { qDebug () << "Addresses are invalid"; } qDebug() << "Error 2 = " << ifc.lastError().message(); } } } } } 

UPDATE # 1

I think this is a type problem. A Qt-Dbus system does not understand the type of the Address property, so it cannot create a QVariant. Therefore, before reading the Address property, I added the following lines. NetworkManager defines the Addresses property as the next type, so I assume that my typedef is good.

aau - "An array of tuples of IPv4 address / prefix / gateway. All 3 elements of each tuple are in network byte order. Essentially: [(addr, prefix, gateway), (addr, prefix, gateway), ...]"

 typedef QList<QList<uint> > Addresses; Q_DECLARE_METATYPE(Addresses) qDBusRegisterMetaType<Addresses>() QVariant addresses = ifc.property("Addresses"); 

I also switched to Qt 5.1 (I used 4.8 before) and I get the same error in the following form.

 Cannot construct placeholder type QDBusRawType 

Thoughts / Suggestions

Regards, Farrukh Arshad

+6
source share
2 answers

As far as I know, the problem is related to type conversion. The property value is in the form aau (as per NM Dbus documentation). QDbusInterface.property returns a QVariant. It finds a property, but cannot determine the type of property, therefore giving me an error message. But I'm worried that I registered my own type of this property with the Qt Meta Object system, as I mentioned in Update # 1, and why it gives me this error. My type was registered on the system correctly, and qDBusRegisterMetaType really returned me a real integer. In Qt 5.1, the origin of the error is in qdbusmaster.cpp. One article suggests registering a meta-type as follows, but to no avail.

 qRegisterMetaType<Addresses>("Addresses"); qDBusRegisterMetaType<Addresses>(); 

At the moment, I do not have time for further search to find out if there is any error or something is missing, but I will update this message after I have a real solution.

DECISION

The following workaround will work to read this property value. For this workaround, you need to add qdbus-private instead of qdbus and enable it.

 QVariant ipv4config = device.property("Ip4Config"); if ( ipv4config.isValid() ) { QDBusObjectPath path = qvariant_cast<QDBusObjectPath>(ipv4config); QDBusMessage message = QDBusMessage::createMethodCall(NM_DBUS_SERVICE, path.path(), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get")); QList<QVariant> arguments; arguments << "org.freedesktop.NetworkManager.IP4Config" << "Addresses"; message.setArguments(arguments); QDBusConnection connection = QDBusConnection::systemBus(); QDBusMessage reply = connection.call(message); foreach(QVariant var, reply.arguments()) { qDebug () << "String = " << QDBusUtil::argumentToString(var).toHtmlEscaped(); } } 

The line will show you the IP address / subnet mask / router that you need to extract from the output. For the record, I used this approach from qdbusviewer.

This is not the right decision, but so far it will seem unpleasant to you. There is also a good article suggesting the use of custom types with Qt Dbus. http://techbase.kde.org/Development/Tutorials/D-Bus/CustomTypes

+5
source

The best solution I found for this was to write an implementation of QDBusAbstractInterface:

 typedef QList<QList<uint> > UIntListList; Q_DECLARE_METATYPE(UIntListList) class DBusIP4ConfigInterface : public QDBusAbstractInterface { Q_OBJECT public: DBusIP4ConfigInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0) { qDBusRegisterMetaType<UIntListList>(); } virtual ~DBusIP4ConfigInterface() { } Q_PROPERTY(UIntListList Addresses READ addresses) UIntListList addresses() const { return qvariant_cast<UIntListList>(property("Addresses")); } Q_PROPERTY(QString Gateway READ gateway) QString gateway() const { return qvariant_cast<QString>(property("Gateway")); } Q_SIGNALS: void PropertiesChanged(const QVariantMap &properties); }; 

This has the added benefit of being quite easy to use:

 UIntListList addresses = m_dbusIP4Config->addresses(); Q_ASSERT(addresses.size() >= 1); Q_ASSERT(addresses[0].size() == 3); QHostAddress ip = QHostAddress(qFromBigEndian(addresses[0][0])); 
0
source

Source: https://habr.com/ru/post/958291/


All Articles