utils-jbus: handles EINTR
[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         for(;;) {
695                 s = poll(fds, n, toms);
696                 if (s >= 0)
697                         break;
698                 if (errno != EINTR)
699                         return r ? r : s;
700                 toms = 0;
701         }
702         n = jbus_dispatch_pollfds(jbuses, njbuses, fds, maxcount - r);
703         return n >= 0 ? r + n : r ? r : n;
704 }
705
706 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
707 {
708         int r = jbus_read_write_dispatch_multiple(&jbus, 1, toms, 1000);
709         return r < 0 ? r : 0;
710 }
711
712 int jbus_call_ss(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, const char*, void*), void *data)
713 {
714         return call(jbus, method, query, onresp, NULL, data);
715 }
716
717 int jbus_call_sj(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, struct json_object*, void*), void *data)
718 {
719         return call(jbus, method, query, NULL, onresp, data);
720 }
721
722 int jbus_call_js(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, const char*, void*), void *data)
723 {
724         const char *str = json_object_to_json_string(query);
725         if (str == NULL) {
726                 errno = ENOMEM;
727                 return -1;
728         }
729         return call(jbus, method, str, onresp, NULL, data);
730 }
731
732 int jbus_call_jj(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, struct json_object*, void*), void *data)
733 {
734         const char *str = json_object_to_json_string(query);
735         if (str == NULL) {
736                 errno = ENOMEM;
737                 return -1;
738         }
739         return call(jbus, method, str, NULL, onresp, data);
740 }
741
742 char *jbus_call_ss_sync(struct jbus *jbus, const char *method, const char *query)
743 {
744         struct respsync synchro;
745         synchro.value = NULL;
746         synchro.replied = jbus_call_ss(jbus, method, query, sync_of_replies, &synchro);
747         while (!synchro.replied && !jbus_read_write_dispatch(jbus, -1));
748         return synchro.value;
749 }
750
751 struct json_object *jbus_call_sj_sync(struct jbus *jbus, const char *method, const char *query)
752 {
753         struct json_object *obj;
754         char *str = jbus_call_ss_sync(jbus, method, query);
755         if (str == NULL)
756                 obj = NULL;
757         else {
758                 obj = json_tokener_parse(str);
759                 free(str);
760         }
761         return obj;
762 }
763
764 char *jbus_call_js_sync(struct jbus *jbus, const char *method, struct json_object *query)
765 {
766         const char *str = json_object_to_json_string(query);
767         if (str == NULL) {
768                 errno = ENOMEM;
769                 return NULL;
770         }
771         return jbus_call_ss_sync(jbus, method, str);
772 }
773
774 struct json_object *jbus_call_jj_sync(struct jbus *jbus, const char *method, struct json_object *query)
775 {
776         const char *str = json_object_to_json_string(query);
777         if (str == NULL) {
778                 errno = ENOMEM;
779                 return NULL;
780         }
781         return jbus_call_sj_sync(jbus, method, str);
782 }
783
784 int jbus_on_signal_s(struct jbus *jbus, const char *name, void (*onsig)(const char *))
785 {
786         return add_signal(jbus, name, onsig, NULL);
787 }
788
789 int jbus_on_signal_j(struct jbus *jbus, const char *name, void (*onsig)(struct json_object *))
790 {
791         return add_signal(jbus, name, NULL, onsig);
792 }
793
794 /************************** FEW LITTLE TESTS *****************************************/
795
796 #ifdef SERVER
797 #include <stdio.h>
798 #include <unistd.h>
799 struct jbus *jbus;
800 void ping(struct jreq *jreq, struct json_object *request)
801 {
802 printf("ping(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(request));
803         jbus_reply_j(jreq, request);
804         json_object_put(request);       
805 }
806 void incr(struct jreq *jreq, struct json_object *request)
807 {
808         static int counter = 0;
809         struct json_object *res = json_object_new_int(++counter);
810 printf("incr(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(res));
811         jbus_reply_j(jreq, res);
812 jbus_send_signal_j(jbus, "incremented", res);
813         json_object_put(res);
814         json_object_put(request);
815 }
816 int main()
817 {
818         int s1, s2, s3;
819         jbus = create_jbus(1, "/bzh/iot/jdbus");
820         s1 = jbus_add_service_j(jbus, "ping", ping);
821         s2 = jbus_add_service_j(jbus, "incr", incr);
822         s3 = jbus_start_serving(jbus);
823         printf("started %d %d %d\n", s1, s2, s3);
824         while (!jbus_read_write_dispatch (jbus, -1));
825 }
826 #endif
827 #ifdef CLIENT
828 #include <stdio.h>
829 #include <unistd.h>
830 struct jbus *jbus;
831 void onresp(int status, struct json_object *response, void *data)
832 {
833         printf("resp: %d, %s, %s\n",status,(char*)data,json_object_to_json_string(response));
834         json_object_put(response);
835 }
836 void signaled(const char *data)
837 {
838         printf("signaled with {%s}\n", data);
839 }
840 int main()
841 {
842         int i = 10;
843         jbus = create_jbus(1, "/bzh/iot/jdbus");
844         jbus_on_signal_s(jbus, "incremented", signaled);
845         while(i--) {
846                 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}", onresp, "ping");
847                 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp, "incr");
848                 jbus_read_write_dispatch (jbus, 1);
849         }
850         printf("[[[%s]]]\n", jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
851         while (!jbus_read_write_dispatch (jbus, -1));
852 }
853 #endif
854
855
856
857
858
859
860
861