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