e379921c8a7caf1cf0a447f0af2917d30991310c
[src/app-framework-main.git] / src / 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 <dbus/dbus.h>
29
30 #include "utils-jbus.h"
31
32 struct jreq;
33 struct jservice;
34 struct jbus;
35
36 /* structure for handled requests */
37 struct jreq {
38         DBusConnection *connection;
39         DBusMessage *request;
40 };
41
42 /* structure for recorded services */
43 struct jservice {
44         struct jservice *next;
45         char *method;
46         void (*oncall_s)(struct jreq *, const char *);
47         void (*oncall_j)(struct jreq *, struct json_object *);
48 };
49
50 /* structure for signal handlers */
51 struct jsignal {
52         struct jsignal *next;
53         char *name;
54         void (*onsignal_s)(const char *);
55         void (*onsignal_j)(struct json_object *);
56 };
57
58 /* structure for recording asynchronous requests */
59 struct jrespw {
60         struct jrespw *next;
61         dbus_uint32_t serial;
62         void *data;
63         void (*onresp_s)(int, const char*, void *);
64         void (*onresp_j)(int, struct json_object*, void *);
65 };
66
67 /* structure for synchronous requests */
68 struct respsync {
69         int replied;
70         char *value;
71 };
72
73 /* structure for handling either client or server jbus on dbus */
74 struct jbus {
75         int refcount;
76         struct jservice *services;
77         DBusConnection *connection;
78         struct jsignal *signals;
79         struct jrespw *waiters;
80         char *path;
81         char *name;
82         int watchnr;
83         int watchfd;
84         int watchflags;
85 };
86
87 /*********************** STATIC COMMON METHODS *****************/
88
89 static inline void free_jreq(struct jreq *jreq)
90 {
91         dbus_message_unref(jreq->request);
92         dbus_connection_unref(jreq->connection);
93         free(jreq);
94 }
95
96 static inline int reply_out_of_memory(struct jreq *jreq)
97 {
98         static const char out_of_memory[] = "out of memory";
99         jbus_reply_error_s(jreq, out_of_memory);
100         errno = ENOMEM;
101         return -1;
102 }
103
104 static inline int reply_invalid_request(struct jreq *jreq)
105 {
106         static const char invalid_request[] = "invalid request";
107         jbus_reply_error_s(jreq, invalid_request);
108         return DBUS_HANDLER_RESULT_HANDLED;
109 }
110
111 static int matchitf(struct jbus *jbus, DBusMessage *message)
112 {
113         const char *itf = dbus_message_get_interface(message);
114         return itf != NULL && !strcmp(itf, jbus->name);
115 }
116
117 static int add_service(
118                 struct jbus *jbus,
119                 const char *method,
120                 void (*oncall_s)(struct jreq*, const char*),
121                 void (*oncall_j)(struct jreq*, struct json_object*)
122 )
123 {
124         struct jservice *srv;
125
126         /* allocation */
127         srv = malloc(sizeof * srv);
128         if (srv == NULL) {
129                 errno = ENOMEM;
130                 goto error;
131         }
132         srv->method = strdup(method);
133         if (!srv->method) {
134                 errno = ENOMEM;
135                 goto error2;
136         }
137
138         /* record the service */
139         srv->oncall_s = oncall_s;
140         srv->oncall_j = oncall_j;
141         srv->next = jbus->services;
142         jbus->services = srv;
143
144         return 0;
145
146 error2:
147         free(srv);
148 error:
149         return -1;
150 }
151
152 static int add_signal(
153         struct jbus *jbus,
154         const char *name,
155         void (*onsignal_s)(const char*),
156         void (*onsignal_j)(struct json_object*)
157 )
158 {
159         char *rule;
160         struct jsignal *sig;
161
162         /* record the signal */
163         if (jbus->signals == NULL) {
164 #if 0
165                 if (0 >= asprintf(&rule, "type='signal',interface='%s',path='%s'", jbus->name, jbus->path))
166 #else
167                 if (0 >= asprintf(&rule, "type='signal',sender='%s',interface='%s',path='%s'", jbus->name, jbus->name, jbus->path))
168 #endif
169                         return -1;
170                 dbus_bus_add_match(jbus->connection, rule, NULL);
171                 free(rule);
172         }
173
174         /* allocation */
175         sig = malloc(sizeof * sig);
176         if (sig == NULL)
177                 goto error;
178         sig->name = strdup(name);
179         if (!sig->name)
180                 goto error2;
181
182         /* record the signal */
183         sig->onsignal_s = onsignal_s;
184         sig->onsignal_j = onsignal_j;
185         sig->next = jbus->signals;
186         jbus->signals = sig;
187
188         return 0;
189
190 error2:
191         free(sig);
192 error:
193         errno = ENOMEM;
194         return -1;
195 }
196
197 static int call(
198         struct jbus *jbus,
199         const char *method,
200         const char *query,
201         void (*onresp_s)(int status, const char *response, void *data),
202         void (*onresp_j)(int status, struct json_object *response, void *data),
203         void *data
204 )
205 {
206         DBusMessage *msg;
207         struct jrespw *resp;
208
209         resp = malloc(sizeof * resp);
210         if (resp == NULL) {
211                 errno = ENOMEM;
212                 goto error;
213         }
214
215         msg = dbus_message_new_method_call(jbus->name, jbus->path, jbus->name, method);
216         if (msg == NULL) {
217                 errno = ENOMEM;
218                 goto error2;
219         }
220
221         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &query, DBUS_TYPE_INVALID)) {
222                 errno = ENOMEM;
223                 goto error3;
224         }
225
226         if (!dbus_connection_send(jbus->connection, msg, &resp->serial)) {
227                 goto error3;
228         }
229
230         dbus_message_unref(msg);
231         resp->data = data;
232         resp->onresp_s = onresp_s;
233         resp->onresp_j = onresp_j;
234         resp->next = jbus->waiters;
235         jbus->waiters = resp;
236         return 0;
237
238 error3:
239         dbus_message_unref(msg);
240 error2:
241         free(resp);
242 error:
243         return -1;
244 }
245
246 static void sync_of_replies(int status, const char *value, void *data)
247 {
248         struct respsync *s = data;
249         s->value = status ? NULL : strdup(value ? value : "");
250         s->replied = 1;
251 }
252
253 static DBusHandlerResult incoming_resp(DBusConnection *connection, DBusMessage *message, struct jbus *jbus, int iserror)
254 {
255         int status;
256         const char *str;
257         struct jrespw *jrw, **prv;
258         struct json_object *reply;
259         dbus_uint32_t serial;
260
261         /* search for the waiter */
262         serial = dbus_message_get_reply_serial(message);
263         prv = &jbus->waiters;
264         while ((jrw = *prv) != NULL && jrw->serial != serial)
265                 prv = &jrw->next;
266         if (jrw == NULL)
267                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
268         *prv = jrw->next;
269
270         /* retrieve the string value */
271         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
272                 status = -1;
273                 str = NULL;
274                 reply = NULL;
275         }
276
277         /* treat it */
278         if (jrw->onresp_s)
279                 jrw->onresp_s(iserror ? -1 : status, str, jrw->data);
280         else {
281                 reply = json_tokener_parse(str);
282                 status = reply ? 0 : -1;
283                 jrw->onresp_j(iserror ? -1 : status, reply, jrw->data);
284                 json_object_put(reply);
285         }
286
287         free(jrw);
288         return DBUS_HANDLER_RESULT_HANDLED;
289 }
290
291 static DBusHandlerResult incoming_call(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
292 {
293         struct jservice *srv;
294         struct jreq *jreq;
295         const char *str;
296         const char *method;
297         struct json_object *query;
298
299         /* search for the service */
300         if (!matchitf(jbus, message))
301                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
302         method = dbus_message_get_member(message);
303         if (method == NULL)
304                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
305         srv = jbus->services;
306         while(srv != NULL && strcmp(method, srv->method))
307                 srv = srv->next;
308         if (srv == NULL)
309                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
310
311         /* handle the message */
312         jreq = malloc(sizeof * jreq);
313         if (jreq == NULL)
314                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
315         jreq->request = dbus_message_ref(message);
316         jreq->connection = dbus_connection_ref(jbus->connection);
317         
318         /* retrieve the string value */
319         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID))
320                 return reply_invalid_request(jreq);
321         if (srv->oncall_s) {
322                 /* handling strings only */
323                 srv->oncall_s(jreq, str);
324         }
325         else {
326                 /* handling json only */
327                 query = json_tokener_parse(str);
328                 if (query == NULL)
329                         return reply_invalid_request(jreq);
330                 srv->oncall_j(jreq, query);
331                 json_object_put(query);
332         }
333         return DBUS_HANDLER_RESULT_HANDLED;
334 }
335
336 static DBusHandlerResult incoming_signal(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
337 {
338         struct jsignal *sig;
339         const char *str;
340         const char *name;
341         struct json_object *obj;
342
343         /* search for the service */
344         if (!matchitf(jbus, message))
345                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
346         name = dbus_message_get_member(message);
347         if (name == NULL)
348                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
349         sig = jbus->signals;
350         while(sig != NULL && strcmp(name, sig->name))
351                 sig = sig->next;
352         if (sig == NULL)
353                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
354
355         /* retrieve the string value */
356         if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
357                 if (sig->onsignal_s) {
358                         /* handling strings only */
359                         sig->onsignal_s(str);
360                 }
361                 else {
362                         /* handling json only */
363                         obj = json_tokener_parse(str);
364                         if (obj != NULL) {
365                                 sig->onsignal_j(obj);
366                                 json_object_put(obj);
367                         }
368                 }
369         }
370         return DBUS_HANDLER_RESULT_HANDLED;
371 }
372
373 static DBusHandlerResult incoming(DBusConnection *connection, DBusMessage *message, void *data)
374 {
375         switch(dbus_message_get_type(message)) {
376         case DBUS_MESSAGE_TYPE_METHOD_CALL:
377                 return incoming_call(connection, message, (struct jbus*)data);
378         case DBUS_MESSAGE_TYPE_METHOD_RETURN:
379                 return incoming_resp(connection, message, (struct jbus*)data, 0);
380         case DBUS_MESSAGE_TYPE_ERROR:
381                 return incoming_resp(connection, message, (struct jbus*)data, 1);
382         case DBUS_MESSAGE_TYPE_SIGNAL:
383                 return incoming_signal(connection, message, (struct jbus*)data);
384         }
385         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
386 }
387
388 static void watchset(DBusWatch *watch, struct jbus *jbus)
389 {
390         unsigned int flags;
391         int wf, e;
392
393         flags = dbus_watch_get_flags(watch);
394         e = dbus_watch_get_enabled(watch);
395         wf = jbus->watchflags;
396         if (e) {
397                 if (flags & DBUS_WATCH_READABLE)
398                         wf |= POLLIN;
399                 if (flags & DBUS_WATCH_WRITABLE)
400                         wf |= POLLOUT;
401         }
402         else {
403                 if (flags & DBUS_WATCH_READABLE)
404                         wf &= ~POLLIN;
405                 if (flags & DBUS_WATCH_WRITABLE)
406                         wf &= ~POLLOUT;
407         }
408         jbus->watchflags = wf;
409 }
410
411 static void watchdel(DBusWatch *watch, void *data)
412 {
413         struct jbus *jbus = data;
414
415         assert(jbus->watchnr > 0);
416         assert(jbus->watchfd == dbus_watch_get_unix_fd(watch));
417         jbus->watchnr--;
418 }
419
420 static void watchtoggle(DBusWatch *watch, void *data)
421 {
422         struct jbus *jbus = data;
423
424         assert(jbus->watchnr > 0);
425         assert(jbus->watchfd == dbus_watch_get_unix_fd(watch));
426         watchset(watch, jbus);
427 }
428
429 static dbus_bool_t watchadd(DBusWatch *watch, void *data)
430 {
431         struct jbus *jbus = data;
432         if (jbus->watchnr == 0) {
433                 jbus->watchfd = dbus_watch_get_unix_fd(watch);
434                 jbus->watchflags = 0;
435         }
436         else if (jbus->watchfd != dbus_watch_get_unix_fd(watch))
437                 return FALSE;
438         jbus->watchnr++;
439         watchset(watch, jbus);
440         return TRUE;
441 }
442
443 /************************** MAIN FUNCTIONS *****************************************/
444
445 struct jbus *create_jbus(int session, const char *path)
446 {
447         struct jbus *jbus;
448         char *name;
449
450         /* create the context and connect */
451         jbus = calloc(1, sizeof * jbus);
452         if (jbus == NULL) {
453                 errno = ENOMEM;
454                 goto error;
455         }
456         jbus->refcount = 1;
457         jbus->path = strdup(path);
458         if (jbus->path == NULL) {
459                 errno = ENOMEM;
460                 goto error2;
461         }
462         while(*path == '/') path++;
463         jbus->name = name = strdup(path);
464         if (name == NULL) {
465                 errno = ENOMEM;
466                 goto error2;
467         }
468         while(*name) {
469                 if (*name == '/')
470                         *name = '.';
471                 name++;
472         }
473         name--;
474         while (name >= jbus->name && *name == '.')
475                 *name-- = 0;
476         if (!*jbus->name) {
477                 errno = EINVAL;
478                 goto error2;
479         }
480
481         /* connect */
482         jbus->connection = dbus_bus_get(session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, NULL);
483         if (jbus->connection == NULL
484         || !dbus_connection_add_filter(jbus->connection, incoming, jbus, NULL)
485         || !dbus_connection_set_watch_functions(jbus->connection, watchadd, watchdel, watchtoggle, jbus, NULL))
486                 goto error2;
487
488         return jbus;
489
490 error2:
491         jbus_unref(jbus);
492 error:
493         return NULL;
494 }
495
496 void jbus_addref(struct jbus *jbus)
497 {
498         jbus->refcount++;
499 }
500
501 void jbus_unref(struct jbus *jbus)
502 {
503         struct jservice *srv;
504         if (!--jbus->refcount) {
505                 if (jbus->connection != NULL)
506                         dbus_connection_unref(jbus->connection);
507                 while((srv = jbus->services) != NULL) {
508                         jbus->services = srv->next;
509                         free(srv->method);
510                         free(srv);
511                 }
512                 free(jbus->name);
513                 free(jbus->path);
514                 free(jbus);
515         }
516 }
517
518 int jbus_reply_error_s(struct jreq *jreq, const char *error)
519 {
520         int rc = -1;
521         DBusMessage *message;
522
523         message = dbus_message_new_error(jreq->request, DBUS_ERROR_FAILED, error);
524         if (message == NULL)
525                 errno = ENOMEM;
526         else {
527                 if (dbus_connection_send(jreq->connection, message, NULL))
528                         rc = 0;
529                 dbus_message_unref(message);
530         }
531         free_jreq(jreq);
532         return rc;
533 }
534
535 int jbus_reply_error_j(struct jreq *jreq, struct json_object *reply)
536 {
537         const char *str = json_object_to_json_string(reply);
538         return str ? jbus_reply_error_s(jreq, str) : reply_out_of_memory(jreq);
539 }
540
541 int jbus_reply_s(struct jreq *jreq, const char *reply)
542 {
543         int rc = -1;
544         DBusMessage *message;
545
546         message = dbus_message_new_method_return(jreq->request);
547         if (message == NULL)
548                 return reply_out_of_memory(jreq);
549
550         if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
551                 dbus_message_unref(message);
552                 return reply_out_of_memory(jreq);
553         }
554
555         if (dbus_connection_send(jreq->connection, message, NULL))
556                 rc = 0;
557         dbus_message_unref(message);
558         free_jreq(jreq);
559         return rc;
560 }
561
562 int jbus_reply_j(struct jreq *jreq, struct json_object *reply)
563 {
564         const char *str = json_object_to_json_string(reply);
565         return str ? jbus_reply_s(jreq, str) : reply_out_of_memory(jreq);
566 }
567
568 int jbus_send_signal_s(struct jbus *jbus, const char *name, const char *content)
569 {
570         int rc = -1;
571         DBusMessage *message;
572
573         message = dbus_message_new_signal(jbus->path, jbus->name, name);
574         if (message == NULL)
575                 goto error;
576
577         if (!dbus_message_set_sender(message, jbus->name)
578         ||  !dbus_message_append_args(message, DBUS_TYPE_STRING, &content, DBUS_TYPE_INVALID)) {
579                 dbus_message_unref(message);
580                 goto error;
581         }
582
583         if (dbus_connection_send(jbus->connection, message, NULL))
584                 rc = 0;
585         dbus_message_unref(message);
586         return rc;
587
588 error:
589         errno = ENOMEM;
590         return -1;
591 }
592
593 int jbus_send_signal_j(struct jbus *jbus, const char *name, struct json_object *content)
594 {
595         const char *str = json_object_to_json_string(content);
596         if (str == NULL) {
597                 errno = ENOMEM;
598                 return -1;
599         }
600         return jbus_send_signal_s(jbus, name, str);
601 }
602
603 int jbus_add_service_s(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *, const char *))
604 {
605         return add_service(jbus, method, oncall, NULL);
606 }
607
608 int jbus_add_service_j(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *, struct json_object *))
609 {
610         return add_service(jbus, method, NULL, oncall);
611 }
612
613 int jbus_start_serving(struct jbus *jbus)
614 {
615         int status = dbus_bus_request_name(jbus->connection, jbus->name, DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
616         switch (status) {
617         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
618         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
619                 return 0;
620         case DBUS_REQUEST_NAME_REPLY_EXISTS:
621         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
622         default:
623                 errno = EADDRINUSE;
624                 return -1;
625         }
626 }
627
628 int jbus_fill_pollfds(struct jbus **jbuses, int njbuses, struct pollfd *fds)
629 {
630         int i, r;
631
632         for (r = i = 0 ; i < njbuses ; i++) {
633                 if (jbuses[i]->watchnr) {
634                         fds[r].fd = jbuses[i]->watchfd;
635                         fds[r].events = jbuses[i]->watchflags;
636                         r++;
637                 }
638         }
639         return r;
640 }
641
642 int jbus_dispatch_pollfds(struct jbus **jbuses, int njbuses, struct pollfd *fds, int maxcount)
643 {
644         int i, r, n;
645         DBusDispatchStatus sts;
646
647         for (r = n = i = 0 ; i < njbuses && n < maxcount ; i++) {
648                 if (jbuses[i]->watchnr && fds[r].fd == jbuses[i]->watchfd) {
649                         if (fds[r].revents) {
650                                 dbus_connection_read_write(jbuses[i]->connection, 0);
651                                 sts = dbus_connection_get_dispatch_status(jbuses[i]->connection);
652                                 while(sts == DBUS_DISPATCH_DATA_REMAINS &&  n < maxcount) {
653                                         sts = dbus_connection_dispatch(jbuses[i]->connection);
654                                         n++;
655                                 }
656                         }
657                         r++;
658                 }
659         }
660         return n;
661 }
662
663 int jbus_dispatch_multiple(struct jbus **jbuses, int njbuses, int maxcount)
664 {
665         int i, r;
666         DBusDispatchStatus sts;
667
668         for (i = r = 0 ; i < njbuses && r < maxcount ; i++) {
669                 dbus_connection_read_write(jbuses[i]->connection, 0);
670                 while(sts == DBUS_DISPATCH_DATA_REMAINS &&  r < maxcount) {
671                         sts = dbus_connection_dispatch(jbuses[i]->connection);
672                         r++;
673                 }
674         }
675         return r;
676 }
677
678 int jbus_read_write_dispatch_multiple(struct jbus **jbuses, int njbuses, int toms, int maxcount)
679 {
680         int n, r, s;
681         struct pollfd *fds;
682
683         if (njbuses < 0 || njbuses > 100) {
684                 errno = EINVAL;
685                 return -1;
686         }
687         fds = alloca(njbuses * sizeof * fds);
688         assert(fds != NULL);
689
690         r = jbus_dispatch_multiple(jbuses, njbuses, maxcount);
691         n = jbus_fill_pollfds(jbuses, njbuses, fds);
692         s = poll(fds, n, toms);
693         if (s < 0)
694                 return r ? r : s;
695         n = jbus_dispatch_pollfds(jbuses, njbuses, fds, maxcount - r);
696         return n >= 0 ? r + n : r ? r : n;
697 }
698
699 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
700 {
701         int r = jbus_read_write_dispatch_multiple(&jbus, 1, toms, 1000);
702         return r < 0 ? r : 0;
703 }
704
705 int jbus_call_ss(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, const char*, void*), void *data)
706 {
707         return call(jbus, method, query, onresp, NULL, data);
708 }
709
710 int jbus_call_sj(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, struct json_object*, void*), void *data)
711 {
712         return call(jbus, method, query, NULL, onresp, data);
713 }
714
715 int jbus_call_js(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, const char*, void*), void *data)
716 {
717         const char *str = json_object_to_json_string(query);
718         if (str == NULL) {
719                 errno = ENOMEM;
720                 return -1;
721         }
722         return call(jbus, method, str, onresp, NULL, data);
723 }
724
725 int jbus_call_jj(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, struct json_object*, void*), 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 char *jbus_call_ss_sync(struct jbus *jbus, const char *method, const char *query)
736 {
737         struct respsync synchro;
738         synchro.value = NULL;
739         synchro.replied = jbus_call_ss(jbus, method, query, sync_of_replies, &synchro);
740         while (!synchro.replied && !jbus_read_write_dispatch(jbus, -1));
741         return synchro.value;
742 }
743
744 struct json_object *jbus_call_sj_sync(struct jbus *jbus, const char *method, const char *query)
745 {
746         struct json_object *obj;
747         char *str = jbus_call_ss_sync(jbus, method, query);
748         if (str == NULL)
749                 obj = NULL;
750         else {
751                 obj = json_tokener_parse(str);
752                 free(str);
753         }
754         return obj;
755 }
756
757 char *jbus_call_js_sync(struct jbus *jbus, const char *method, struct json_object *query)
758 {
759         const char *str = json_object_to_json_string(query);
760         if (str == NULL) {
761                 errno = ENOMEM;
762                 return NULL;
763         }
764         return jbus_call_ss_sync(jbus, method, str);
765 }
766
767 struct json_object *jbus_call_jj_sync(struct jbus *jbus, const char *method, struct json_object *query)
768 {
769         const char *str = json_object_to_json_string(query);
770         if (str == NULL) {
771                 errno = ENOMEM;
772                 return NULL;
773         }
774         return jbus_call_sj_sync(jbus, method, str);
775 }
776
777 int jbus_on_signal_s(struct jbus *jbus, const char *name, void (*onsig)(const char *))
778 {
779         return add_signal(jbus, name, onsig, NULL);
780 }
781
782 int jbus_on_signal_j(struct jbus *jbus, const char *name, void (*onsig)(struct json_object *))
783 {
784         return add_signal(jbus, name, NULL, onsig);
785 }
786
787 /************************** FEW LITTLE TESTS *****************************************/
788
789 #ifdef SERVER
790 #include <stdio.h>
791 #include <unistd.h>
792 struct jbus *jbus;
793 void ping(struct jreq *jreq, struct json_object *request)
794 {
795 printf("ping(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(request));
796         jbus_reply_j(jreq, request);
797         json_object_put(request);       
798 }
799 void incr(struct jreq *jreq, struct json_object *request)
800 {
801         static int counter = 0;
802         struct json_object *res = json_object_new_int(++counter);
803 printf("incr(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(res));
804         jbus_reply_j(jreq, res);
805 jbus_send_signal_j(jbus, "incremented", res);
806         json_object_put(res);
807         json_object_put(request);
808 }
809 int main()
810 {
811         int s1, s2, s3;
812         jbus = create_jbus(1, "/bzh/iot/jdbus");
813         s1 = jbus_add_service_j(jbus, "ping", ping);
814         s2 = jbus_add_service_j(jbus, "incr", incr);
815         s3 = jbus_start_serving(jbus);
816         printf("started %d %d %d\n", s1, s2, s3);
817         while (!jbus_read_write_dispatch (jbus, -1));
818 }
819 #endif
820 #ifdef CLIENT
821 #include <stdio.h>
822 #include <unistd.h>
823 struct jbus *jbus;
824 void onresp(int status, struct json_object *response, void *data)
825 {
826         printf("resp: %d, %s, %s\n",status,(char*)data,json_object_to_json_string(response));
827         json_object_put(response);
828 }
829 void signaled(const char *data)
830 {
831         printf("signaled with {%s}\n", data);
832 }
833 int main()
834 {
835         int i = 10;
836         jbus = create_jbus(1, "/bzh/iot/jdbus");
837         jbus_on_signal_s(jbus, "incremented", signaled);
838         while(i--) {
839                 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}", onresp, "ping");
840                 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp, "incr");
841                 jbus_read_write_dispatch (jbus, 1);
842         }
843         printf("[[[%s]]]\n", jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
844         while (!jbus_read_write_dispatch (jbus, -1));
845 }
846 #endif
847
848
849
850
851
852
853
854