Search code examples
qtdbusconnman

Catching and responding to the Connman 'RequestInput' method call with QtDBus


I'm building a simple Qt-based application for monitoring and connecting to WiFi networks. I'm interfacing with Connman via its D-Bus APIs, and am able to scan for available networks, turn on/off technologies and register an agent as expected. I'm currently unable to provide the requested passphrase when the Connman RequestInput method is called (when attempting to connect to a protected/secure network), as I'm unsure how to bind the RequestInput method with a function in Qt.

Below is some indicative code which outlines the approach:

//Create a QDBusConnection systemBus() object
QDBusConnection connection = QDBusConnection::systemBus();

//Ensure the systemBus() connection is established
if (!connection.isConnected()) {
    qDebug() << "Connection error.";
}

//Create a Connman Manager D-Bus API interface object
QDBusInterface manager("net.connman", "/", "net.connman.Manager", connection);

//Register an agent with the Connman Manager API
manager.call("RegisterAgent", QVariant::fromValue(QDBusObjectPath("/test/agent")));

//Attempt to bind the mySlot() function with the net.connman.Agent RequestInput method
//This does not currently work
connection.connect("",
                   "/test/agent",
                   "net.connman.Agent",
                   "RequestInput",
                    this,
                    SLOT(mySlot(QDBusObjectPath, QVariantMap)));

//Create a Connman Service D-Bus API interface object (for a specific WiFi Service)
QDBusInterface service("net.connman",
                       "/net/connman/service/[WIFI SERVICE]",
                       "net.connman.Service",
                        connection);

//Attempt to connect to the secure WiFi network
//Note: this network has not previously been connected, so the RequestInput method is guaranteed to be called
service.call("Connect");

QVariantMap myClass::mySlot(const QDBusObjectPath &path, const QVariantMap &map)
{
    //Connman Agent RequestInput() method received
}

As commented above, the attempted binding of the /test/agent path, net.connman.Agent interface and RequestInput method to the mySlot() function does not work; there are no errors reported but the mySlot() function is never called. If I enable debugging with the QDBUS_DEBUG environment variable, I receive the following:

QDBusConnectionPrivate(0xffff74003a00) got message (signal): QDBusMessage(type=MethodCall, service=":1.3", path="/test/agent", interface="net.connman.Agent", member="RequestInput", signature="oa{sv}", contents=([ObjectPath: /net/connman/service/[WIFI SERVICE]], [Argument: a{sv} {"Passphrase" = [Variant: [Argument: a{sv} {"Type" = [Variant(QString): "psk"], "Requirement" = [Variant(QString): "mandatory"]}]]}]) )

The above is exactly what I'd expect; the RequestInput method is being called for the /test/agent path on the net.connman.Agent interface with the oa{sv} signature.

My questions:

  1. How do I 'connect' to the RequestInput method call, such that my mySlot() function can parse the RequestInput method data?
  2. How do I return the required QVariantMap from within mySlot()?

Solution

  • From the debug output it appears that ConnMan is doing a MethodCall, but QDBusConnection::connect() is for handling DBus singals, which is why your slot is not invoked.

    You need to register an object implementing the net.connman.Agent interface onto the corresponding path, so that ConnMan can invoke your methods:

    class ConnManAgent : public QObject {
        Q_OBJECT
        Q_CLASSINFO("D-Bus Interface", "net.connman.Agent")
    public:
        ConnManAgent(QObject *parent = nullptr);
    
        Q_INVOKABLE QVariantMap RequestInput(const QDBusObjectPath &, const QVariantMap &);
    
       // ... Rest of the net.connman.Agent interface
    };
    

    and then register it on the respective path:

    connection.registerObject(
        QStringLiteral("/test/agent"),
        new ConnManAgent(this), 
        QDBusConnection::ExportAllInvokables);
    

    This exports all methods marked with Q_INVOKABLE to DBus. You might also mark them as Q_SLOTS and use ExportAllSlots, that's mostly up to you.