Fedora 30 packaging fix issu
[src/app-framework-binder.git] / src / afb-api-dbus.c
1 /*
2  * Copyright (C) 2015-2018 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #if defined(WITH_DBUS_TRANSPARENCY)
19
20 #define _GNU_SOURCE
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <errno.h>
27
28 #include <systemd/sd-bus.h>
29 #include <json-c/json.h>
30 #if !defined(JSON_C_TO_STRING_NOSLASHESCAPE)
31 #define JSON_C_TO_STRING_NOSLASHESCAPE 0
32 #endif
33
34 #include <afb/afb-event-x2.h>
35
36 #include "afb-systemd.h"
37
38 #include "afb-session.h"
39 #include "afb-msg-json.h"
40 #include "afb-api.h"
41 #include "afb-apiset.h"
42 #include "afb-api-dbus.h"
43 #include "afb-context.h"
44 #include "afb-cred.h"
45 #include "afb-evt.h"
46 #include "afb-xreq.h"
47 #include "verbose.h"
48
49
50 static const char DEFAULT_PATH_PREFIX[] = "/org/agl/afb/api/";
51
52 struct dbus_memo;
53 struct dbus_event;
54 struct origin;
55
56 /*
57  * The path given are of the form
58  *     system:/org/agl/afb/api/...
59  * or
60  *     user:/org/agl/afb/api/...
61  */
62 struct api_dbus
63 {
64         struct sd_bus *sdbus;   /* the bus */
65         char *path;             /* path of the object for the API */
66         char *name;             /* name/interface of the object */
67         char *api;              /* api name of the interface */
68         union {
69                 struct {
70                         struct sd_bus_slot *slot_broadcast;
71                         struct sd_bus_slot *slot_event;
72                         struct dbus_event *events;
73                         struct dbus_memo *memos;
74                 } client;
75                 struct {
76                         struct sd_bus_slot *slot_call;
77                         struct afb_evt_listener *listener; /* listener for broadcasted events */
78                         struct origin *origins;
79                         struct afb_apiset *apiset;
80                 } server;
81         };
82 };
83
84 /******************* common part **********************************/
85
86 /*
87  * create a structure api_dbus connected on either the system
88  * bus if 'system' is not null or on the user bus. The connection
89  * is established for either emiting/receiving on 'path' being of length
90  * 'pathlen'.
91  */
92 static struct api_dbus *make_api_dbus_3(int system, const char *path, size_t pathlen)
93 {
94         struct api_dbus *api;
95         struct sd_bus *sdbus;
96         char *ptr;
97
98         /* allocates the structure */
99         api = calloc(1, sizeof *api + 1 + pathlen + pathlen);
100         if (api == NULL) {
101                 errno = ENOMEM;
102                 goto error;
103         }
104
105         /* init the structure's strings */
106
107         /* path is copied after the struct */
108         api->path = (void*)(api+1);
109         strcpy(api->path, path);
110
111         /* api name is at the end of the path */
112         api->api = strrchr(api->path, '/');
113         if (api->api == NULL) {
114                 errno = EINVAL;
115                 goto error2;
116         }
117         api->api++;
118         if (!afb_api_is_valid_name(api->api)) {
119                 errno = EINVAL;
120                 goto error2;
121         }
122
123         /* the name/interface is copied after the path */
124         api->name = &api->path[pathlen + 1];
125         strcpy(api->name, &path[1]);
126         ptr = strchr(api->name, '/');
127         while(ptr != NULL) {
128                 *ptr = '.';
129                 ptr = strchr(ptr, '/');
130         }
131
132         /* choose the bus */
133         sdbus = (system ? afb_systemd_get_system_bus : afb_systemd_get_user_bus)();
134         if (sdbus == NULL)
135                 goto error2;
136
137         api->sdbus = sdbus;
138         return api;
139
140 error2:
141         free(api);
142 error:
143         return NULL;
144 }
145
146 /*
147  * create a structure api_dbus connected on either the system
148  * bus if 'system' is not null or on the user bus. The connection
149  * is established for either emiting/receiving on 'path'.
150  * If 'path' is not absolute, it is prefixed with DEFAULT_PATH_PREFIX.
151  */
152 static struct api_dbus *make_api_dbus_2(int system, const char *path)
153 {
154         size_t len;
155         char *ptr;
156
157         /* check the length of the path */
158         len = strlen(path);
159         if (len == 0) {
160                 errno = EINVAL;
161                 return NULL;
162         }
163
164         /* if the path is absolute, creation now */
165         if (path[0] == '/')
166                 return make_api_dbus_3(system, path, len);
167
168         /* compute the path prefixed with DEFAULT_PATH_PREFIX */
169         assert(strlen(DEFAULT_PATH_PREFIX) > 0);
170         assert(DEFAULT_PATH_PREFIX[strlen(DEFAULT_PATH_PREFIX) - 1] == '/');
171         len += strlen(DEFAULT_PATH_PREFIX);
172         ptr = alloca(len + 1);
173         strcpy(stpcpy(ptr, DEFAULT_PATH_PREFIX), path);
174
175         /* creation for prefixed path */
176         return make_api_dbus_3(system, ptr, len);
177 }
178
179 /*
180  * create a structure api_dbus connected either emiting/receiving
181  * on 'path'.
182  * The path can be prefixed with "system:" or "user:" to select
183  * either the user or the system D-Bus. If none is set then user's
184  * bus is selected.
185  * If remaining 'path' is not absolute, it is prefixed with
186  * DEFAULT_PATH_PREFIX.
187  */
188 static struct api_dbus *make_api_dbus(const char *path)
189 {
190         const char *ptr;
191         size_t preflen;
192
193         /* retrieves the prefix "scheme-like" part */
194         ptr = strchr(path, ':');
195         if (ptr == NULL)
196                 return make_api_dbus_2(0, path);
197
198         /* check the prefix part */
199         preflen = (size_t)(ptr - path);
200         if (strncmp(path, "system", preflen) == 0)
201                 return make_api_dbus_2(1, ptr + 1);
202
203         if (strncmp(path, "user", preflen) == 0)
204                 return make_api_dbus_2(0, ptr + 1);
205
206         /* TODO: connect to a foreign D-Bus? */
207         errno = EINVAL;
208         return NULL;
209 }
210
211 static void destroy_api_dbus(struct api_dbus *api)
212 {
213         free(api);
214 }
215
216 /******************* client part **********************************/
217
218 /*
219  * structure for recording query data
220  */
221 struct dbus_memo {
222         struct dbus_memo *next;         /* the next memo */
223         struct api_dbus *api;           /* the dbus api */
224         struct afb_xreq *xreq;          /* the request */
225         uint64_t msgid;                 /* the message identifier */
226 };
227
228 struct dbus_event
229 {
230         struct dbus_event *next;
231         struct afb_event_x2 *event;
232         int id;
233         int refcount;
234 };
235
236 /* allocates and init the memorizing data */
237 static struct dbus_memo *api_dbus_client_memo_make(struct api_dbus *api, struct afb_xreq *xreq)
238 {
239         struct dbus_memo *memo;
240
241         memo = malloc(sizeof *memo);
242         if (memo != NULL) {
243                 afb_xreq_unhooked_addref(xreq);
244                 memo->xreq = xreq;
245                 memo->msgid = 0;
246                 memo->api = api;
247                 memo->next = api->client.memos;
248                 api->client.memos = memo;
249         }
250         return memo;
251 }
252
253 /* free and release the memorizing data */
254 static void api_dbus_client_memo_destroy(struct dbus_memo *memo)
255 {
256         struct dbus_memo **prv;
257
258         prv = &memo->api->client.memos;
259         while (*prv != NULL) {
260                 if (*prv == memo) {
261                         *prv = memo->next;
262                         break;
263                 }
264                 prv = &(*prv)->next;
265         }
266
267         afb_xreq_unhooked_unref(memo->xreq);
268         free(memo);
269 }
270
271 /* search a memorized request */
272 static struct dbus_memo *api_dbus_client_memo_search(struct api_dbus *api, uint64_t msgid)
273 {
274         struct dbus_memo *memo;
275
276         memo = api->client.memos;
277         while (memo != NULL && memo->msgid != msgid)
278                 memo = memo->next;
279
280         return memo;
281 }
282
283 /* callback when received answer */
284 static int api_dbus_client_on_reply(sd_bus_message *message, void *userdata, sd_bus_error *ret_error)
285 {
286         int rc;
287         struct dbus_memo *memo;
288         const char *json, *error, *info;
289         struct json_object *object;
290         enum json_tokener_error jerr;
291
292         /* retrieve the recorded data */
293         memo = userdata;
294
295         /* get the answer */
296         rc = sd_bus_message_read(message, "sss", &json, &error, &info);
297         if (rc < 0) {
298                 /* failing to have the answer */
299                 afb_xreq_reply(memo->xreq, NULL, "error", "dbus error");
300         } else {
301                 /* report the answer */
302                 if (!*json)
303                         object = NULL;
304                 else {
305                         object = json_tokener_parse_verbose(json, &jerr);
306                         if (jerr != json_tokener_success)
307                                 object = json_object_new_string(json);
308                 }
309                 afb_xreq_reply(memo->xreq, object, *error ? error : NULL, *info ? info : NULL);
310         }
311         api_dbus_client_memo_destroy(memo);
312         return 1;
313 }
314
315 /* on call, propagate it to the dbus service */
316 static void api_dbus_client_call(void *closure, struct afb_xreq *xreq)
317 {
318         struct api_dbus *api = closure;
319         size_t size;
320         int rc;
321         struct dbus_memo *memo;
322         struct sd_bus_message *msg;
323         const char *creds;
324
325         /* create the recording data */
326         memo = api_dbus_client_memo_make(api, xreq);
327         if (memo == NULL) {
328                 afb_xreq_reply(memo->xreq, NULL, "error", "out of memory");
329                 return;
330         }
331
332         /* creates the message */
333         msg = NULL;
334         rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.called_verb);
335         if (rc < 0)
336                 goto error;
337
338         creds = xreq_on_behalf_cred_export(xreq);
339         rc = sd_bus_message_append(msg, "ssus",
340                         afb_xreq_raw(xreq, &size),
341                         afb_session_uuid(xreq->context.session),
342                         (uint32_t)xreq->context.flags,
343                         creds ?: "");
344         if (rc < 0)
345                 goto error;
346
347         /* makes the call */
348         rc = sd_bus_call_async(api->sdbus, NULL, msg, api_dbus_client_on_reply, memo, (uint64_t)-1);
349         if (rc < 0)
350                 goto error;
351
352         rc = sd_bus_message_get_cookie(msg, &memo->msgid);
353         if (rc >= 0)
354                 goto end;
355
356 error:
357         /* if there was an error report it directly */
358         errno = -rc;
359         afb_xreq_reply(memo->xreq, NULL, "error", "dbus error");
360         api_dbus_client_memo_destroy(memo);
361 end:
362         sd_bus_message_unref(msg);
363 }
364
365 /* receives broadcasted events */
366 static int api_dbus_client_on_broadcast_event(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
367 {
368         struct json_object *object;
369         const char *event, *data;
370         enum json_tokener_error jerr;
371         int rc = sd_bus_message_read(m, "ss", &event, &data);
372         if (rc < 0)
373                 ERROR("unreadable broadcasted event");
374         else {
375                 object = json_tokener_parse_verbose(data, &jerr);
376                 if (jerr != json_tokener_success)
377                         object = json_object_new_string(data);
378                 afb_evt_broadcast(event, object);
379         }
380         return 1;
381 }
382
383 /* search the eventid */
384 static struct dbus_event *api_dbus_client_event_search(struct api_dbus *api, int id, const char *name)
385 {
386         struct dbus_event *ev;
387
388         ev = api->client.events;
389         while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name)))
390                 ev = ev->next;
391
392         return ev;
393 }
394
395 /* adds an eventid */
396 static void api_dbus_client_event_create(struct api_dbus *api, int id, const char *name)
397 {
398         struct dbus_event *ev;
399
400         /* check conflicts */
401         ev = api_dbus_client_event_search(api, id, name);
402         if (ev != NULL) {
403                 ev->refcount++;
404                 return;
405         }
406
407         /* no conflict, try to add it */
408         ev = malloc(sizeof *ev);
409         if (ev != NULL) {
410                 ev->event = afb_evt_event_x2_create(name);
411                 if (ev->event == NULL)
412                         free(ev);
413                 else {
414                         ev->refcount = 1;
415                         ev->id = id;
416                         ev->next = api->client.events;
417                         api->client.events = ev;
418                         return;
419                 }
420         }
421         ERROR("can't create event %s, out of memory", name);
422 }
423
424 /* removes an eventid */
425 static void api_dbus_client_event_drop(struct api_dbus *api, int id, const char *name)
426 {
427         struct dbus_event *ev, **prv;
428
429         /* retrieves the event */
430         ev = api_dbus_client_event_search(api, id, name);
431         if (ev == NULL) {
432                 ERROR("event %s not found", name);
433                 return;
434         }
435
436         /* decrease the reference count */
437         if (--ev->refcount)
438                 return;
439
440         /* unlinks the event */
441         prv = &api->client.events;
442         while (*prv != ev)
443                 prv = &(*prv)->next;
444         *prv = ev->next;
445
446         /* destroys the event */
447         afb_evt_event_x2_unref(ev->event);
448         free(ev);
449 }
450
451 /* pushs an event */
452 static void api_dbus_client_event_push(struct api_dbus *api, int id, const char *name, const char *data)
453 {
454         struct json_object *object;
455         struct dbus_event *ev;
456         enum json_tokener_error jerr;
457
458         /* retrieves the event */
459         ev = api_dbus_client_event_search(api, id, name);
460         if (ev == NULL) {
461                 ERROR("event %s not found", name);
462                 return;
463         }
464
465         /* destroys the event */
466         object = json_tokener_parse_verbose(data, &jerr);
467         if (jerr != json_tokener_success)
468                 object = json_object_new_string(data);
469         afb_evt_event_x2_push(ev->event, object);
470 }
471
472 /* subscribes an event */
473 static void api_dbus_client_event_subscribe(struct api_dbus *api, int id, const char *name, uint64_t msgid)
474 {
475         int rc;
476         struct dbus_event *ev;
477         struct dbus_memo *memo;
478
479         /* retrieves the event */
480         ev = api_dbus_client_event_search(api, id, name);
481         if (ev == NULL) {
482                 ERROR("event %s not found", name);
483                 return;
484         }
485
486         /* retrieves the memo */
487         memo = api_dbus_client_memo_search(api, msgid);
488         if (memo == NULL) {
489                 ERROR("message not found");
490                 return;
491         }
492
493         /* subscribe the request to the event */
494         rc = afb_xreq_subscribe(memo->xreq, ev->event);
495         if (rc < 0)
496                 ERROR("can't subscribe: %m");
497 }
498
499 /* unsubscribes an event */
500 static void api_dbus_client_event_unsubscribe(struct api_dbus *api, int id, const char *name, uint64_t msgid)
501 {
502         int rc;
503         struct dbus_event *ev;
504         struct dbus_memo *memo;
505
506         /* retrieves the event */
507         ev = api_dbus_client_event_search(api, id, name);
508         if (ev == NULL) {
509                 ERROR("event %s not found", name);
510                 return;
511         }
512
513         /* retrieves the memo */
514         memo = api_dbus_client_memo_search(api, msgid);
515         if (memo == NULL) {
516                 ERROR("message not found");
517                 return;
518         }
519
520         /* unsubscribe the request from the event */
521         rc = afb_xreq_unsubscribe(memo->xreq, ev->event);
522         if (rc < 0)
523                 ERROR("can't unsubscribe: %m");
524 }
525
526 /* receives calls for event */
527 static int api_dbus_client_on_manage_event(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
528 {
529         const char *eventname, *data;
530         int rc;
531         int32_t eventid;
532         uint8_t order;
533         struct api_dbus *api;
534         uint64_t msgid;
535
536         /* check if expected message */
537         api = userdata;
538         if (0 != strcmp(api->name, sd_bus_message_get_interface(m)))
539                 return 0; /* not the expected interface */
540         if (0 != strcmp("event", sd_bus_message_get_member(m)))
541                 return 0; /* not the expected member */
542         if (sd_bus_message_get_expect_reply(m))
543                 return 0; /* not the expected type of message */
544
545         /* reads the message */
546         rc = sd_bus_message_read(m, "yisst", &order, &eventid, &eventname, &data, &msgid);
547         if (rc < 0) {
548                 ERROR("unreadable event");
549                 return 1;
550         }
551
552         /* what is the order ? */
553         switch ((char)order) {
554         case '+': /* creates the event */
555                 api_dbus_client_event_create(api, eventid, eventname);
556                 break;
557         case '-': /* drops the event */
558                 api_dbus_client_event_drop(api, eventid, eventname);
559                 break;
560         case '!': /* pushs the event */
561                 api_dbus_client_event_push(api, eventid, eventname, data);
562                 break;
563         case 'S': /* subscribe event for a request */
564                 api_dbus_client_event_subscribe(api, eventid, eventname, msgid);
565                 break;
566         case 'U': /* unsubscribe event for a request */
567                 api_dbus_client_event_unsubscribe(api, eventid, eventname, msgid);
568                 break;
569         default:
570                 /* unexpected order */
571                 ERROR("unexpected order '%c' received", (char)order);
572                 break;
573         }
574         return 1;
575 }
576
577 static struct afb_api_itf dbus_api_itf = {
578         .call = api_dbus_client_call
579 };
580
581 /* adds a afb-dbus-service client api */
582 int afb_api_dbus_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
583 {
584         int rc;
585         struct api_dbus *api;
586         struct afb_api_item afb_api;
587         char *match;
588
589         /* create the dbus client api */
590         api = make_api_dbus(path);
591         if (api == NULL)
592                 goto error;
593
594         /* connect to broadcasted events */
595         rc = asprintf(&match, "type='signal',path='%s',interface='%s',member='broadcast'", api->path, api->name);
596         if (rc < 0) {
597                 errno = ENOMEM;
598                 ERROR("out of memory");
599                 goto error;
600         }
601         rc = sd_bus_add_match(api->sdbus, &api->client.slot_broadcast, match, api_dbus_client_on_broadcast_event, api);
602         free(match);
603         if (rc < 0) {
604                 errno = -rc;
605                 ERROR("can't add dbus match %s for %s", api->path, api->name);
606                 goto error;
607         }
608
609         /* connect to event management */
610         rc = sd_bus_add_object(api->sdbus, &api->client.slot_event, api->path, api_dbus_client_on_manage_event, api);
611         if (rc < 0) {
612                 errno = -rc;
613                 ERROR("can't add dbus object %s for %s", api->path, api->name);
614                 goto error;
615         }
616
617         /* record it as an API */
618         afb_api.closure = api;
619         afb_api.itf = &dbus_api_itf;
620         afb_api.group = NULL;
621         if (afb_apiset_add(declare_set, api->api, afb_api) < 0)
622                 goto error2;
623
624         return 0;
625
626 error2:
627         destroy_api_dbus(api);
628 error:
629         return -1;
630 }
631
632 /******************* event structures for server part **********************************/
633
634 static void afb_api_dbus_server_event_add(void *closure, const char *event, int eventid);
635 static void afb_api_dbus_server_event_remove(void *closure, const char *event, int eventid);
636 static void afb_api_dbus_server_event_push(void *closure, const char *event, int eventid, struct json_object *object);
637 static void afb_api_dbus_server_event_broadcast(void *closure, const char *event, int eventid, struct json_object *object);
638
639 /* the interface for events broadcasting */
640 static const struct afb_evt_itf evt_broadcast_itf = {
641         .broadcast = afb_api_dbus_server_event_broadcast,
642 };
643
644 /* the interface for events pushing */
645 static const struct afb_evt_itf evt_push_itf = {
646         .push = afb_api_dbus_server_event_push,
647         .add = afb_api_dbus_server_event_add,
648         .remove = afb_api_dbus_server_event_remove
649 };
650
651 /******************* origin description part for server *****************************/
652
653 struct origin
654 {
655         /* link to next different origin */
656         struct origin *next;
657
658         /* the server dbus-api */
659         struct api_dbus *api;
660
661         /* count of references */
662         int refcount;
663
664         /* credentials of the origin */
665         struct afb_cred *cred;
666
667         /* the origin */
668         char name[];
669 };
670
671 /* get the credentials for the message */
672 static void init_origin_creds(struct origin *origin)
673 {
674         int rc;
675         sd_bus_creds *c;
676         uid_t uid;
677         gid_t gid;
678         pid_t pid;
679         const char *context;
680
681         rc = sd_bus_get_name_creds(origin->api->sdbus, origin->name,
682                         SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT,
683                         &c);
684         if (rc < 0)
685                 origin->cred = NULL;
686         else {
687                 afb_cred_unref(origin->cred);
688                 sd_bus_creds_get_uid(c, &uid);
689                 sd_bus_creds_get_gid(c, &gid);
690                 sd_bus_creds_get_pid(c, &pid);
691                 sd_bus_creds_get_selinux_context(c, &context);
692                 origin->cred = afb_cred_create(uid, gid, pid, context);
693                 sd_bus_creds_unref(c);
694         }
695 }
696
697 static struct origin *afb_api_dbus_server_origin_get(struct api_dbus *api, const char *sender)
698 {
699         struct origin *origin;
700
701         /* searchs for an existing origin */
702         origin = api->server.origins;
703         while (origin != NULL) {
704                 if (0 == strcmp(origin->name, sender)) {
705                         origin->refcount++;
706                         return origin;
707                 }
708                 origin = origin->next;
709         }
710
711         /* not found, create it */
712         origin = malloc(strlen(sender) + 1 + sizeof *origin);
713         if (origin == NULL)
714                 errno = ENOMEM;
715         else {
716                 origin->api = api;
717                 origin->refcount = 1;
718                 strcpy(origin->name, sender);
719                 init_origin_creds(origin);
720                 origin->next = api->server.origins;
721                 api->server.origins = origin;
722         }
723         return origin;
724 }
725
726 static void afb_api_dbus_server_origin_unref(struct origin *origin)
727 {
728         if (!--origin->refcount) {
729                 struct origin **prv;
730
731                 prv = &origin->api->server.origins;
732                 while(*prv != origin)
733                         prv = &(*prv)->next;
734                 *prv = origin->next;
735                 afb_cred_unref(origin->cred);
736                 free(origin);
737         }
738 }
739
740 struct listener
741 {
742         /* link to next different origin */
743         struct origin *origin;
744
745         /* the listener of events */
746         struct afb_evt_listener *listener;
747 };
748
749 static void afb_api_dbus_server_listener_free(struct listener *listener)
750 {
751         afb_evt_listener_unref(listener->listener);
752         afb_api_dbus_server_origin_unref(listener->origin);
753         free(listener);
754 }
755
756 static struct listener *afb_api_dbus_server_listener_get(struct api_dbus *api, const char *sender, struct afb_session *session)
757 {
758         int rc;
759         struct listener *listener;
760         struct origin *origin;
761
762         /* get the origin */
763         origin = afb_api_dbus_server_origin_get(api, sender);
764         if (origin == NULL)
765                 return NULL;
766
767         /* retrieves the stored listener */
768         listener = afb_session_get_cookie(session, origin);
769         if (listener != NULL) {
770                 /* found */
771                 afb_api_dbus_server_origin_unref(origin);
772                 return listener;
773         }
774
775         /* creates the listener */
776         listener = malloc(sizeof *listener);
777         if (listener == NULL)
778                 errno = ENOMEM;
779         else {
780                 listener->origin = origin;
781                 listener->listener = afb_evt_listener_create(&evt_push_itf, origin);
782                 if (listener->listener != NULL) {
783                         rc = afb_session_set_cookie(session, origin, listener, (void*)afb_api_dbus_server_listener_free);
784                         if (rc == 0)
785                                 return listener;
786                         afb_evt_listener_unref(listener->listener);
787                 }
788                 free(listener);
789         }
790         afb_api_dbus_server_origin_unref(origin);
791         return NULL;
792 }
793
794 /******************* dbus request part for server *****************/
795
796 /**
797  * Structure for a dbus request
798  */
799 struct dbus_req {
800         struct afb_xreq xreq;           /**< the xreq of the request */
801         sd_bus_message *message;        /**< the incoming request message */
802         const char *request;            /**< the readen request as string */
803         struct json_object *json;       /**< the readen request as object */
804         struct listener *listener;      /**< the listener for events */
805 };
806
807 /* decrement the reference count of the request and free/release it on falling to null */
808 static void dbus_req_destroy(struct afb_xreq *xreq)
809 {
810         struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
811
812         afb_context_disconnect(&dreq->xreq.context);
813         json_object_put(dreq->json);
814         sd_bus_message_unref(dreq->message);
815         free(dreq);
816 }
817
818 /* get the object of the request */
819 static struct json_object *dbus_req_json(struct afb_xreq *xreq)
820 {
821         struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
822
823         return dreq->json;
824 }
825
826 void dbus_req_raw_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
827 {
828         struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
829         int rc;
830
831         rc = sd_bus_reply_method_return(dreq->message, "sss",
832                 obj ? json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN|JSON_C_TO_STRING_NOSLASHESCAPE) : "",
833                 error ? : "",
834                 info ? : "");
835         if (rc < 0)
836                 ERROR("sending the reply failed");
837 }
838
839 static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid);
840
841 static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
842 {
843         struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
844         uint64_t msgid;
845         int rc;
846
847         rc = afb_evt_event_x2_add_watch(dreq->listener->listener, event);
848         sd_bus_message_get_cookie(dreq->message, &msgid);
849         afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid);
850         return rc;
851 }
852
853 static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event)
854 {
855         struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
856         uint64_t msgid;
857         int rc;
858
859         sd_bus_message_get_cookie(dreq->message, &msgid);
860         afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid);
861         rc = afb_evt_event_x2_remove_watch(dreq->listener->listener, event);
862         return rc;
863 }
864
865 const struct afb_xreq_query_itf afb_api_dbus_xreq_itf = {
866         .json = dbus_req_json,
867         .reply = dbus_req_raw_reply,
868         .unref = dbus_req_destroy,
869         .subscribe = dbus_req_subscribe,
870         .unsubscribe = dbus_req_unsubscribe,
871 };
872
873 /******************* server part **********************************/
874
875 static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid)
876 {
877         int rc;
878         struct api_dbus *api;
879         struct sd_bus_message *msg;
880
881         api = origin->api;
882         msg = NULL;
883
884         rc = sd_bus_message_new_method_call(api->sdbus, &msg, origin->name, api->path, api->name, "event");
885         if (rc < 0)
886                 goto error;
887
888         rc = sd_bus_message_append(msg, "yisst", (uint8_t)order, (int32_t)eventid, event, data, msgid);
889         if (rc < 0)
890                 goto error;
891
892         rc = sd_bus_send(api->sdbus, msg, NULL); /* NULL for cookie implies no expected reply */
893         if (rc >= 0)
894                 goto end;
895
896 error:
897         ERROR("error while send event %c%s(%d) to %s", order, event, eventid, origin->name);
898 end:
899         sd_bus_message_unref(msg);
900 }
901
902 static void afb_api_dbus_server_event_add(void *closure, const char *event, int eventid)
903 {
904         afb_api_dbus_server_event_send(closure, '+', event, eventid, "", 0);
905 }
906
907 static void afb_api_dbus_server_event_remove(void *closure, const char *event, int eventid)
908 {
909         afb_api_dbus_server_event_send(closure, '-', event, eventid, "", 0);
910 }
911
912 static void afb_api_dbus_server_event_push(void *closure, const char *event, int eventid, struct json_object *object)
913 {
914         const char *data = json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN|JSON_C_TO_STRING_NOSLASHESCAPE);
915         afb_api_dbus_server_event_send(closure, '!', event, eventid, data, 0);
916         json_object_put(object);
917 }
918
919 static void afb_api_dbus_server_event_broadcast(void *closure, const char *event, int eventid, struct json_object *object)
920 {
921         int rc;
922         struct api_dbus *api;
923
924         api = closure;
925         rc = sd_bus_emit_signal(api->sdbus, api->path, api->name, "broadcast",
926                         "ss", event, json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN|JSON_C_TO_STRING_NOSLASHESCAPE));
927         if (rc < 0)
928                 ERROR("error while broadcasting event %s", event);
929         json_object_put(object);
930 }
931
932 /* called when the object for the service is called */
933 static int api_dbus_server_on_object_called(sd_bus_message *message, void *userdata, sd_bus_error *ret_error)
934 {
935         int rc;
936         const char *method;
937         const char *uuid;
938         const char *creds;
939         struct dbus_req *dreq;
940         struct api_dbus *api = userdata;
941         uint32_t flags;
942         struct afb_session *session;
943         struct listener *listener;
944         enum json_tokener_error jerr;
945
946         /* check the interface */
947         if (strcmp(sd_bus_message_get_interface(message), api->name) != 0)
948                 return 0;
949
950         /* get the method */
951         method = sd_bus_message_get_member(message);
952
953         /* create the request */
954         dreq = calloc(1 , sizeof *dreq);
955         if (dreq == NULL)
956                 goto out_of_memory;
957
958         /* get the data */
959         rc = sd_bus_message_read(message, "ssus", &dreq->request, &uuid, &flags, &creds);
960         if (rc < 0) {
961                 sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_SIGNATURE, "invalid signature");
962                 goto error;
963         }
964
965         /* connect to the context */
966         afb_xreq_init(&dreq->xreq, &afb_api_dbus_xreq_itf);
967         if (afb_context_connect(&dreq->xreq.context, uuid, NULL) < 0)
968                 goto out_of_memory;
969         session = dreq->xreq.context.session;
970
971         /* get the listener */
972         listener = afb_api_dbus_server_listener_get(api, sd_bus_message_get_sender(message), session);
973         if (listener == NULL)
974                 goto out_of_memory;
975
976         /* fulfill the request and emit it */
977         dreq->xreq.context.flags = flags;
978         dreq->xreq.cred = afb_cred_mixed_on_behalf_import(listener->origin->cred, uuid, creds && creds[0] ? creds : NULL);
979         dreq->message = sd_bus_message_ref(message);
980         dreq->json = json_tokener_parse_verbose(dreq->request, &jerr);
981         if (jerr != json_tokener_success) {
982                 /* lazy error detection of json request. Is it to improve? */
983                 dreq->json = json_object_new_string(dreq->request);
984         }
985         dreq->listener = listener;
986         dreq->xreq.request.called_api = api->api;
987         dreq->xreq.request.called_verb = method;
988         afb_xreq_process(&dreq->xreq, api->server.apiset);
989         return 1;
990
991 out_of_memory:
992         sd_bus_reply_method_errorf(message, SD_BUS_ERROR_NO_MEMORY, "out of memory");
993 error:
994         free(dreq);
995         return 1;
996 }
997
998 /* create the service */
999 int afb_api_dbus_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)
1000 {
1001         int rc;
1002         struct api_dbus *api;
1003
1004         /* get the dbus api object connected */
1005         api = make_api_dbus(path);
1006         if (api == NULL)
1007                 goto error;
1008
1009         /* request the service object name */
1010         rc = sd_bus_request_name(api->sdbus, api->name, 0);
1011         if (rc < 0) {
1012                 errno = -rc;
1013                 ERROR("can't register name %s", api->name);
1014                 goto error2;
1015         }
1016
1017         /* connect the service to the dbus object */
1018         rc = sd_bus_add_object(api->sdbus, &api->server.slot_call, api->path, api_dbus_server_on_object_called, api);
1019         if (rc < 0) {
1020                 errno = -rc;
1021                 ERROR("can't add dbus object %s for %s", api->path, api->name);
1022                 goto error3;
1023         }
1024         INFO("afb service over dbus installed, name %s, path %s", api->name, api->path);
1025
1026         api->server.listener = afb_evt_listener_create(&evt_broadcast_itf, api);
1027         api->server.apiset = afb_apiset_addref(call_set);
1028         return 0;
1029 error3:
1030         sd_bus_release_name(api->sdbus, api->name);
1031 error2:
1032         destroy_api_dbus(api);
1033 error:
1034         return -1;
1035 }
1036
1037 #endif
1038