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