Error reading DBus interface properties returning QVariant using QDBusInterface
-
I am trying to get networking information (IP Address, Netmask, Route etc.) for all my interfaces in Qt using NetworkManager DBus interface. The problem is when I try to access the property "Addresses" 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 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 above interface's mentioned property via qtdbusviewer. Following is my code snippet.
@
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(); } } } } }
@
I think it appears to be problem of types. Qt-Dbus type system does not understand the type of "Addresses" property so unable to create a QVariant out of it. So I added following lines before reading the property "Addresses". NetworkManager defines the property Addresses as following type, so I guess my typedef is good.aau - "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");
@Also I switched to Qt 5.1 (Earlier I was using 4.8), and I am getting the same error. In Qt 5.1 this error is somewhat beautiful.
Thoughts / Suggestions
Regards,
Farrukh Arshad. -
So far as per my research the problem is related to the type conversion. The property value is in the form of aau (as per NM Dbus documentation). QDbusInterface.property returns QVariant. It does find the property but unable to determine the type of the property hence giving me the error message. But my concern is, I have registered the custom type of this property with the Qt Meta Object system as I have mentioned in the Update # 1 then why it is giving me this error my type was registered with the system properly and qDBusRegisterMetaType did returned me a valid integer. In Qt 5.1 the origin of the error is in qdbusmaster.cpp. One article suggests to register meta type as mentioned below, but to no avail.
@
qRegisterMetaType<Addresses>("Addresses");
qDBusRegisterMetaType<Addresses>();
@
For now I don't have time to further dig into to see if it is some bug or I am missing something, but I will update this post once I have actual solution.WORKAROUND
Following workaround will work to read the given property value. For this workaround to work you need to add qdbus-private instead of qdbus and include <private/qdbusutil_p.h>.
@
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 string will show you the IP Address / Subnet Mask / Router IP which you will have to extract from the output. I have taken this approach from qdbusviewer.
This is not the the right solution, but it will get you out of trouble for the time being. There is also a good article suggesting usage of custom types with Qt Dbus.
http://techbase.kde.org/Development/Tutorials/D-Bus/CustomTypes