2 * Copyright (C) 2015-2018 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #if defined(WITH_DBUS_TRANSPARENCY)
28 #include <systemd/sd-bus.h>
29 #include <json-c/json.h>
31 #include <afb/afb-event-x2.h>
33 #include "afb-systemd.h"
35 #include "afb-session.h"
36 #include "afb-msg-json.h"
38 #include "afb-apiset.h"
39 #include "afb-api-dbus.h"
40 #include "afb-context.h"
46 static const char DEFAULT_PATH_PREFIX[] = "/org/agl/afb/api/";
53 * The path given are of the form
54 * system:/org/agl/afb/api/...
56 * user:/org/agl/afb/api/...
60 struct sd_bus *sdbus; /* the bus */
61 char *path; /* path of the object for the API */
62 char *name; /* name/interface of the object */
63 char *api; /* api name of the interface */
66 struct sd_bus_slot *slot_broadcast;
67 struct sd_bus_slot *slot_event;
68 struct dbus_event *events;
69 struct dbus_memo *memos;
72 struct sd_bus_slot *slot_call;
73 struct afb_evt_listener *listener; /* listener for broadcasted events */
74 struct origin *origins;
75 struct afb_apiset *apiset;
80 /******************* common part **********************************/
83 * create a structure api_dbus connected on either the system
84 * bus if 'system' is not null or on the user bus. The connection
85 * is established for either emiting/receiving on 'path' being of length
88 static struct api_dbus *make_api_dbus_3(int system, const char *path, size_t pathlen)
94 /* allocates the structure */
95 api = calloc(1, sizeof *api + 1 + pathlen + pathlen);
101 /* init the structure's strings */
103 /* path is copied after the struct */
104 api->path = (void*)(api+1);
105 strcpy(api->path, path);
107 /* api name is at the end of the path */
108 api->api = strrchr(api->path, '/');
109 if (api->api == NULL) {
114 if (!afb_api_is_valid_name(api->api)) {
119 /* the name/interface is copied after the path */
120 api->name = &api->path[pathlen + 1];
121 strcpy(api->name, &path[1]);
122 ptr = strchr(api->name, '/');
125 ptr = strchr(ptr, '/');
129 sdbus = (system ? afb_systemd_get_system_bus : afb_systemd_get_user_bus)();
143 * create a structure api_dbus connected on either the system
144 * bus if 'system' is not null or on the user bus. The connection
145 * is established for either emiting/receiving on 'path'.
146 * If 'path' is not absolute, it is prefixed with DEFAULT_PATH_PREFIX.
148 static struct api_dbus *make_api_dbus_2(int system, const char *path)
153 /* check the length of the path */
160 /* if the path is absolute, creation now */
162 return make_api_dbus_3(system, path, len);
164 /* compute the path prefixed with DEFAULT_PATH_PREFIX */
165 assert(strlen(DEFAULT_PATH_PREFIX) > 0);
166 assert(DEFAULT_PATH_PREFIX[strlen(DEFAULT_PATH_PREFIX) - 1] == '/');
167 len += strlen(DEFAULT_PATH_PREFIX);
168 ptr = alloca(len + 1);
169 strcpy(stpcpy(ptr, DEFAULT_PATH_PREFIX), path);
171 /* creation for prefixed path */
172 return make_api_dbus_3(system, ptr, len);
176 * create a structure api_dbus connected either emiting/receiving
178 * The path can be prefixed with "system:" or "user:" to select
179 * either the user or the system D-Bus. If none is set then user's
181 * If remaining 'path' is not absolute, it is prefixed with
182 * DEFAULT_PATH_PREFIX.
184 static struct api_dbus *make_api_dbus(const char *path)
189 /* retrieves the prefix "scheme-like" part */
190 ptr = strchr(path, ':');
192 return make_api_dbus_2(0, path);
194 /* check the prefix part */
195 preflen = (size_t)(ptr - path);
196 if (strncmp(path, "system", preflen) == 0)
197 return make_api_dbus_2(1, ptr + 1);
199 if (strncmp(path, "user", preflen) == 0)
200 return make_api_dbus_2(0, ptr + 1);
202 /* TODO: connect to a foreign D-Bus? */
207 static void destroy_api_dbus(struct api_dbus *api)
212 /******************* client part **********************************/
215 * structure for recording query data
218 struct dbus_memo *next; /* the next memo */
219 struct api_dbus *api; /* the dbus api */
220 struct afb_xreq *xreq; /* the request */
221 uint64_t msgid; /* the message identifier */
226 struct dbus_event *next;
227 struct afb_event_x2 *event;
232 /* allocates and init the memorizing data */
233 static struct dbus_memo *api_dbus_client_memo_make(struct api_dbus *api, struct afb_xreq *xreq)
235 struct dbus_memo *memo;
237 memo = malloc(sizeof *memo);
239 afb_xreq_unhooked_addref(xreq);
243 memo->next = api->client.memos;
244 api->client.memos = memo;
249 /* free and release the memorizing data */
250 static void api_dbus_client_memo_destroy(struct dbus_memo *memo)
252 struct dbus_memo **prv;
254 prv = &memo->api->client.memos;
255 while (*prv != NULL) {
263 afb_xreq_unhooked_unref(memo->xreq);
267 /* search a memorized request */
268 static struct dbus_memo *api_dbus_client_memo_search(struct api_dbus *api, uint64_t msgid)
270 struct dbus_memo *memo;
272 memo = api->client.memos;
273 while (memo != NULL && memo->msgid != msgid)
279 /* callback when received answer */
280 static int api_dbus_client_on_reply(sd_bus_message *message, void *userdata, sd_bus_error *ret_error)
283 struct dbus_memo *memo;
284 const char *json, *error, *info;
286 /* retrieve the recorded data */
290 rc = sd_bus_message_read(message, "sss", &json, &error, &info);
292 /* failing to have the answer */
293 afb_xreq_reply(memo->xreq, NULL, "error", "dbus error");
295 /* report the answer */
296 afb_xreq_reply(memo->xreq, *json ? json_tokener_parse(json) : NULL, *error ? error : NULL, *info ? info : NULL);
298 api_dbus_client_memo_destroy(memo);
302 /* on call, propagate it to the dbus service */
303 static void api_dbus_client_call(void *closure, struct afb_xreq *xreq)
305 struct api_dbus *api = closure;
308 struct dbus_memo *memo;
309 struct sd_bus_message *msg;
312 /* create the recording data */
313 memo = api_dbus_client_memo_make(api, xreq);
315 afb_xreq_reply(memo->xreq, NULL, "error", "out of memory");
319 /* creates the message */
321 rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.called_verb);
325 creds = xreq_on_behalf_cred_export(xreq);
326 rc = sd_bus_message_append(msg, "ssus",
327 afb_xreq_raw(xreq, &size),
328 afb_session_uuid(xreq->context.session),
329 (uint32_t)xreq->context.flags,
335 rc = sd_bus_call_async(api->sdbus, NULL, msg, api_dbus_client_on_reply, memo, (uint64_t)-1);
339 rc = sd_bus_message_get_cookie(msg, &memo->msgid);
344 /* if there was an error report it directly */
346 afb_xreq_reply(memo->xreq, NULL, "error", "dbus error");
347 api_dbus_client_memo_destroy(memo);
349 sd_bus_message_unref(msg);
352 /* receives broadcasted events */
353 static int api_dbus_client_on_broadcast_event(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
355 struct json_object *object;
356 const char *event, *data;
357 int rc = sd_bus_message_read(m, "ss", &event, &data);
359 ERROR("unreadable broadcasted event");
361 object = json_tokener_parse(data);
362 afb_evt_broadcast(event, object);
367 /* search the eventid */
368 static struct dbus_event *api_dbus_client_event_search(struct api_dbus *api, int id, const char *name)
370 struct dbus_event *ev;
372 ev = api->client.events;
373 while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name)))
379 /* adds an eventid */
380 static void api_dbus_client_event_create(struct api_dbus *api, int id, const char *name)
382 struct dbus_event *ev;
384 /* check conflicts */
385 ev = api_dbus_client_event_search(api, id, name);
391 /* no conflict, try to add it */
392 ev = malloc(sizeof *ev);
394 ev->event = afb_evt_event_x2_create(name);
395 if (ev->event == NULL)
400 ev->next = api->client.events;
401 api->client.events = ev;
405 ERROR("can't create event %s, out of memory", name);
408 /* removes an eventid */
409 static void api_dbus_client_event_drop(struct api_dbus *api, int id, const char *name)
411 struct dbus_event *ev, **prv;
413 /* retrieves the event */
414 ev = api_dbus_client_event_search(api, id, name);
416 ERROR("event %s not found", name);
420 /* decrease the reference count */
424 /* unlinks the event */
425 prv = &api->client.events;
430 /* destroys the event */
431 afb_evt_event_x2_unref(ev->event);
436 static void api_dbus_client_event_push(struct api_dbus *api, int id, const char *name, const char *data)
438 struct json_object *object;
439 struct dbus_event *ev;
441 /* retrieves the event */
442 ev = api_dbus_client_event_search(api, id, name);
444 ERROR("event %s not found", name);
448 /* destroys the event */
449 object = json_tokener_parse(data);
450 afb_evt_event_x2_push(ev->event, object);
453 /* subscribes an event */
454 static void api_dbus_client_event_subscribe(struct api_dbus *api, int id, const char *name, uint64_t msgid)
457 struct dbus_event *ev;
458 struct dbus_memo *memo;
460 /* retrieves the event */
461 ev = api_dbus_client_event_search(api, id, name);
463 ERROR("event %s not found", name);
467 /* retrieves the memo */
468 memo = api_dbus_client_memo_search(api, msgid);
470 ERROR("message not found");
474 /* subscribe the request to the event */
475 rc = afb_xreq_subscribe(memo->xreq, ev->event);
477 ERROR("can't subscribe: %m");
480 /* unsubscribes an event */
481 static void api_dbus_client_event_unsubscribe(struct api_dbus *api, int id, const char *name, uint64_t msgid)
484 struct dbus_event *ev;
485 struct dbus_memo *memo;
487 /* retrieves the event */
488 ev = api_dbus_client_event_search(api, id, name);
490 ERROR("event %s not found", name);
494 /* retrieves the memo */
495 memo = api_dbus_client_memo_search(api, msgid);
497 ERROR("message not found");
501 /* unsubscribe the request from the event */
502 rc = afb_xreq_unsubscribe(memo->xreq, ev->event);
504 ERROR("can't unsubscribe: %m");
507 /* receives calls for event */
508 static int api_dbus_client_on_manage_event(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
510 const char *eventname, *data;
514 struct api_dbus *api;
517 /* check if expected message */
519 if (0 != strcmp(api->name, sd_bus_message_get_interface(m)))
520 return 0; /* not the expected interface */
521 if (0 != strcmp("event", sd_bus_message_get_member(m)))
522 return 0; /* not the expected member */
523 if (sd_bus_message_get_expect_reply(m))
524 return 0; /* not the expected type of message */
526 /* reads the message */
527 rc = sd_bus_message_read(m, "yisst", &order, &eventid, &eventname, &data, &msgid);
529 ERROR("unreadable event");
533 /* what is the order ? */
534 switch ((char)order) {
535 case '+': /* creates the event */
536 api_dbus_client_event_create(api, eventid, eventname);
538 case '-': /* drops the event */
539 api_dbus_client_event_drop(api, eventid, eventname);
541 case '!': /* pushs the event */
542 api_dbus_client_event_push(api, eventid, eventname, data);
544 case 'S': /* subscribe event for a request */
545 api_dbus_client_event_subscribe(api, eventid, eventname, msgid);
547 case 'U': /* unsubscribe event for a request */
548 api_dbus_client_event_unsubscribe(api, eventid, eventname, msgid);
551 /* unexpected order */
552 ERROR("unexpected order '%c' received", (char)order);
558 static struct afb_api_itf dbus_api_itf = {
559 .call = api_dbus_client_call
562 /* adds a afb-dbus-service client api */
563 int afb_api_dbus_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
566 struct api_dbus *api;
567 struct afb_api_item afb_api;
570 /* create the dbus client api */
571 api = make_api_dbus(path);
575 /* connect to broadcasted events */
576 rc = asprintf(&match, "type='signal',path='%s',interface='%s',member='broadcast'", api->path, api->name);
579 ERROR("out of memory");
582 rc = sd_bus_add_match(api->sdbus, &api->client.slot_broadcast, match, api_dbus_client_on_broadcast_event, api);
586 ERROR("can't add dbus match %s for %s", api->path, api->name);
590 /* connect to event management */
591 rc = sd_bus_add_object(api->sdbus, &api->client.slot_event, api->path, api_dbus_client_on_manage_event, api);
594 ERROR("can't add dbus object %s for %s", api->path, api->name);
598 /* record it as an API */
599 afb_api.closure = api;
600 afb_api.itf = &dbus_api_itf;
601 afb_api.group = NULL;
602 if (afb_apiset_add(declare_set, api->api, afb_api) < 0)
608 destroy_api_dbus(api);
613 /******************* event structures for server part **********************************/
615 static void afb_api_dbus_server_event_add(void *closure, const char *event, int eventid);
616 static void afb_api_dbus_server_event_remove(void *closure, const char *event, int eventid);
617 static void afb_api_dbus_server_event_push(void *closure, const char *event, int eventid, struct json_object *object);
618 static void afb_api_dbus_server_event_broadcast(void *closure, const char *event, int eventid, struct json_object *object);
620 /* the interface for events broadcasting */
621 static const struct afb_evt_itf evt_broadcast_itf = {
622 .broadcast = afb_api_dbus_server_event_broadcast,
625 /* the interface for events pushing */
626 static const struct afb_evt_itf evt_push_itf = {
627 .push = afb_api_dbus_server_event_push,
628 .add = afb_api_dbus_server_event_add,
629 .remove = afb_api_dbus_server_event_remove
632 /******************* origin description part for server *****************************/
636 /* link to next different origin */
639 /* the server dbus-api */
640 struct api_dbus *api;
642 /* count of references */
645 /* credentials of the origin */
646 struct afb_cred *cred;
652 /* get the credentials for the message */
653 static void init_origin_creds(struct origin *origin)
662 rc = sd_bus_get_name_creds(origin->api->sdbus, origin->name,
663 SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT,
668 afb_cred_unref(origin->cred);
669 sd_bus_creds_get_uid(c, &uid);
670 sd_bus_creds_get_gid(c, &gid);
671 sd_bus_creds_get_pid(c, &pid);
672 sd_bus_creds_get_selinux_context(c, &context);
673 origin->cred = afb_cred_create(uid, gid, pid, context);
674 sd_bus_creds_unref(c);
678 static struct origin *afb_api_dbus_server_origin_get(struct api_dbus *api, const char *sender)
680 struct origin *origin;
682 /* searchs for an existing origin */
683 origin = api->server.origins;
684 while (origin != NULL) {
685 if (0 == strcmp(origin->name, sender)) {
689 origin = origin->next;
692 /* not found, create it */
693 origin = malloc(strlen(sender) + sizeof *origin);
698 origin->refcount = 1;
699 strcpy(origin->name, sender);
700 init_origin_creds(origin);
701 origin->next = api->server.origins;
702 api->server.origins = origin;
707 static void afb_api_dbus_server_origin_unref(struct origin *origin)
709 if (!--origin->refcount) {
712 prv = &origin->api->server.origins;
713 while(*prv != origin)
716 afb_cred_unref(origin->cred);
723 /* link to next different origin */
724 struct origin *origin;
726 /* the listener of events */
727 struct afb_evt_listener *listener;
730 static void afb_api_dbus_server_listener_free(struct listener *listener)
732 afb_evt_listener_unref(listener->listener);
733 afb_api_dbus_server_origin_unref(listener->origin);
737 static struct listener *afb_api_dbus_server_listener_get(struct api_dbus *api, const char *sender, struct afb_session *session)
740 struct listener *listener;
741 struct origin *origin;
744 origin = afb_api_dbus_server_origin_get(api, sender);
748 /* retrieves the stored listener */
749 listener = afb_session_get_cookie(session, origin);
750 if (listener != NULL) {
752 afb_api_dbus_server_origin_unref(origin);
756 /* creates the listener */
757 listener = malloc(sizeof *listener);
758 if (listener == NULL)
761 listener->origin = origin;
762 listener->listener = afb_evt_listener_create(&evt_push_itf, origin);
763 if (listener->listener != NULL) {
764 rc = afb_session_set_cookie(session, origin, listener, (void*)afb_api_dbus_server_listener_free);
767 afb_evt_listener_unref(listener->listener);
771 afb_api_dbus_server_origin_unref(origin);
775 /******************* dbus request part for server *****************/
778 * Structure for a dbus request
781 struct afb_xreq xreq; /**< the xreq of the request */
782 sd_bus_message *message; /**< the incoming request message */
783 const char *request; /**< the readen request as string */
784 struct json_object *json; /**< the readen request as object */
785 struct listener *listener; /**< the listener for events */
788 /* decrement the reference count of the request and free/release it on falling to null */
789 static void dbus_req_destroy(struct afb_xreq *xreq)
791 struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
793 afb_context_disconnect(&dreq->xreq.context);
794 json_object_put(dreq->json);
795 sd_bus_message_unref(dreq->message);
799 /* get the object of the request */
800 static struct json_object *dbus_req_json(struct afb_xreq *xreq)
802 struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
807 void dbus_req_raw_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
809 struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
812 rc = sd_bus_reply_method_return(dreq->message, "sss",
813 obj ? json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN) : "",
817 ERROR("sending the reply failed");
820 static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid);
822 static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
824 struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
828 rc = afb_evt_event_x2_add_watch(dreq->listener->listener, event);
829 sd_bus_message_get_cookie(dreq->message, &msgid);
830 afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid);
834 static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
836 struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
840 sd_bus_message_get_cookie(dreq->message, &msgid);
841 afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid);
842 rc = afb_evt_event_x2_remove_watch(dreq->listener->listener, event);
846 const struct afb_xreq_query_itf afb_api_dbus_xreq_itf = {
847 .json = dbus_req_json,
848 .reply = dbus_req_raw_reply,
849 .unref = dbus_req_destroy,
850 .subscribe = dbus_req_subscribe,
851 .unsubscribe = dbus_req_unsubscribe,
854 /******************* server part **********************************/
856 static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid)
859 struct api_dbus *api;
860 struct sd_bus_message *msg;
865 rc = sd_bus_message_new_method_call(api->sdbus, &msg, origin->name, api->path, api->name, "event");
869 rc = sd_bus_message_append(msg, "yisst", (uint8_t)order, (int32_t)eventid, event, data, msgid);
873 rc = sd_bus_send(api->sdbus, msg, NULL); /* NULL for cookie implies no expected reply */
878 ERROR("error while send event %c%s(%d) to %s", order, event, eventid, origin->name);
880 sd_bus_message_unref(msg);
883 static void afb_api_dbus_server_event_add(void *closure, const char *event, int eventid)
885 afb_api_dbus_server_event_send(closure, '+', event, eventid, "", 0);
888 static void afb_api_dbus_server_event_remove(void *closure, const char *event, int eventid)
890 afb_api_dbus_server_event_send(closure, '-', event, eventid, "", 0);
893 static void afb_api_dbus_server_event_push(void *closure, const char *event, int eventid, struct json_object *object)
895 const char *data = json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN);
896 afb_api_dbus_server_event_send(closure, '!', event, eventid, data, 0);
897 json_object_put(object);
900 static void afb_api_dbus_server_event_broadcast(void *closure, const char *event, int eventid, struct json_object *object)
903 struct api_dbus *api;
906 rc = sd_bus_emit_signal(api->sdbus, api->path, api->name, "broadcast",
907 "ss", event, json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN));
909 ERROR("error while broadcasting event %s", event);
910 json_object_put(object);
913 /* called when the object for the service is called */
914 static int api_dbus_server_on_object_called(sd_bus_message *message, void *userdata, sd_bus_error *ret_error)
920 struct dbus_req *dreq;
921 struct api_dbus *api = userdata;
923 struct afb_session *session;
924 struct listener *listener;
926 /* check the interface */
927 if (strcmp(sd_bus_message_get_interface(message), api->name) != 0)
931 method = sd_bus_message_get_member(message);
933 /* create the request */
934 dreq = calloc(1 , sizeof *dreq);
939 rc = sd_bus_message_read(message, "ssus", &dreq->request, &uuid, &flags, &creds);
941 sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_SIGNATURE, "invalid signature");
945 /* connect to the context */
946 afb_xreq_init(&dreq->xreq, &afb_api_dbus_xreq_itf);
947 if (afb_context_connect(&dreq->xreq.context, uuid, NULL) < 0)
949 session = dreq->xreq.context.session;
951 /* get the listener */
952 listener = afb_api_dbus_server_listener_get(api, sd_bus_message_get_sender(message), session);
953 if (listener == NULL)
956 /* fulfill the request and emit it */
957 dreq->xreq.context.flags = flags;
958 dreq->xreq.cred = afb_cred_mixed_on_behalf_import(listener->origin->cred, uuid, creds && creds[0] ? creds : NULL);
959 dreq->message = sd_bus_message_ref(message);
960 dreq->json = json_tokener_parse(dreq->request);
961 if (dreq->json == NULL && strcmp(dreq->request, "null")) {
962 /* lazy error detection of json request. Is it to improve? */
963 dreq->json = json_object_new_string(dreq->request);
965 dreq->listener = listener;
966 dreq->xreq.request.called_api = api->api;
967 dreq->xreq.request.called_verb = method;
968 afb_xreq_process(&dreq->xreq, api->server.apiset);
972 sd_bus_reply_method_errorf(message, SD_BUS_ERROR_NO_MEMORY, "out of memory");
978 /* create the service */
979 int afb_api_dbus_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
982 struct api_dbus *api;
984 /* get the dbus api object connected */
985 api = make_api_dbus(path);
989 /* request the service object name */
990 rc = sd_bus_request_name(api->sdbus, api->name, 0);
993 ERROR("can't register name %s", api->name);
997 /* connect the service to the dbus object */
998 rc = sd_bus_add_object(api->sdbus, &api->server.slot_call, api->path, api_dbus_server_on_object_called, api);
1001 ERROR("can't add dbus object %s for %s", api->path, api->name);
1004 INFO("afb service over dbus installed, name %s, path %s", api->name, api->path);
1006 api->server.listener = afb_evt_listener_create(&evt_broadcast_itf, api);
1007 api->server.apiset = afb_apiset_addref(call_set);
1010 sd_bus_release_name(api->sdbus, api->name);
1012 destroy_api_dbus(api);