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