utils-dbus: fix un initialised status
[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 = 0;
273         else {
274                 status = -1;
275                 str = NULL;
276                 reply = NULL;
277         }
278
279         /* treat it */
280         if (jrw->onresp_s)
281                 jrw->onresp_s(iserror ? -1 : status, str, jrw->data);
282         else {
283                 reply = json_tokener_parse(str);
284                 status = reply ? 0 : -1;
285                 jrw->onresp_j(iserror ? -1 : status, reply, jrw->data);
286                 json_object_put(reply);
287         }
288
289         free(jrw);
290         return DBUS_HANDLER_RESULT_HANDLED;
291 }
292
293 static DBusHandlerResult incoming_call(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
294 {
295         struct jservice *srv;
296         struct jreq *jreq;
297         const char *str;
298         const char *method;
299         struct json_object *query;
300
301         /* search for the service */
302         if (!matchitf(jbus, message))
303                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
304         method = dbus_message_get_member(message);
305         if (method == NULL)
306                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
307         srv = jbus->services;
308         while(srv != NULL && strcmp(method, srv->method))
309                 srv = srv->next;
310         if (srv == NULL)
311                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
312
313         /* handle the message */
314         jreq = malloc(sizeof * jreq);
315         if (jreq == NULL)
316                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
317         jreq->request = dbus_message_ref(message);
318         jreq->connection = dbus_connection_ref(jbus->connection);
319         
320         /* retrieve the string value */
321         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID))
322                 return reply_invalid_request(jreq);
323         if (srv->oncall_s) {
324                 /* handling strings only */
325                 srv->oncall_s(jreq, str);
326         }
327         else {
328                 /* handling json only */
329                 query = json_tokener_parse(str);
330                 if (query == NULL)
331                         return reply_invalid_request(jreq);
332                 srv->oncall_j(jreq, query);
333                 json_object_put(query);
334         }
335         return DBUS_HANDLER_RESULT_HANDLED;
336 }
337
338 static DBusHandlerResult incoming_signal(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
339 {
340         struct jsignal *sig;
341         const char *str;
342         const char *name;
343         struct json_object *obj;
344
345         /* search for the service */
346         if (!matchitf(jbus, message))
347                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
348         name = dbus_message_get_member(message);
349         if (name == NULL)
350                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
351         sig = jbus->signals;
352         while(sig != NULL && strcmp(name, sig->name))
353                 sig = sig->next;
354         if (sig == NULL)
355                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
356
357         /* retrieve the string value */
358         if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
359                 if (sig->onsignal_s) {
360                         /* handling strings only */
361                         sig->onsignal_s(str);
362                 }
363                 else {
364                         /* handling json only */
365                         obj = json_tokener_parse(str);
366                         if (obj != NULL) {
367                                 sig->onsignal_j(obj);
368                                 json_object_put(obj);
369                         }
370                 }
371         }
372         return DBUS_HANDLER_RESULT_HANDLED;
373 }
374
375 static DBusHandlerResult incoming(DBusConnection *connection, DBusMessage *message, void *data)
376 {
377         switch(dbus_message_get_type(message)) {
378         case DBUS_MESSAGE_TYPE_METHOD_CALL:
379                 return incoming_call(connection, message, (struct jbus*)data);
380         case DBUS_MESSAGE_TYPE_METHOD_RETURN:
381                 return incoming_resp(connection, message, (struct jbus*)data, 0);
382         case DBUS_MESSAGE_TYPE_ERROR:
383                 return incoming_resp(connection, message, (struct jbus*)data, 1);
384         case DBUS_MESSAGE_TYPE_SIGNAL:
385                 return incoming_signal(connection, message, (struct jbus*)data);
386         }
387         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
388 }
389
390 static void watchset(DBusWatch *watch, struct jbus *jbus)
391 {
392         unsigned int flags;
393         int wf, e;
394
395         flags = dbus_watch_get_flags(watch);
396         e = dbus_watch_get_enabled(watch);
397         wf = jbus->watchflags;
398         if (e) {
399                 if (flags & DBUS_WATCH_READABLE)
400                         wf |= POLLIN;
401                 if (flags & DBUS_WATCH_WRITABLE)
402                         wf |= POLLOUT;
403         }
404         else {
405                 if (flags & DBUS_WATCH_READABLE)
406                         wf &= ~POLLIN;
407                 if (flags & DBUS_WATCH_WRITABLE)
408                         wf &= ~POLLOUT;
409         }
410         jbus->watchflags = wf;
411 }
412
413 static void watchdel(DBusWatch *watch, void *data)
414 {
415         struct jbus *jbus = data;
416
417         assert(jbus->watchnr > 0);
418         assert(jbus->watchfd == dbus_watch_get_unix_fd(watch));
419         jbus->watchnr--;
420 }
421
422 static void watchtoggle(DBusWatch *watch, void *data)
423 {
424         struct jbus *jbus = data;
425
426         assert(jbus->watchnr > 0);
427         assert(jbus->watchfd == dbus_watch_get_unix_fd(watch));
428         watchset(watch, jbus);
429 }
430
431 static dbus_bool_t watchadd(DBusWatch *watch, void *data)
432 {
433         struct jbus *jbus = data;
434         if (jbus->watchnr == 0) {
435                 jbus->watchfd = dbus_watch_get_unix_fd(watch);
436                 jbus->watchflags = 0;
437         }
438         else if (jbus->watchfd != dbus_watch_get_unix_fd(watch))
439                 return FALSE;
440         jbus->watchnr++;
441         watchset(watch, jbus);
442         return TRUE;
443 }
444
445 /************************** MAIN FUNCTIONS *****************************************/
446
447 struct jbus *create_jbus(int session, const char *path)
448 {
449         struct jbus *jbus;
450         char *name;
451
452         /* create the context and connect */
453         jbus = calloc(1, sizeof * jbus);
454         if (jbus == NULL) {
455                 errno = ENOMEM;
456                 goto error;
457         }
458         jbus->refcount = 1;
459         jbus->path = strdup(path);
460         if (jbus->path == NULL) {
461                 errno = ENOMEM;
462                 goto error2;
463         }
464         while(*path == '/') path++;
465         jbus->name = name = strdup(path);
466         if (name == NULL) {
467                 errno = ENOMEM;
468                 goto error2;
469         }
470         while(*name) {
471                 if (*name == '/')
472                         *name = '.';
473                 name++;
474         }
475         name--;
476         while (name >= jbus->name && *name == '.')
477                 *name-- = 0;
478         if (!*jbus->name) {
479                 errno = EINVAL;
480                 goto error2;
481         }
482
483         /* connect */
484         jbus->connection = dbus_bus_get(session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, NULL);
485         if (jbus->connection == NULL
486         || !dbus_connection_add_filter(jbus->connection, incoming, jbus, NULL)
487         || !dbus_connection_set_watch_functions(jbus->connection, watchadd, watchdel, watchtoggle, jbus, NULL))
488                 goto error2;
489
490         return jbus;
491
492 error2:
493         jbus_unref(jbus);
494 error:
495         return NULL;
496 }
497
498 void jbus_addref(struct jbus *jbus)
499 {
500         jbus->refcount++;
501 }
502
503 void jbus_unref(struct jbus *jbus)
504 {
505         struct jservice *srv;
506         if (!--jbus->refcount) {
507                 if (jbus->connection != NULL)
508                         dbus_connection_unref(jbus->connection);
509                 while((srv = jbus->services) != NULL) {
510                         jbus->services = srv->next;
511                         free(srv->method);
512                         free(srv);
513                 }
514                 free(jbus->name);
515                 free(jbus->path);
516                 free(jbus);
517         }
518 }
519
520 int jbus_reply_error_s(struct jreq *jreq, const char *error)
521 {
522         int rc = -1;
523         DBusMessage *message;
524
525         message = dbus_message_new_error(jreq->request, DBUS_ERROR_FAILED, error);
526         if (message == NULL)
527                 errno = ENOMEM;
528         else {
529                 if (dbus_connection_send(jreq->connection, message, NULL))
530                         rc = 0;
531                 dbus_message_unref(message);
532         }
533         free_jreq(jreq);
534         return rc;
535 }
536
537 int jbus_reply_error_j(struct jreq *jreq, struct json_object *reply)
538 {
539         const char *str = json_object_to_json_string(reply);
540         return str ? jbus_reply_error_s(jreq, str) : reply_out_of_memory(jreq);
541 }
542
543 int jbus_reply_s(struct jreq *jreq, const char *reply)
544 {
545         int rc = -1;
546         DBusMessage *message;
547
548         message = dbus_message_new_method_return(jreq->request);
549         if (message == NULL)
550                 return reply_out_of_memory(jreq);
551
552         if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
553                 dbus_message_unref(message);
554                 return reply_out_of_memory(jreq);
555         }
556
557         if (dbus_connection_send(jreq->connection, message, NULL))
558                 rc = 0;
559         dbus_message_unref(message);
560         free_jreq(jreq);
561         return rc;
562 }
563
564 int jbus_reply_j(struct jreq *jreq, struct json_object *reply)
565 {
566         const char *str = json_object_to_json_string(reply);
567         return str ? jbus_reply_s(jreq, str) : reply_out_of_memory(jreq);
568 }
569
570 int jbus_send_signal_s(struct jbus *jbus, const char *name, const char *content)
571 {
572         int rc = -1;
573         DBusMessage *message;
574
575         message = dbus_message_new_signal(jbus->path, jbus->name, name);
576         if (message == NULL)
577                 goto error;
578
579         if (!dbus_message_set_sender(message, jbus->name)
580         ||  !dbus_message_append_args(message, DBUS_TYPE_STRING, &content, DBUS_TYPE_INVALID)) {
581                 dbus_message_unref(message);
582                 goto error;
583         }
584
585         if (dbus_connection_send(jbus->connection, message, NULL))
586                 rc = 0;
587         dbus_message_unref(message);
588         return rc;
589
590 error:
591         errno = ENOMEM;
592         return -1;
593 }
594
595 int jbus_send_signal_j(struct jbus *jbus, const char *name, struct json_object *content)
596 {
597         const char *str = json_object_to_json_string(content);
598         if (str == NULL) {
599                 errno = ENOMEM;
600                 return -1;
601         }
602         return jbus_send_signal_s(jbus, name, str);
603 }
604
605 int jbus_add_service_s(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *, const char *))
606 {
607         return add_service(jbus, method, oncall, NULL);
608 }
609
610 int jbus_add_service_j(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *, struct json_object *))
611 {
612         return add_service(jbus, method, NULL, oncall);
613 }
614
615 int jbus_start_serving(struct jbus *jbus)
616 {
617         int status = dbus_bus_request_name(jbus->connection, jbus->name, DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
618         switch (status) {
619         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
620         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
621                 return 0;
622         case DBUS_REQUEST_NAME_REPLY_EXISTS:
623         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
624         default:
625                 errno = EADDRINUSE;
626                 return -1;
627         }
628 }
629
630 int jbus_fill_pollfds(struct jbus **jbuses, int njbuses, struct pollfd *fds)
631 {
632         int i, r;
633
634         for (r = i = 0 ; i < njbuses ; i++) {
635                 if (jbuses[i]->watchnr) {
636                         fds[r].fd = jbuses[i]->watchfd;
637                         fds[r].events = jbuses[i]->watchflags;
638                         r++;
639                 }
640         }
641         return r;
642 }
643
644 int jbus_dispatch_pollfds(struct jbus **jbuses, int njbuses, struct pollfd *fds, int maxcount)
645 {
646         int i, r, n;
647         DBusDispatchStatus sts;
648
649         for (r = n = i = 0 ; i < njbuses && n < maxcount ; i++) {
650                 if (jbuses[i]->watchnr && fds[r].fd == jbuses[i]->watchfd) {
651                         if (fds[r].revents) {
652                                 dbus_connection_read_write(jbuses[i]->connection, 0);
653                                 sts = dbus_connection_get_dispatch_status(jbuses[i]->connection);
654                                 while(sts == DBUS_DISPATCH_DATA_REMAINS &&  n < maxcount) {
655                                         sts = dbus_connection_dispatch(jbuses[i]->connection);
656                                         n++;
657                                 }
658                         }
659                         r++;
660                 }
661         }
662         return n;
663 }
664
665 int jbus_dispatch_multiple(struct jbus **jbuses, int njbuses, int maxcount)
666 {
667         int i, r;
668         DBusDispatchStatus sts;
669
670         for (i = r = 0 ; i < njbuses && r < maxcount ; i++) {
671                 dbus_connection_read_write(jbuses[i]->connection, 0);
672                 while(sts == DBUS_DISPATCH_DATA_REMAINS &&  r < maxcount) {
673                         sts = dbus_connection_dispatch(jbuses[i]->connection);
674                         r++;
675                 }
676         }
677         return r;
678 }
679
680 int jbus_read_write_dispatch_multiple(struct jbus **jbuses, int njbuses, int toms, int maxcount)
681 {
682         int n, r, s;
683         struct pollfd *fds;
684
685         if (njbuses < 0 || njbuses > 100) {
686                 errno = EINVAL;
687                 return -1;
688         }
689         fds = alloca(njbuses * sizeof * fds);
690         assert(fds != NULL);
691
692         r = jbus_dispatch_multiple(jbuses, njbuses, maxcount);
693         n = jbus_fill_pollfds(jbuses, njbuses, fds);
694         s = poll(fds, n, toms);
695         if (s < 0)
696                 return r ? r : s;
697         n = jbus_dispatch_pollfds(jbuses, njbuses, fds, maxcount - r);
698         return n >= 0 ? r + n : r ? r : n;
699 }
700
701 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
702 {
703         int r = jbus_read_write_dispatch_multiple(&jbus, 1, toms, 1000);
704         return r < 0 ? r : 0;
705 }
706
707 int jbus_call_ss(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, const char*, void*), void *data)
708 {
709         return call(jbus, method, query, onresp, NULL, data);
710 }
711
712 int jbus_call_sj(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, struct json_object*, void*), void *data)
713 {
714         return call(jbus, method, query, NULL, onresp, data);
715 }
716
717 int jbus_call_js(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, const char*, void*), void *data)
718 {
719         const char *str = json_object_to_json_string(query);
720         if (str == NULL) {
721                 errno = ENOMEM;
722                 return -1;
723         }
724         return call(jbus, method, str, onresp, NULL, data);
725 }
726
727 int jbus_call_jj(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, struct json_object*, void*), void *data)
728 {
729         const char *str = json_object_to_json_string(query);
730         if (str == NULL) {
731                 errno = ENOMEM;
732                 return -1;
733         }
734         return call(jbus, method, str, NULL, onresp, data);
735 }
736
737 char *jbus_call_ss_sync(struct jbus *jbus, const char *method, const char *query)
738 {
739         struct respsync synchro;
740         synchro.value = NULL;
741         synchro.replied = jbus_call_ss(jbus, method, query, sync_of_replies, &synchro);
742         while (!synchro.replied && !jbus_read_write_dispatch(jbus, -1));
743         return synchro.value;
744 }
745
746 struct json_object *jbus_call_sj_sync(struct jbus *jbus, const char *method, const char *query)
747 {
748         struct json_object *obj;
749         char *str = jbus_call_ss_sync(jbus, method, query);
750         if (str == NULL)
751                 obj = NULL;
752         else {
753                 obj = json_tokener_parse(str);
754                 free(str);
755         }
756         return obj;
757 }
758
759 char *jbus_call_js_sync(struct jbus *jbus, const char *method, struct json_object *query)
760 {
761         const char *str = json_object_to_json_string(query);
762         if (str == NULL) {
763                 errno = ENOMEM;
764                 return NULL;
765         }
766         return jbus_call_ss_sync(jbus, method, str);
767 }
768
769 struct json_object *jbus_call_jj_sync(struct jbus *jbus, const char *method, struct json_object *query)
770 {
771         const char *str = json_object_to_json_string(query);
772         if (str == NULL) {
773                 errno = ENOMEM;
774                 return NULL;
775         }
776         return jbus_call_sj_sync(jbus, method, str);
777 }
778
779 int jbus_on_signal_s(struct jbus *jbus, const char *name, void (*onsig)(const char *))
780 {
781         return add_signal(jbus, name, onsig, NULL);
782 }
783
784 int jbus_on_signal_j(struct jbus *jbus, const char *name, void (*onsig)(struct json_object *))
785 {
786         return add_signal(jbus, name, NULL, onsig);
787 }
788
789 /************************** FEW LITTLE TESTS *****************************************/
790
791 #ifdef SERVER
792 #include <stdio.h>
793 #include <unistd.h>
794 struct jbus *jbus;
795 void ping(struct jreq *jreq, struct json_object *request)
796 {
797 printf("ping(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(request));
798         jbus_reply_j(jreq, request);
799         json_object_put(request);       
800 }
801 void incr(struct jreq *jreq, struct json_object *request)
802 {
803         static int counter = 0;
804         struct json_object *res = json_object_new_int(++counter);
805 printf("incr(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(res));
806         jbus_reply_j(jreq, res);
807 jbus_send_signal_j(jbus, "incremented", res);
808         json_object_put(res);
809         json_object_put(request);
810 }
811 int main()
812 {
813         int s1, s2, s3;
814         jbus = create_jbus(1, "/bzh/iot/jdbus");
815         s1 = jbus_add_service_j(jbus, "ping", ping);
816         s2 = jbus_add_service_j(jbus, "incr", incr);
817         s3 = jbus_start_serving(jbus);
818         printf("started %d %d %d\n", s1, s2, s3);
819         while (!jbus_read_write_dispatch (jbus, -1));
820 }
821 #endif
822 #ifdef CLIENT
823 #include <stdio.h>
824 #include <unistd.h>
825 struct jbus *jbus;
826 void onresp(int status, struct json_object *response, void *data)
827 {
828         printf("resp: %d, %s, %s\n",status,(char*)data,json_object_to_json_string(response));
829         json_object_put(response);
830 }
831 void signaled(const char *data)
832 {
833         printf("signaled with {%s}\n", data);
834 }
835 int main()
836 {
837         int i = 10;
838         jbus = create_jbus(1, "/bzh/iot/jdbus");
839         jbus_on_signal_s(jbus, "incremented", signaled);
840         while(i--) {
841                 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}", onresp, "ping");
842                 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp, "incr");
843                 jbus_read_write_dispatch (jbus, 1);
844         }
845         printf("[[[%s]]]\n", jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
846         while (!jbus_read_write_dispatch (jbus, -1));
847 }
848 #endif
849
850
851
852
853
854
855
856