c4146a4697d388ef949251129604220f9226f581
[src/app-framework-binder.git] / plugins / afm-main-plugin / utils-jbus.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <poll.h>
25 #include <assert.h>
26
27 #include <json-c/json.h>
28 #include <systemd/sd-bus.h>
29 #include <systemd/sd-bus-protocol.h>
30
31 #include "utils-jbus.h"
32
33 /*
34  * max depth of json messages
35  */
36 #define MAX_JSON_DEPTH 10
37
38 /*
39  * errors messages generated by jbus
40  */
41 static const char out_of_memory_string[] = "out of memory";
42
43 /*
44  * structure for services
45  */
46 struct jservice {
47         struct jservice *next;  /* link to the next service */
48         char *method;           /* method name for the service */
49         void (*oncall_s) (struct sd_bus_message *, const char *, void *);
50                                 /* string callback */
51         void (*oncall_j) (struct sd_bus_message *, struct json_object *, void *);
52                                 /* json callback */
53         void *data;             /* closure data for the callbacks */
54 };
55
56 /*
57  * structure for signals
58  */
59 struct jsignal {
60         struct jsignal *next;   /* link to the next signal */
61         char *name;             /* name of the expected signal */
62         void (*onsignal_s) (const char *, void *);
63                                 /* string callback */
64         void (*onsignal_j) (struct json_object *, void *);
65                                 /* json callback */
66         void *data;             /* closure data for the callbacks */
67 };
68
69 /*
70  * structure for asynchronous requests
71  */
72 struct jrespw {
73         struct jbus *jbus;
74         void (*onresp_s) (int, const char *, void *);
75                                 /* string callback */
76         void (*onresp_j) (int, struct json_object *, void *);
77                                 /* json callback */
78         void *data;             /* closure data for the callbacks */
79 };
80
81 /*
82  * structure for handling either client or server jbus on dbus
83  */
84 struct jbus {
85         int refcount;                   /* referenced how many time */
86         struct sd_bus *sdbus;
87         struct sd_bus_slot *sservice;
88         struct sd_bus_slot *ssignal;
89         struct json_tokener *tokener;   /* string to json tokenizer */
90         struct jservice *services;      /* first service */
91         struct jsignal *signals;        /* first signal */
92         char *path;                     /* dbus path */
93         char *name;                     /* dbus name */
94 };
95
96 /*********************** STATIC COMMON METHODS *****************/
97
98 static int mkerrno(int rc)
99 {
100         if (rc >= 0)
101                 return rc;
102         errno = -rc;
103         return -1;
104 }
105
106 /*
107  * Replies the error "out of memory".
108  * This function is intended to be used in services when an
109  * allocation fails. Thus, it set errno to ENOMEM and
110  * returns -1.
111  */
112 static inline int reply_out_of_memory(struct sd_bus_message *smsg)
113 {
114         jbus_reply_error_s(smsg, out_of_memory_string);
115         errno = ENOMEM;
116         return -1;
117 }
118
119 /*
120  * Parses the json-string 'msg' to create a json object stored
121  * in 'obj'. It uses the tokener of 'jbus'. This is a small
122  * improvement to avoid recreation of tokeners.
123  *
124  * Returns 1 in case of success and put the result in *'obj'.
125  * Returns 0 in case of error and put NULL in *'obj'.
126  */
127 static int jparse(struct jbus *jbus, const char *msg, struct json_object **obj)
128 {
129         json_tokener_reset(jbus->tokener);
130         *obj = json_tokener_parse_ex(jbus->tokener, msg, -1);
131         if (json_tokener_get_error(jbus->tokener) == json_tokener_success)
132                 return 1;
133         json_object_put(*obj);
134         *obj = NULL;
135         return 0;
136 }
137
138 static int on_service_call(struct sd_bus_message *smsg, struct jbus *jbus, sd_bus_error *error)
139 {
140         struct jservice *service;
141         const char *member, *content;
142         struct json_object *obj;
143
144         /* check the type */
145         if (!sd_bus_message_has_signature(smsg, "s")
146           || sd_bus_message_read_basic(smsg, 's', &content) < 0) {
147                 sd_bus_error_set_const(error, "bad signature", "");
148                 return 1;
149         }
150
151         /* dispatch */
152         member = sd_bus_message_get_member(smsg);
153         service = jbus->services;
154         while (service != NULL) {
155                 if (!strcmp(service->method, member)) {
156                         if (service->oncall_s)
157                                 service->oncall_s(smsg, content, service->data);
158                         else if (service->oncall_j) {
159                                 if (!jparse(jbus, content, &obj))
160                                         obj = json_object_new_string(content);
161                                 service->oncall_j(smsg, obj, service->data);
162                                 json_object_put(obj);
163                         }
164                         return 1;
165                 }
166                 service = service->next;
167         }
168         return 0;
169 }
170
171 /*
172  * Adds to 'jbus' a service of name 'method'. The service is
173  * performed by one of the callback 'oncall_s' (for string) or
174  * 'oncall_j' (for json) that will receive the request and the
175  * closure parameter 'data'.
176  *
177  * returns 0 in case of success or -1 in case of error (ENOMEM).
178  */
179 static int add_service(
180                 struct jbus *jbus,
181                 const char *method,
182                 void (*oncall_s) (struct sd_bus_message *, const char *, void *),
183                 void (*oncall_j) (struct sd_bus_message *, struct json_object *, void *),
184                 void *data)
185 {
186         int rc;
187         struct jservice *srv;
188
189         /* connection of the service */
190         if (jbus->sservice == NULL) {
191                 rc = sd_bus_add_object(jbus->sdbus, &jbus->sservice, jbus->path, (void*)on_service_call, jbus);
192                 if (rc < 0) {
193                         errno = -rc;
194                         goto error;
195                 }
196         }
197
198         /* allocation */
199         srv = malloc(sizeof *srv);
200         if (srv == NULL) {
201                 errno = ENOMEM;
202                 goto error;
203         }
204         srv->method = strdup(method);
205         if (!srv->method) {
206                 errno = ENOMEM;
207                 goto error2;
208         }
209
210         /* record the service */
211         srv->oncall_s = oncall_s;
212         srv->oncall_j = oncall_j;
213         srv->data = data;
214         srv->next = jbus->services;
215         jbus->services = srv;
216
217         return 0;
218
219  error2:
220         free(srv);
221  error:
222         return -1;
223 }
224
225 static int on_signal_event(struct sd_bus_message *smsg, struct jbus *jbus, sd_bus_error *error)
226 {
227         struct jsignal *signal;
228         const char *member, *content;
229         struct json_object *obj;
230
231         /* check the type */
232         if (!sd_bus_message_has_signature(smsg, "s")
233           || sd_bus_message_read_basic(smsg, 's', &content) < 0)
234                 return 0;
235
236         /* dispatch */
237         member = sd_bus_message_get_member(smsg);
238         signal = jbus->signals;
239         while (signal != NULL) {
240                 if (!strcmp(signal->name, member)) {
241                         if (signal->onsignal_s)
242                                 signal->onsignal_s(content, signal->data);
243                         else if (signal->onsignal_j) {
244                                 if (!jparse(jbus, content, &obj))
245                                         obj = json_object_new_string(content);
246                                 signal->onsignal_j(obj, signal->data);
247                                 json_object_put(obj);
248                         }
249                 }
250                 signal = signal->next;
251         }
252         return 0;
253 }
254
255 /*
256  * Adds to 'jbus' a handler for the signal of 'name' emmited by
257  * the sender and the interface that 'jbus' is linked to.
258  * The signal is handled by one of the callback 'onsignal_s'
259  * (for string) or 'onsignal_j' (for json) that will receive
260  * parameters associated with the signal and the closure
261  * parameter 'data'.
262  *
263  * returns 0 in case of success or -1 in case of error (ENOMEM).
264  */
265 static int add_signal(
266                 struct jbus *jbus,
267                 const char *name,
268                 void (*onsignal_s) (const char *, void *),
269                 void (*onsignal_j) (struct json_object *, void *),
270                 void *data)
271 {
272         int rc;
273         struct jsignal *sig;
274         char *match;
275
276         /* connection of the signal */
277         if (jbus->ssignal == NULL) {
278                 rc = asprintf(&match, "type='signal',path='%s',interface='%s'", jbus->path, jbus->name);
279                 if (rc < 0) {
280                         errno = ENOMEM;
281                         goto error;
282                 }
283                 rc = sd_bus_add_match(jbus->sdbus, &jbus->ssignal, match, (void*)on_signal_event, jbus);
284                 free(match);
285                 if (rc < 0) {
286                         errno = -rc;
287                         goto error;
288                 }
289         }
290
291         /* allocation */
292         sig = malloc(sizeof *sig);
293         if (sig == NULL) {
294                 errno = ENOMEM;
295                 goto error;
296         }
297         sig->name = strdup(name);
298         if (!sig->name) {
299                 errno = ENOMEM;
300                 goto error2;
301         }
302
303         /* record the signal */
304         sig->onsignal_s = onsignal_s;
305         sig->onsignal_j = onsignal_j;
306         sig->data = data;
307         sig->next = jbus->signals;
308         jbus->signals = sig;
309
310         return 0;
311
312  error2:
313         free(sig);
314  error:
315         return -1;
316 }
317
318 static int on_reply(struct sd_bus_message *smsg, struct jrespw *jrespw, sd_bus_error *error)
319 {
320         struct json_object *obj;
321         const char *reply;
322         int iserror;
323
324         /* check the type */
325         if (!sd_bus_message_has_signature(smsg, "s")
326           || sd_bus_message_read_basic(smsg, 's', &reply) < 0) {
327                 sd_bus_error_set_const(error, "bad signature", "");
328                 goto end;
329         }
330         iserror = sd_bus_message_is_method_error(smsg, NULL);
331
332         /* dispatch string? */
333         if (jrespw->onresp_s != NULL) {
334                 jrespw->onresp_s(iserror, reply, jrespw->data);
335                 goto end;
336         }
337
338         /* dispatch json */
339         if (!jparse(jrespw->jbus, reply, &obj))
340                 obj = json_object_new_string(reply);
341         jrespw->onresp_j(iserror, obj, jrespw->data);
342         json_object_put(obj);
343
344  end:
345         free(jrespw);
346         return 1;
347 }
348
349 /*
350  * Creates a message for 'method' with one string parameter being 'query'
351  * and sends it to the destination, object and interface linked to 'jbus'.
352  *
353  * Adds to 'jbus' the response handler defined by the callbacks 'onresp_s'
354  * (for string) and 'onresp_j' (for json) and the closure parameter 'data'.
355  *
356  * Returns 0 in case of success or -1 in case of error.
357  */
358 static int call(
359                 struct jbus *jbus,
360                 const char *method,
361                 const char *query,
362                 void (*onresp_s) (int, const char *, void *),
363                 void (*onresp_j) (int, struct json_object *, void *),
364                 void *data)
365 {
366         int rc;
367         struct jrespw *resp;
368
369         /* allocates the response structure */
370         resp = malloc(sizeof *resp);
371         if (resp == NULL) {
372                 errno = ENOMEM;
373                 goto error;
374         }
375
376         /* fulfill the response structure */
377         resp->jbus = jbus;
378         resp->onresp_s = onresp_s;
379         resp->onresp_j = onresp_j;
380         resp->data = data;
381
382         rc = sd_bus_call_method_async(jbus->sdbus, NULL, jbus->name, jbus->path, jbus->name, method, (void*)on_reply, resp, "s", query);
383         if (rc < 0) {
384                 errno = -rc;
385                 goto error2;
386         }
387
388         return 0;
389
390  error2:
391         free(resp);
392  error:
393         return -1;
394 }
395
396 /********************* MAIN FUNCTIONS *****************************************/
397
398 /*
399  * Creates a 'jbus' bound the 'path' and it derived names and linked
400  * either to the DBUS SYSTEM when 'session' is nul or to the DBUS SESSION
401  * if 'session' is not nul.
402  *
403  * The parameter 'path' is intended to be the path of a DBUS single object.
404  * Single means that it exists only one instance of the object on the
405  * given bus. That path implies 2 derived DBUS names:
406  *   1. the destination name of the program that handles the object
407  *   2. the interface name of the object
408  * These names are derived by removing the heading slash (/) and
409  * by replacing all occurences of slashes by dots.
410  * For example, passing path = /a/b/c means that the object /a/b/c is
411  * handled by the destination a.b.c and replies to the interface a.b.c
412  *
413  * Returns the created jbus or NULL in case of error.
414  */
415 struct jbus *create_jbus(struct sd_bus *sdbus, const char *path)
416 {
417         struct jbus *jbus;
418         char *name;
419
420         /* create the jbus object */
421         jbus = calloc(1, sizeof *jbus);
422         if (jbus == NULL) {
423                 errno = ENOMEM;
424                 goto error;
425         }
426         jbus->refcount = 1;
427
428         /* create the tokener */
429         jbus->tokener = json_tokener_new_ex(MAX_JSON_DEPTH);
430         if (jbus->tokener == NULL) {
431                 errno = ENOMEM;
432                 goto error2;
433         }
434
435         /* records the path */
436         jbus->path = strdup(path);
437         if (jbus->path == NULL) {
438                 errno = ENOMEM;
439                 goto error2;
440         }
441
442         /* makes the name from the path */
443         while (*path == '/')
444                 path++;
445         jbus->name = name = strdup(path);
446         if (name == NULL) {
447                 errno = ENOMEM;
448                 goto error2;
449         }
450         while (*name) {
451                 if (*name == '/')
452                         *name = '.';
453                 name++;
454         }
455         name--;
456         while (name >= jbus->name && *name == '.')
457                 *name-- = 0;
458         if (!*jbus->name) {
459                 errno = EINVAL;
460                 goto error2;
461         }
462
463         /* connect and init */
464         jbus->sdbus = sd_bus_ref(sdbus);
465
466         return jbus;
467
468  error2:
469         jbus_unref(jbus);
470  error:
471         return NULL;
472 }
473
474 /*
475  * Adds one reference to 'jbus'.
476  */
477 void jbus_addref(struct jbus *jbus)
478 {
479         jbus->refcount++;
480 }
481
482 /*
483  * Removes one reference to 'jbus'. Destroys 'jbus' and it related
484  * data if the count of references decrease to zero.
485  */
486 void jbus_unref(struct jbus *jbus)
487 {
488         struct jservice *srv;
489         struct jsignal *sig;
490         if (!--jbus->refcount) {
491                 while ((srv = jbus->services) != NULL) {
492                         jbus->services = srv->next;
493                         free(srv->method);
494                         free(srv);
495                 }
496                 while ((sig = jbus->signals) != NULL) {
497                         jbus->signals = sig->next;
498                         free(sig->name);
499                         free(sig);
500                 }
501                 if (jbus->sservice != NULL)
502                         sd_bus_slot_unref(jbus->sservice);
503                 if (jbus->ssignal != NULL)
504                         sd_bus_slot_unref(jbus->ssignal);
505                 if (jbus->tokener != NULL)
506                         json_tokener_free(jbus->tokener);
507                 sd_bus_unref(jbus->sdbus);
508                 free(jbus->name);
509                 free(jbus->path);
510                 free(jbus);
511         }
512 }
513
514 /*
515  * Replies an error of string 'error' to the request handled by 'smsg'.
516  * Also destroys the request 'smsg' that must not be used later.
517  *
518  * Returns 0 in case of success or -1 in case of error.
519  */
520 int jbus_reply_error_s(struct sd_bus_message *smsg, const char *error)
521 {
522         return mkerrno(sd_bus_reply_method_errorf(smsg, SD_BUS_ERROR_FAILED, "%s", error));
523 }
524
525 /*
526  * Replies an error of json 'reply' to the request handled by 'smsg'.
527  * Also destroys the request 'smsg' that must not be used later.
528  *
529  * Returns 0 in case of success or -1 in case of error.
530  */
531 int jbus_reply_error_j(struct sd_bus_message *smsg, struct json_object *reply)
532 {
533         const char *str = json_object_to_json_string(reply);
534         return str ? jbus_reply_error_s(smsg, str) : reply_out_of_memory(smsg);
535 }
536
537 /*
538  * Replies normally the string 'reply' to the request handled by 'smsg'.
539  * Also destroys the request 'smsg' that must not be used later.
540  *
541  * Returns 0 in case of success or -1 in case of error.
542  */
543 int jbus_reply_s(struct sd_bus_message *smsg, const char *reply)
544 {
545         return mkerrno(sd_bus_reply_method_return(smsg, "s", reply));
546 }
547
548 /*
549  * Replies normally the json 'reply' to the request handled by 'smsg'.
550  * Also destroys the request 'smsg' that must not be used later.
551  *
552  * Returns 0 in case of success or -1 in case of error.
553  */
554 int jbus_reply_j(struct sd_bus_message *smsg, struct json_object *reply)
555 {
556         const char *str = json_object_to_json_string(reply);
557         return str ? jbus_reply_s(smsg, str) : reply_out_of_memory(smsg);
558 }
559
560 /*
561  * Sends from 'jbus' the signal of 'name' handling the string 'content'.
562  *
563  * Returns 0 in case of success or -1 in case of error.
564  */
565 int jbus_send_signal_s(struct jbus *jbus, const char *name, const char *content)
566 {
567         return mkerrno(sd_bus_emit_signal(jbus->sdbus, jbus->path, jbus->name, name, "s", content));
568 }
569
570 /*
571  * Sends from 'jbus' the signal of 'name' handling the json 'content'.
572  *
573  * Returns 0 in case of success or -1 in case of error.
574  */
575 int jbus_send_signal_j(struct jbus *jbus, const char *name,
576                        struct json_object *content)
577 {
578         const char *str = json_object_to_json_string(content);
579         if (str == NULL) {
580                 errno = ENOMEM;
581                 return -1;
582         }
583         return jbus_send_signal_s(jbus, name, str);
584 }
585
586 /*
587  * Adds to 'jbus' a service handling calls to the 'method' using
588  * the "string" callback 'oncall' and the closure value 'data'.
589  *
590  * The callback 'oncall' is invoked for handling incoming method
591  * calls. It receives 3 parameters:
592  *   1. struct sd_bus_message *: a handler to data to be used for replying
593  *   2. const char *: the received string
594  *   3. void *: the closure 'data' set by this function
595  *
596  * Returns 0 in case of success or -1 in case of error.
597  */
598 int jbus_add_service_s(
599                 struct jbus *jbus,
600                 const char *method,
601                 void (*oncall) (struct sd_bus_message *, const char *, void *),
602                 void *data)
603 {
604         return add_service(jbus, method, oncall, NULL, data);
605 }
606
607 /*
608  * Adds to 'jbus' a service handling calls to the 'method' using
609  * the "json" callback 'oncall' and the closure value 'data'.
610  *
611  * The callback 'oncall' is invoked for handling incoming method
612  * calls. It receives 3 parameters:
613  *   1. struct sd_bus_message *: a handler to data to be used for replying
614  *   2. struct json_object *: the received json
615  *   3. void *: the closure 'data' set by this function
616  *
617  * Returns 0 in case of success or -1 in case of error.
618  */
619 int jbus_add_service_j(
620                 struct jbus *jbus,
621                 const char *method,
622                 void (*oncall) (struct sd_bus_message *, struct json_object *, void *),
623                 void *data)
624 {
625         return add_service(jbus, method, NULL, oncall, data);
626 }
627
628 /*
629  * Start to serve: activate services declared for 'jbus'.
630  * This function, in fact, declares 'jbus' as the receiver
631  * for calls to the destination derived from the path set at
632  * 'jbus' creation.
633  * It also allows 'jbus' to emit signals of that origin.
634  *
635  * Returns 0 in case of success or -1 in case of error.
636  */
637 int jbus_start_serving(struct jbus *jbus)
638 {
639         return mkerrno(sd_bus_request_name(jbus->sdbus, jbus->name, 0));
640 }
641
642 /*
643  * Asynchronous call to 'method' of 'jbus' passing the string 'query'.
644  * On response, the function 'onresp' is called with the returned string
645  * value and the closure 'data'.
646  * The function 'onresp' is invoked with 3 parameters:
647  *   1. int: 0 if no error or -1 if error.
648  *   2. const char *: the returned string (might be NULL if error)
649  *   3. void *: the closure 'data'
650  *
651  * Returns 0 in case of success or -1 in case of error.
652  */
653 int jbus_call_ss(
654                 struct jbus *jbus,
655                 const char *method,
656                 const char *query,
657                 void (*onresp) (int, const char *, void *),
658                 void *data)
659 {
660         return call(jbus, method, query, onresp, NULL, data);
661 }
662
663 /*
664  * Asynchronous call to 'method' of 'jbus' passing the string 'query'.
665  * On response, the function 'onresp' is called with the returned json
666  * value and the closure 'data'.
667  * The function 'onresp' is invoked with 3 parameters:
668  *   1. int: 0 if no error or -1 if error.
669  *   2. const char *: the returned json (might be NULL if error)
670  *   3. void *: the closure 'data'
671  *
672  * Returns 0 in case of success or -1 in case of error.
673  */
674 int jbus_call_sj(
675                 struct jbus *jbus,
676                 const char *method,
677                 const char *query,
678                 void (*onresp) (int, struct json_object *, void *),
679                 void *data)
680 {
681         return call(jbus, method, query, NULL, onresp, data);
682 }
683
684 /*
685  * Asynchronous call to 'method' of 'jbus' passing the json 'query'.
686  * On response, the function 'onresp' is called with the returned string
687  * value and the closure 'data'.
688  * The function 'onresp' is invoked with 3 parameters:
689  *   1. int: 0 if no error or -1 if error.
690  *   2. const char *: the returned string (might be NULL if error)
691  *   3. void *: the closure 'data'
692  *
693  * Returns 0 in case of success or -1 in case of error.
694  */
695 int jbus_call_js(
696                 struct jbus *jbus,
697                 const char *method,
698                 struct json_object *query,
699                 void (*onresp) (int, const char *, void *),
700                 void *data)
701 {
702         const char *str = json_object_to_json_string(query);
703         if (str == NULL) {
704                 errno = ENOMEM;
705                 return -1;
706         }
707         return call(jbus, method, str, onresp, NULL, data);
708 }
709
710 /*
711  * Asynchronous call to 'method' of 'jbus' passing the json 'query'.
712  * On response, the function 'onresp' is called with the returned json
713  * value and the closure 'data'.
714  * The function 'onresp' is invoked with 3 parameters:
715  *   1. int: 0 if no error or -1 if error.
716  *   2. const char *: the returned json (might be NULL if error)
717  *   3. void *: the closure 'data'
718  *
719  * Returns 0 in case of success or -1 in case of error.
720  */
721 int jbus_call_jj(
722                 struct jbus *jbus,
723                 const char *method,
724                 struct json_object *query,
725                 void (*onresp) (int, struct json_object *, void *),
726                 void *data)
727 {
728         const char *str = json_object_to_json_string(query);
729         if (str == NULL) {
730                 errno = ENOMEM;
731                 return -1;
732         }
733         return call(jbus, method, str, NULL, onresp, data);
734 }
735
736 /*
737  * Synchronous call to 'method' of 'jbus' passing the string 'query'.
738  * The returned string response is returned.
739  *
740  * Returns the string response or NULL in case of error.
741  */
742 char *jbus_call_ss_sync(
743                 struct jbus *jbus,
744                 const char *method,
745                 const char *query)
746 {
747         sd_bus_message *smsg = NULL;
748         sd_bus_error error = SD_BUS_ERROR_NULL;
749         char *result = NULL;
750         const char *reply;
751
752         /* makes the call */
753         if (mkerrno(sd_bus_call_method(jbus->sdbus, jbus->name, jbus->path, jbus->name, method, &error, &smsg, "s", query)) < 0)
754                 goto error;
755
756         /* check if error */
757         if (sd_bus_message_is_method_error(smsg, NULL))
758                 goto error;
759
760         /* check the returned type */
761         if (!sd_bus_message_has_signature(smsg, "s")
762           || sd_bus_message_read_basic(smsg, 's', &reply) < 0)
763                 goto error;
764
765         /* get the result */
766         result = strdup(reply);
767
768 error:
769         sd_bus_message_unref(smsg);
770         sd_bus_error_free(&error);
771         return result;
772 }
773
774 /*
775  * Synchronous call to 'method' of 'jbus' passing the string 'query'.
776  * The returned json response is returned.
777  *
778  * Returns the json response or NULL in case of error.
779  */
780 struct json_object *jbus_call_sj_sync(
781                 struct jbus *jbus,
782                 const char *method,
783                 const char *query)
784 {
785         struct json_object *obj;
786         char *str = jbus_call_ss_sync(jbus, method, query);
787         if (str == NULL)
788                 obj = NULL;
789         else {
790                 jparse(jbus, str, &obj);
791                 free(str);
792         }
793         return obj;
794 }
795
796 /*
797  * Synchronous call to 'method' of 'jbus' passing the json 'query'.
798  * The returned string response is returned.
799  *
800  * Returns the string response or NULL in case of error.
801  */
802 char *jbus_call_js_sync(
803                 struct jbus *jbus,
804                 const char *method,
805                 struct json_object *query)
806 {
807         const char *str = json_object_to_json_string(query);
808         if (str == NULL) {
809                 errno = ENOMEM;
810                 return NULL;
811         }
812         return jbus_call_ss_sync(jbus, method, str);
813 }
814
815 /*
816  * Synchronous call to 'method' of 'jbus' passing the json 'query'.
817  * The returned json response is returned.
818  *
819  * Returns the json response or NULL in case of error.
820  */
821 struct json_object *jbus_call_jj_sync(
822                 struct jbus *jbus,
823                 const char *method,
824                 struct json_object *query)
825 {
826         const char *str = json_object_to_json_string(query);
827         if (str == NULL) {
828                 errno = ENOMEM;
829                 return NULL;
830         }
831         return jbus_call_sj_sync(jbus, method, str);
832 }
833
834 /*
835  * Records for 'jbus' the string signal handler 'onsig' with closure 'data'
836  * for the signal of 'name'.
837  * The callback handler is called with 2 arguments:
838  *   1. char *: the string parameter associated to the signal
839  *   2. void *: the closure data.
840  *
841  * Returns 0 in case of success or -1 otherwise.
842  */
843 int jbus_on_signal_s(
844                 struct jbus *jbus,
845                 const char *name,
846                 void (*onsig) (const char *, void *),
847                 void *data)
848 {
849         return add_signal(jbus, name, onsig, NULL, data);
850 }
851
852 /*
853  * Records for 'jbus' the json signal handler 'onsig' with closure 'data'
854  * for the signal of 'name'.
855  * The callback handler is called with 2 arguments:
856  *   1. struct json_object *: the json parameter associated to the signal
857  *   2. void *: the closure data.
858  *
859  * Returns 0 in case of success or -1 otherwise.
860  */
861 int jbus_on_signal_j(
862                 struct jbus *jbus,
863                 const char *name,
864                 void (*onsig) (struct json_object *, void *),
865                 void *data)
866 {
867         return add_signal(jbus, name, NULL, onsig, data);
868 }
869
870 /****************** FEW LITTLE TESTS *****************************************/
871
872 #if defined(SERVER)||defined(CLIENT)
873 #include <stdio.h>
874 #include <unistd.h>
875
876 static struct sd_bus *msbus()
877 {
878         static struct sd_bus *r = NULL;
879         if (r == NULL) {
880                 static sd_event *e;
881                 sd_event_default(&e);
882                 sd_bus_open_user(&r);
883                 sd_bus_attach_event(r, e, 0);
884         }
885         return r;
886 }
887
888 static sd_event *events()
889 {
890         static sd_event *ev = NULL;
891         if (ev == NULL)
892                 ev = sd_bus_get_event(msbus());
893         return ev;
894 }
895
896 static int mwait(int timeout, void *closure)
897 {
898         sd_event_run(events(), -1);
899         return 0;
900 }
901
902 static struct jbus *jbus;
903
904 #ifdef SERVER
905 void ping(struct sd_bus_message *smsg, struct json_object *request, void *unused)
906 {
907         printf("ping(%s) -> %s\n", json_object_to_json_string(request),
908                json_object_to_json_string(request));
909         jbus_reply_j(smsg, request);
910         json_object_put(request);
911 }
912
913 void incr(struct sd_bus_message *smsg, struct json_object *request, void *unused)
914 {
915         static int counter = 0;
916         struct json_object *res = json_object_new_int(++counter);
917         printf("incr(%s) -> %s\n", json_object_to_json_string(request),
918                json_object_to_json_string(res));
919         jbus_reply_j(smsg, res);
920         jbus_send_signal_j(jbus, "incremented", res);
921         json_object_put(res);
922         json_object_put(request);
923 }
924
925 int main()
926 {
927         int s1, s2, s3;
928         jbus = create_jbus(msbus(), "/bzh/iot/jdbus");
929         s1 = jbus_add_service_j(jbus, "ping", ping, NULL);
930         s2 = jbus_add_service_j(jbus, "incr", incr, NULL);
931         s3 = jbus_start_serving(jbus);
932         printf("started %d %d %d\n", s1, s2, s3);
933         while (!mwait(-1,jbus)) ;
934         return 0;
935 }
936 #endif
937
938 #ifdef CLIENT
939 void onresp(int status, struct json_object *response, void *data)
940 {
941         printf("resp: %d, %s, %s\n", status, (char *)data,
942                json_object_to_json_string(response));
943         json_object_put(response);
944 }
945
946 void signaled(const char *content, void *data)
947 {
948         printf("signaled with {%s}/%s\n", content, (char*)data);
949 }
950
951 int main()
952 {
953         int i = 1;
954         jbus = create_jbus(msbus(), "/bzh/iot/jdbus");
955         jbus_on_signal_s(jbus, "incremented", signaled, "closure-signal");
956         while (i--) {
957                 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}",
958                              onresp, "ping");
959                 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp,
960                              "incr");
961                 mwait(-1,jbus);
962         }
963         printf("[[[%s]]]\n",
964                jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
965         while (!mwait(-1,jbus)) ;
966         return 0;
967 }
968 #endif
969 #endif
970