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