-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error when implementing DBus ObjectManager #50
Comments
Hi, the error return value probably originates in sd-bus here:
https://github.com/systemd/systemd/blob/master/src/libsystemd/sd-bus/bus-objects.c#L1777
sd-bus seems to provide standard interfaces for all objects itself. So to
all user's D-Bus objects, sd-bus adds four additional interfaces. And
implements them according to specs. If it's the user who tries to provide
one or more of these standard interfaces, sd-bus rejects that.
So the good news is that they're there already and you don't have to
implement them yourself :)
…On Wed, May 8, 2019 at 10:41 PM Mike Willard ***@***.***> wrote:
I am attempting to implement the org.freedesktop.DBus.ObjectManager
interface, as defined here
<https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager>
.
Through introspection of other DBus services, I was able to produce an XML
interface definition for the ObjectManager interface. The ObjectManager
requires a method GetManagedObjects with the argument signature
a{oa{sa{sv}}}, and emits two signals for InterfacesAdded and
InterfacesRemoved.
The XML I generated looks like this:
<node>
<interface name="org.freedesktop.DBus.ObjectManager">
<method name="GetManagedObjects">
<arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
</method>
<signal name="InterfacesAdded">
<arg type="o" name="object_path"/>
<arg type="a{sa{sv}}" name="interfaces_and_properties"/>
</signal>
<signal name="InterfacesRemoved">
<arg type="o" name="object_path"/>
<arg type="as" name="interfaces"/>
</signal>
</interface>
</node>
The problem I am having is that when I go to create this service and
register with DBus, I am getting the following error:
terminate called after throwing an instance of 'sdbus::Error'
what(): [org.freedesktop.DBus.Error.InvalidArgs] Failed to register object vtable (Invalid argument)
So, it seems that for some reason my implementation is not valid according
to the DBus ObjectManager interface. I have not been able to figure out
why. If I change my code to use an interface name other than
"org.freedesktop.DBus.ObjectManager", it works fine, so it seems that there
is some kind of validation going on when I try to register something as an
ObjectManager. I have not been able to figure out where my DBus service
differs from the spec.
I have copied below the code from 3 files: the source code of the simple
application I am trying to run, the class I created for the ObjectManager
adapter, and the auto-generated adapter glue code that was generated using
the sdbus-c++-xml2cpp` tool.
I have also tried manually registering the interface, using
gattService->registerMethod() and passing the interface name and
arguments in manually, but I still got the same error.
Any help is greatly appreciated!
Source code of simple-gatt-service.cpp
#include "interfaces/objectmanager_adapter.h"
#include <vector>
#include <string>
#include <iostream>
#include <unistd.h>
int main(int argc, char *argv[])
{
// Create D-Bus connection to the system bus and requests name on it.
const char* serviceName = "org.gattservice";
auto connection = sdbus::createSystemBusConnection(serviceName);
// Create D-Bus object.
const char* objectPath = "/org/gattservice";
auto gattService = sdbus::createObject(*connection, objectPath);
ObjectManagerAdapter objectManager(*connection, objectPath);
connection->enterProcessingLoop();
}
Source code of objectmanager_adapter.h
#include "objectmanager_adapter_glue.h"
using ObjectManagerAdapterInterface = sdbus::AdaptorInterfaces<org::freedesktop::DBus::ObjectManager_adaptor>;
class ObjectManagerAdapter : public ObjectManagerAdapterInterface
{public:
ObjectManagerAdapter(sdbus::IConnection& connection, std::string objectPath)
: ObjectManagerAdapterInterface(connection, objectPath)
{
registerAdaptor();
}
~ObjectManagerAdapter()
{
unregisterAdaptor();
}private:
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> GetManagedObjects() override
{
std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> mapOfObjects;
return {mapOfObjects};
}
};
Source code of objectmanager_adapter_glue.h (auto-generated from xml)
/* * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! */
#ifndef __sdbuscpp__objectmanager_adapter_glue_h__adaptor__H__
#define __sdbuscpp__objectmanager_adapter_glue_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {namespace freedesktop {namespace DBus {
class ObjectManager_adaptor
{public:
static constexpr const char* interfaceName = "org.freedesktop.DBus.ObjectManager";
protected:
ObjectManager_adaptor(sdbus::IObject& object)
: object_(object)
{
object_.registerMethod("GetManagedObjects").onInterface(interfaceName).implementedAs([this](){ return this->GetManagedObjects(); });
object_.registerSignal("InterfacesAdded").onInterface(interfaceName).withParameters<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>>();
object_.registerSignal("InterfacesRemoved").onInterface(interfaceName).withParameters<sdbus::ObjectPath, std::vector<std::string>>();
}
public:
void InterfacesAdded(const sdbus::ObjectPath& object_path, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfaces_and_properties)
{
object_.emitSignal("InterfacesAdded").onInterface(interfaceName).withArguments(object_path, interfaces_and_properties);
}
void InterfacesRemoved(const sdbus::ObjectPath& object_path, const std::vector<std::string>& interfaces)
{
object_.emitSignal("InterfacesRemoved").onInterface(interfaceName).withArguments(object_path, interfaces);
}
private:
virtual std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> GetManagedObjects() = 0;
private:
sdbus::IObject& object_;
};
}}} // namespaces
#endif
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#50>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABM3OURNK43IPR3I3NGPAALPUM3HRANCNFSM4HLVB5UQ>
.
|
Oh wow, that makes my job easier :) Thanks! |
I've just added a subsection on this behavior to the docs: https://github.com/Kistler-Group/sdbus-cpp/blob/master/docs/using-sdbus-c++.md#standard-d-bus-interfaces I think I should also add |
For some reason I am still having trouble getting the ObjectManager to show up. I put together a simple c++ application that creates a D-Bus object with a single interface and property. When I look at that object in D-Feet, it doesn't list the ObjectManager interface. However, I was able to get it to show up by explicitly calling sd_bus_add_object_manager on the connection. I made a branch here showing the work to do that: When I add this function call, I am able to see the ObjectManager in D-Feet, and calling the GetManagedObjects function works as expected. Do you know why I am not be seeing the ObjectManager added by default? Here's the simple c++ program: #include <sdbus-c++/sdbus-c++.h>
int main(int argc, char *argv[])
{
// Create D-Bus connection to the system bus and requests name on it.
const char* serviceName = "org.example.service";
auto connection = sdbus::createSystemBusConnection(serviceName);
// Create D-Bus object.
const char* objectPath = "/org/example/service";
auto serviceObject = sdbus::createObject(*connection, objectPath);
// Register D-Bus methods and signals on the object, and export the object.
const char* interfaceName = "org.example.service";
serviceObject->registerProperty("Name").onInterface(interfaceName).withGetter([](){ return "hello"; }).withSetter([](const uint32_t& value){ });
serviceObject->finishRegistration();
// Start the service
connection->enterProcessingLoop();
} Here's the same program with the call to sd_bus_add_object_manager added. This will require the changes on my branch to compile. #include <sdbus-c++/sdbus-c++.h>
int main(int argc, char *argv[])
{
// Create D-Bus connection to the system bus and requests name on it.
const char* serviceName = "org.example.service";
auto connection = sdbus::createSystemBusConnection(serviceName);
// Create D-Bus object.
const char* objectPath = "/org/example/service";
auto serviceObject = sdbus::createObject(*connection, objectPath);
// Register D-Bus property on the object, and export the object.
const char* interfaceName = "org.example.service";
serviceObject->registerProperty("Name").onInterface(interfaceName).withGetter([](){ return "hello"; }).withSetter([](const uint32_t& value){ });
serviceObject->finishRegistration();
// Add an objectManager interface at the root of the service
connection->addObjectManager("/");
// Start the service
connection->enterProcessingLoop();
} The attached screenshots show how the service shows up in D-Feet before and after adding the function call. |
Having ObjectManager not as a default interface for every D-Bus object is a design decision of sd-bus, the underlying D-Bus implementation. It is available, just that it has to be added explicitly for a given object path. I've accepted your changes (thank you) and extended the |
Returning to this after a month away... Hello @mdw87 - were you able to get sdbus-cpp, Bluez, and ObjectManager to play well with each other? Is your code public? Could I look at it for inspirational purposes? Hello @sangelovic - did you add support for emitting Properties- and ObjectManager-related signals? How critical (do you think) support for those is? --wpd |
I am attempting to implement the
org.freedesktop.DBus.ObjectManager
interface, as defined here.Through introspection of other DBus services, I was able to produce an XML interface definition for the ObjectManager interface. The ObjectManager requires a method
GetManagedObjects
with the argument signaturea{oa{sa{sv}}}
, and emits two signals forInterfacesAdded
andInterfacesRemoved
.The XML I generated looks like this:
The problem I am having is that when I go to create this service and register with DBus, I am getting the following error:
So, it seems that for some reason my implementation is not valid according to the DBus ObjectManager interface. I have not been able to figure out why. If I change my code to use an interface name other than "org.freedesktop.DBus.ObjectManager", it works fine, so it seems that there is some kind of validation going on when I try to register something as an ObjectManager. I have not been able to figure out where my DBus service differs from the spec.
I have copied below the code from 3 files: the source code of the simple application I am trying to run, the class I created for the ObjectManager adapter, and the auto-generated adapter glue code that was generated using the sdbus-c++-xml2cpp` tool.
I have also tried manually registering the interface, using
gattService->registerMethod(interfaceName, "GetManagedObjects", "", "a{oa{sa{sv}}}", &GetManagedObjects)
rather than the stubs generated from XML, but I still got the same error.Any help is greatly appreciated!
Source code of simple-gatt-service.cpp
Source code of objectmanager_adapter.h
Source code of objectmanager_adapter_glue.h (auto-generated from xml)
The text was updated successfully, but these errors were encountered: