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