[systemd-devel] Calling sd_bus_reply_method_return outside method handler

Jean Valjean valjean.jean1802 at gmail.com
Thu Jan 24 20:36:42 UTC 2019


After some experimentation I came to realize that it is not possible
to send a response to a message at later time
if handler is registered with sd_bus_add_object_vtable for some object
and interface. The message must be processed
and reply send in function that given to sd_bus_vtable. To work around
this one has to process messages with  sd_bus_process(bus_, &msg).
And scan msg for path and other information. Unfortunately with this
approach introspection is not automatic.

On Tue, 15 Jan 2019 at 19:06, Jean Valjean <valjean.jean1802 at gmail.com> wrote:
>
> Thank you for your explanation, Lenart. I tried different approach.
> Everything is running on a single thread. I have a global
> `sd_bus_message* test` variable. I do the following
>
> int method_handler(sd_bus_message* m, void* /*userdata*/,
> sd_bus_error* /*error*/) {
>   test = sd_bus_message_ref(m);
>   return 0;
> }
>
> And create an object with
>
> static const sd_bus_vtable vtable[] = {
>   SD_BUS_VTABLE_START(0),
>   SD_BUS_PROPERTY("Description", "s", property_handler, 0,
> SD_BUS_VTABLE_PROPERTY_CONST),
>   SD_BUS_METHOD("Do",  "s", "s", method_handler, SD_BUS_VTABLE_UNPRIVILEGED),
>   SD_BUS_VTABLE_END
> };
>
> r = sd_bus_add_object_vtable(
>         bus_,
>         nullptr,
>         path,
>         interface,
>         vtable,
>         nullptr
> );
>
> Connect to bus, request service name and start waiting for incoming messages
> sd_bus_open_user(&bus_);
> sd_bus_request_name(bus_, service_name_, 0);
>
>   while(true){
>      sd_bus_process(bus_, NULL);
>
>     if (r > 0) {
>       continue;
>     }
>
>     if (test) {
>       int r = sd_bus_message_get_errno(test);
>
>       if(!r) {
>         const char* reply = "reply";
>         r  = sd_bus_reply_method_return(test, "s", reply);
>       }else {
>         std::cout << "Error\n";
>       }
>
>       sd_bus_message_unref(test);
>       test = nullptr;
>     }
>     r = sd_bus_wait(bus_, 1e+6);
>   }
>
> sd_bus_reply_method_return(test, "s", reply) doesn't do anything if
> called outside method_handler.
> I think that the call that is responsible for invoking method_handler
> sends an error back to the client when method_handler returns.
> Hence the connection to client is actually closed when I call
> sd_bus_reply_method_return(test, "s", reply).
> In that case I suppose sd_bus_message_get_errno should return an error
> but it doesn't.
>
> I'm using mailinglist for the first time so I'm not sure it that OK to
> post code here. Hope it will show correctly in your email client.
>
>
> On Tue, 15 Jan 2019 at 15:05, Lennart Poettering <mzerqung at 0pointer.de> wrote:
> >
> > On Mo, 14.01.19 21:07, Jean Valjean (valjean.jean1802 at gmail.com) wrote:
> >
> > > I want to send a reply to a method call outside method_handler. Is it
> > > possible?
> > > In the method_handler I increase reference count of sd_bus_message and send
> > > it to the other thread. From there I want to call
> > > sd_bus_reply_method_return to send a reply but get Unknown method or
> > > interface error when I invoke method with bussctl --user call. If I call
> > > the return method from method_handler everything works as expected.
> >
> > Note that sd-bus is not thread-safe on its own. It's threads-aware
> > however: if you are careful to lock around all invocations of sd_bus
> > using a single connection (and its associated messages) is generally
> > fine, but it's up to you to carefully lock.
> >
> > So yeah, it's certainly OK to reply to an incoming bus call msgs
> > outside of the stack method handler stack frame, but if that means
> > threads, then make sure you know what you are doing.
> >
> > Lennart
> >
> > --
> > Lennart Poettering, Red Hat


More information about the systemd-devel mailing list