Fwd: C++ libubus wrapper
Wojciech Jowsa
wojciech.jowsa at gmail.com
Thu Feb 4 12:25:42 EST 2021
czw., 4 lut 2021 o 10:32 Felix Fietkau <nbd at nbd.name> napisał(a):
>
>
> On 2021-02-03 20:02, Wojciech Jowsa wrote:
> > Hi,
> >
> > I would like to write a libubus wrapper in C++. When looking into
> > ubus_method and ubus_handler_t structures I don't see a place where I
> > could pass a this pointer. It makes the handling of ubus calls in C++
> > a bit complicated.
> > The solution to that case would be adding a void pointer to the
> > ubus_method structure (like in the ubus_request struct). This way it
> > would be possible to pass e.g function pointer.
> > Would it be possible to add a void pointer to ubus_method structure?
> > If yes then I will provide the patch asap.
> I don't think a 'this' pointer should be in the ubus_method. Methods can
> typically be shared between multiple ubus_objects, and the 'this'
> pointer would typically go into the ubus_object.
The pointer would share the same concept as the .handler member of
ubus_method structure.
It means that C++ handler method would be called based on the ubus method name.
Void pointer could also be the last argument of ubus_handler_t. Then
I see that e.g. ubus_request structure has a void pointer as a member
or ubus_lookup has a void pointer
parameter so the idea is implemented but only partially.
> However, even there it is not necessary to have a void pointer directly
> in the struct. You can simply embed the ubus_object in another data
> structure which contains the 'this' pointer (or maybe is even embedded
> in the C++ object directly)
Then obtain parent struct with container_of? This might somehow work
but personally I have never tried that.
I think that the common pattern for C libraries API methods is to
allow passing a user data through a void pointer either as
a function parameter or as a structure member.
> I don't write code in C++ myself, so if there's something I'm missing
> here, please let me know and show me some details.
The flow would be following (I omit external event-loop handling)
//Define function pointer type and a struct which contains a function pointer.
//The function pointer is the same as ubus_handler_t
//The struct is required to be able to cast to void*
typedef std::function<int(ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req,
const char *method, struct blob_attr *msg)> IUbus_f_ptr;
struct IUbusEntry
{
IUbus_f_ptr f_ptr;
};
//In the class using ubus wrapper, bind member function (handler) with
this and call addUbusObject method from C++ ubus wrapper
int ubusCB(ubus_context *ctx, struct ubus_object *obj, struct
ubus_request_data *req, const char *method, struct blob_attr *msg);
IUbus::IUbusEntry_t mUbus_cb;
mUbus_cb.f_ptr = std::bind(&UBusHandler::ubusCB, this, _1, _2, _3, _4, _5);
mUbus.addObject(&mUbus_cb);
// In addObject(IUbusEntry_t *aCallback), set .priv to aCallback method.
// In a static testMethod match a method based on its name and call a
C++ callback (priv pointer).
ubus_method lMethod;
memset(&lMethod, 0, sizeof(ubus_method));
lMethod.name = "restart";
lMethod.handler = &IUbus::testMethod;
lMethod.priv = (void*) aCallback;
int IUbus::testMethod( ubus_context *ctx, ubus_object *obj,
ubus_request_data *req, const char *method,
blob_attr *msg)
{
for(int i = 0; i < obj->n_methods; i++) {
if(!strcmp(obj->methods[i].name, method)) {
return ((IUbus::IUbusEntry_t
*)(obj->methods[i].priv))->f_ptr(ctx, obj, req, method, msg);
}
}
return 0;
}
As I wrote before the void pointer could be a part of ubus_method
struct or the last argument of ubus_handler_t.
It would really make using ubus in C++ projects easier :)
BR,
Wojtek
More information about the openwrt-devel
mailing list