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