user2952272
user2952272

Reputation: 341

D-Bus client not receiving signal events in the system bus

I am using the sdbus-cpp libary to test how to create a service and access it's methods and signals through a D-Bus client. The library provides an example of this that I tested and worked for me. However, this example creates a service in the session bus and I would like to make it work on the system bus. This is the example:

Server side:

#include <sdbus-c++/sdbus-c++.h>
#include <vector>
#include <string>

int main(int argc, char *argv[])
{
    // Create D-Bus connection to the (either system or session) bus and requests a well-known name on it.
    sdbus::ServiceName serviceName{"org.sdbuscpp.concatenator"};
    auto connection = sdbus::createBusConnection(serviceName);

    // Create concatenator D-Bus object.
    sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
    auto concatenator = sdbus::createObject(*connection, std::move(objectPath));

    auto concatenate = [&concatenator](const std::vector<int> numbers, const std::string& separator)
    {
        // Return error if there are no numbers in the collection
        if (numbers.empty())
            throw sdbus::Error(sdbus::Error::Name{"org.sdbuscpp.Concatenator.Error"}, "No numbers provided");

        std::string result;
        for (auto number : numbers)
        {
            result += (result.empty() ? std::string() : separator) + std::to_string(number);
        }

        // Emit 'concatenated' signal
        concatenator->emitSignal("concatenated").onInterface("org.sdbuscpp.Concatenator").withArguments(result);
        std::cout << "Signal emitted with result: " << result << std::endl;

        return result;
    };

    // Register D-Bus methods and signals on the concatenator object, and exports the object.
    concatenator->addVTable(sdbus::registerMethod("concatenate").implementedAs(std::move(concatenate)),
                            sdbus::registerSignal("concatenated").withParameters<std::string>())
                           .forInterface("org.sdbuscpp.Concatenator");

    // Run the loop on the connection.
    connection->enterEventLoop();
}

Client side:

#include <sdbus-c++/sdbus-c++.h>
#include <vector>
#include <string>
#include <iostream>
#include <unistd.h>

void onConcatenated(const std::string& concatenatedString)
{
    std::cout << "Received signal with concatenated string " << concatenatedString << std::endl;
}

int main(int argc, char *argv[])
{
    // Create proxy object for the concatenator object on the server side
    sdbus::ServiceName destination{"org.sdbuscpp.concatenator"};
    sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
    auto concatenatorProxy = sdbus::createProxy(std::move(destination), std::move(objectPath));

    // Let's subscribe for the 'concatenated' signals
    sdbus::InterfaceName interfaceName{"org.sdbuscpp.Concatenator"};
    concatenatorProxy->uponSignal("concatenated").onInterface(interfaceName).call([](const std::string& str){ onConcatenated(str); });
    std::cout << "Signal handler registered." << std::endl;

    std::vector<int> numbers = {1, 2, 3};
    std::string separator = ":";

    // Invoke concatenate on given interface of the object
    {
        std::string concatenatedString;
        concatenatorProxy->callMethod("concatenate").onInterface(interfaceName).withArguments(numbers, separator).storeResultsTo(concatenatedString);
        assert(concatenatedString == "1:2:3");
        std::cout << "Methode result assert: " << concatenatedString << std::endl;
    }

    // Invoke concatenate again, this time with no numbers and we shall get an error
    {
        try
        {
            concatenatorProxy->callMethod("concatenate").onInterface(interfaceName).withArguments(std::vector<int>(), separator);
            assert(false);
        }
        catch(const sdbus::Error& e)
        {
            std::cerr << "Got concatenate error " << e.getName() << " with message " << e.getMessage() << std::endl;
        }
    }

    // Give sufficient time to receive 'concatenated' signal from the first concatenate invocation
    sleep(2);

    return 0;
}

To test the example I execute the client and the server in two separate terminals. This is the output of both client and server. They work as expected:

enter image description here

Then, to test this same example in the system bus, for starters I already created a policy file in /etc/dbus-1/system.d that looks like this:

<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="me">
<allow own="org.sdbuscpp.concatenator"/>
<allow send_destination="org.sdbuscpp.concatenator"/>
<allow send_interface="org.sdbuscpp.Concatenator" send_type="method_call"/>
<allow send_interface="org.sdbuscpp.Concatenator" send_type="signal"/>
<allow receive_sender="org.sdbuscpp.concatenator"/>
<allow receive_type="signal"/>
</policy>
</busconfig>

The problem I am having is that the client is not detecting the signal generated by the server when testing this in the system bus. However, it works in the session bus. And I am sure the method executed by the client is reaching the server because I print the data received by the server and it's correct ("1:2:3").

I am not sure what am I doing wrong, am I lacking some permit in the policy file? I also tried changing the policy line to but was getting the same issue. Do I also need to provide a .service file in /etc/systemd/system? Doesn't look like it by my understanding.

I also tried using this more generic policy file with the same results:

<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="me">
<allow own="org.sdbuscpp.concatenator"/>
</policy>    
<policy context="default">
<allow send_destination="org.sdbuscpp.concatenator" send_interface="org.sdbuscpp.Concatenator"/>
</policy>
</busconfig>

Here are the changes I did to the client and server from the example, to try using them in the system bus. Basically just specified that the connection should be to the system bus:

Client side:

auto connection = sdbus::createSystemBusConnection();
sdbus::ServiceName destination{"org.sdbuscpp.concatenator"};
sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
auto concatenatorProxy = sdbus::createProxy(*connection, std::move(destination), std::move(objectPath));

Server side:

sdbus::ServiceName serviceName{"org.sdbuscpp.concatenator"};
auto connection = sdbus::createSystemBusConnection(serviceName);
sdbus::ObjectPath objectPath{"/org/sdbuscpp/concatenator"};
auto concatenator = sdbus::createObject(*connection, std::move(objectPath));

Again, I execute the client and the server in two separate terminals. This is the output of both client and server. As you can see the string "Received signal with concatenated string 1:2:3" is not being shown this time, meaning the client didn't detect the signal triggering:

enter image description here

Upvotes: 3

Views: 113

Answers (0)

Related Questions