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