cmake: improves error detection
[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         short 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         short wf;
411
412         flags = dbus_watch_get_flags(watch);
413         wf = jbus->watchflags;
414         if (dbus_watch_get_enabled(watch)) {
415                 if (flags & DBUS_WATCH_READABLE)
416                         wf |= POLLIN;
417                 if (flags & DBUS_WATCH_WRITABLE)
418                         wf |= POLLOUT;
419         }
420         else {
421                 if (flags & DBUS_WATCH_READABLE)
422                         wf &= ~POLLIN;
423                 if (flags & DBUS_WATCH_WRITABLE)
424                         wf &= ~POLLOUT;
425         }
426         jbus->watchflags = wf;
427 }
428
429 static void watchdel(DBusWatch *watch, void *data)
430 {
431         struct jbus *jbus = data;
432
433         assert(jbus->watchnr > 0);
434         assert(jbus->watchfd == dbus_watch_get_unix_fd(watch));
435         jbus->watchnr--;
436 }
437
438 static void watchtoggle(DBusWatch *watch, void *data)
439 {
440         struct jbus *jbus = data;
441
442         assert(jbus->watchnr > 0);
443         assert(jbus->watchfd == dbus_watch_get_unix_fd(watch));
444         watchset(watch, jbus);
445 }
446
447 static dbus_bool_t watchadd(DBusWatch *watch, void *data)
448 {
449         struct jbus *jbus = data;
450         if (jbus->watchnr == 0) {
451                 jbus->watchfd = dbus_watch_get_unix_fd(watch);
452                 jbus->watchflags = 0;
453         }
454         else if (jbus->watchfd != dbus_watch_get_unix_fd(watch))
455                 return FALSE;
456         jbus->watchnr++;
457         watchset(watch, jbus);
458         return TRUE;
459 }
460
461 /************************** MAIN FUNCTIONS *****************************************/
462
463 struct jbus *create_jbus_system(const char *path)
464 {
465         return create_jbus(path, 0);
466 }
467
468 struct jbus *create_jbus_session(const char *path)
469 {
470         return create_jbus(path, 1);
471 }
472
473 struct jbus *create_jbus(const char *path, int session)
474 {
475         struct jbus *jbus;
476         char *name;
477
478         /* create the context and connect */
479         jbus = calloc(1, sizeof * jbus);
480         if (jbus == NULL) {
481                 errno = ENOMEM;
482                 goto error;
483         }
484         jbus->refcount = 1;
485         jbus->tokener = json_tokener_new_ex(MAX_JSON_DEPTH);
486         if (jbus->tokener == NULL) {
487                 errno = ENOMEM;
488                 goto error2;
489         }
490         jbus->path = strdup(path);
491         if (jbus->path == NULL) {
492                 errno = ENOMEM;
493                 goto error2;
494         }
495         while(*path == '/') path++;
496         jbus->name = name = strdup(path);
497         if (name == NULL) {
498                 errno = ENOMEM;
499                 goto error2;
500         }
501         while(*name) {
502                 if (*name == '/')
503                         *name = '.';
504                 name++;
505         }
506         name--;
507         while (name >= jbus->name && *name == '.')
508                 *name-- = 0;
509         if (!*jbus->name) {
510                 errno = EINVAL;
511                 goto error2;
512         }
513
514         /* connect */
515         jbus->connection = dbus_bus_get(session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, NULL);
516         if (jbus->connection == NULL
517         || !dbus_connection_add_filter(jbus->connection, incoming, jbus, NULL)
518         || !dbus_connection_set_watch_functions(jbus->connection, watchadd, watchdel, watchtoggle, jbus, NULL))
519                 goto error2;
520
521         return jbus;
522
523 error2:
524         jbus_unref(jbus);
525 error:
526         return NULL;
527 }
528
529 void jbus_addref(struct jbus *jbus)
530 {
531         jbus->refcount++;
532 }
533
534 void jbus_unref(struct jbus *jbus)
535 {
536         struct jservice *srv;
537         if (!--jbus->refcount) {
538                 if (jbus->connection != NULL)
539                         dbus_connection_unref(jbus->connection);
540                 while((srv = jbus->services) != NULL) {
541                         jbus->services = srv->next;
542                         free(srv->method);
543                         free(srv);
544                 }
545                 if (jbus->tokener != NULL)
546                         json_tokener_free(jbus->tokener);
547                 free(jbus->name);
548                 free(jbus->path);
549                 free(jbus);
550         }
551 }
552
553 int jbus_reply_error_s(struct jreq *jreq, const char *error)
554 {
555         int rc = -1;
556         DBusMessage *message;
557
558         message = dbus_message_new_error(jreq->request, DBUS_ERROR_FAILED, error);
559         if (message == NULL)
560                 errno = ENOMEM;
561         else {
562                 if (dbus_connection_send(jreq->connection, message, NULL))
563                         rc = 0;
564                 dbus_message_unref(message);
565         }
566         free_jreq(jreq);
567         return rc;
568 }
569
570 int jbus_reply_error_j(struct jreq *jreq, struct json_object *reply)
571 {
572         const char *str = json_object_to_json_string(reply);
573         return str ? jbus_reply_error_s(jreq, str) : reply_out_of_memory(jreq);
574 }
575
576 int jbus_reply_s(struct jreq *jreq, const char *reply)
577 {
578         int rc = -1;
579         DBusMessage *message;
580
581         message = dbus_message_new_method_return(jreq->request);
582         if (message == NULL)
583                 return reply_out_of_memory(jreq);
584
585         if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
586                 dbus_message_unref(message);
587                 return reply_out_of_memory(jreq);
588         }
589
590         if (dbus_connection_send(jreq->connection, message, NULL))
591                 rc = 0;
592         dbus_message_unref(message);
593         free_jreq(jreq);
594         return rc;
595 }
596
597 int jbus_reply_j(struct jreq *jreq, struct json_object *reply)
598 {
599         const char *str = json_object_to_json_string(reply);
600         return str ? jbus_reply_s(jreq, str) : reply_out_of_memory(jreq);
601 }
602
603 int jbus_send_signal_s(struct jbus *jbus, const char *name, const char *content)
604 {
605         int rc = -1;
606         DBusMessage *message;
607
608         message = dbus_message_new_signal(jbus->path, jbus->name, name);
609         if (message == NULL)
610                 goto error;
611
612         if (!dbus_message_set_sender(message, jbus->name)
613         ||  !dbus_message_append_args(message, DBUS_TYPE_STRING, &content, DBUS_TYPE_INVALID)) {
614                 dbus_message_unref(message);
615                 goto error;
616         }
617
618         if (dbus_connection_send(jbus->connection, message, NULL))
619                 rc = 0;
620         dbus_message_unref(message);
621         return rc;
622
623 error:
624         errno = ENOMEM;
625         return -1;
626 }
627
628 int jbus_send_signal_j(struct jbus *jbus, const char *name, struct json_object *content)
629 {
630         const char *str = json_object_to_json_string(content);
631         if (str == NULL) {
632                 errno = ENOMEM;
633                 return -1;
634         }
635         return jbus_send_signal_s(jbus, name, str);
636 }
637
638 int jbus_add_service_s(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *, const char *, void *), void *data)
639 {
640         return add_service(jbus, method, oncall, NULL, data);
641 }
642
643 int jbus_add_service_j(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *, struct json_object *, void *), void *data)
644 {
645         return add_service(jbus, method, NULL, oncall, data);
646 }
647
648 int jbus_start_serving(struct jbus *jbus)
649 {
650         int status = dbus_bus_request_name(jbus->connection, jbus->name, DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
651         switch (status) {
652         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
653         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
654                 return 0;
655         case DBUS_REQUEST_NAME_REPLY_EXISTS:
656         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
657         default:
658                 errno = EADDRINUSE;
659                 return -1;
660         }
661 }
662
663 int jbus_fill_pollfds(struct jbus **jbuses, int njbuses, struct pollfd *fds)
664 {
665         int i, r;
666
667         for (r = i = 0 ; i < njbuses ; i++) {
668                 if (jbuses[i]->watchnr) {
669                         fds[r].fd = jbuses[i]->watchfd;
670                         fds[r].events = jbuses[i]->watchflags;
671                         r++;
672                 }
673         }
674         return r;
675 }
676
677 int jbus_dispatch_pollfds(struct jbus **jbuses, int njbuses, struct pollfd *fds, int maxcount)
678 {
679         int i, r, n;
680         DBusDispatchStatus sts;
681
682         for (r = n = i = 0 ; i < njbuses && n < maxcount ; i++) {
683                 if (jbuses[i]->watchnr && fds[r].fd == jbuses[i]->watchfd) {
684                         if (fds[r].revents) {
685                                 dbus_connection_read_write(jbuses[i]->connection, 0);
686                                 sts = dbus_connection_get_dispatch_status(jbuses[i]->connection);
687                                 while(sts == DBUS_DISPATCH_DATA_REMAINS &&  n < maxcount) {
688                                         sts = dbus_connection_dispatch(jbuses[i]->connection);
689                                         n++;
690                                 }
691                         }
692                         r++;
693                 }
694         }
695         return n;
696 }
697
698 int jbus_dispatch_multiple(struct jbus **jbuses, int njbuses, int maxcount)
699 {
700         int i, r;
701         DBusDispatchStatus sts;
702
703         for (i = r = 0 ; i < njbuses && r < maxcount ; i++) {
704                 dbus_connection_read_write(jbuses[i]->connection, 0);
705                 sts = dbus_connection_get_dispatch_status(jbuses[i]->connection);
706                 while(sts == DBUS_DISPATCH_DATA_REMAINS &&  r < maxcount) {
707                         sts = dbus_connection_dispatch(jbuses[i]->connection);
708                         r++;
709                 }
710         }
711         return r;
712 }
713
714 int jbus_read_write_dispatch_multiple(struct jbus **jbuses, int njbuses, int toms, int maxcount)
715 {
716         int n, r, s;
717         struct pollfd *fds;
718
719         if (njbuses < 0 || njbuses > 100) {
720                 errno = EINVAL;
721                 return -1;
722         }
723         fds = alloca((unsigned)njbuses * sizeof * fds);
724         assert(fds != NULL);
725
726         r = jbus_dispatch_multiple(jbuses, njbuses, maxcount);
727         if (r)
728                 return r;
729         n = jbus_fill_pollfds(jbuses, njbuses, fds);
730         for(;;) {
731                 s = poll(fds, (nfds_t)n, toms);
732                 if (s >= 0)
733                         break;
734                 if (errno != EINTR)
735                         return r ? r : s;
736                 toms = 0;
737         }
738         n = jbus_dispatch_pollfds(jbuses, njbuses, fds, maxcount - r);
739         return n >= 0 ? r + n : r ? r : n;
740 }
741
742 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
743 {
744         int r = jbus_read_write_dispatch_multiple(&jbus, 1, toms, 1000);
745         return r < 0 ? r : 0;
746 }
747
748 int jbus_call_ss(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, const char*, void*), void *data)
749 {
750         return call(jbus, method, query, onresp, NULL, data);
751 }
752
753 int jbus_call_sj(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, struct json_object*, void*), void *data)
754 {
755         return call(jbus, method, query, NULL, onresp, data);
756 }
757
758 int jbus_call_js(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, const char*, void*), void *data)
759 {
760         const char *str = json_object_to_json_string(query);
761         if (str == NULL) {
762                 errno = ENOMEM;
763                 return -1;
764         }
765         return call(jbus, method, str, onresp, NULL, data);
766 }
767
768 int jbus_call_jj(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, struct json_object*, void*), void *data)
769 {
770         const char *str = json_object_to_json_string(query);
771         if (str == NULL) {
772                 errno = ENOMEM;
773                 return -1;
774         }
775         return call(jbus, method, str, NULL, onresp, data);
776 }
777
778 char *jbus_call_ss_sync(struct jbus *jbus, const char *method, const char *query)
779 {
780         struct respsync synchro;
781         synchro.value = NULL;
782         synchro.replied = jbus_call_ss(jbus, method, query, sync_of_replies, &synchro);
783         while (!synchro.replied && !jbus_read_write_dispatch(jbus, -1));
784         return synchro.value;
785 }
786
787 struct json_object *jbus_call_sj_sync(struct jbus *jbus, const char *method, const char *query)
788 {
789         struct json_object *obj;
790         char *str = jbus_call_ss_sync(jbus, method, query);
791         if (str == NULL)
792                 obj = NULL;
793         else {
794                 parse(jbus, str, &obj);
795                 free(str);
796         }
797         return obj;
798 }
799
800 char *jbus_call_js_sync(struct jbus *jbus, const char *method, struct json_object *query)
801 {
802         const char *str = json_object_to_json_string(query);
803         if (str == NULL) {
804                 errno = ENOMEM;
805                 return NULL;
806         }
807         return jbus_call_ss_sync(jbus, method, str);
808 }
809
810 struct json_object *jbus_call_jj_sync(struct jbus *jbus, const char *method, struct json_object *query)
811 {
812         const char *str = json_object_to_json_string(query);
813         if (str == NULL) {
814                 errno = ENOMEM;
815                 return NULL;
816         }
817         return jbus_call_sj_sync(jbus, method, str);
818 }
819
820 int jbus_on_signal_s(struct jbus *jbus, const char *name, void (*onsig)(const char *, void *), void *data)
821 {
822         return add_signal(jbus, name, onsig, NULL, data);
823 }
824
825 int jbus_on_signal_j(struct jbus *jbus, const char *name, void (*onsig)(struct json_object *, void *), void *data)
826 {
827         return add_signal(jbus, name, NULL, onsig, data);
828 }
829
830 /************************** FEW LITTLE TESTS *****************************************/
831
832 #ifdef SERVER
833 #include <stdio.h>
834 #include <unistd.h>
835 struct jbus *jbus;
836 void ping(struct jreq *jreq, struct json_object *request, void *unused)
837 {
838 printf("ping(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(request));
839         jbus_reply_j(jreq, request);
840         json_object_put(request);       
841 }
842 void incr(struct jreq *jreq, struct json_object *request, void *unused)
843 {
844         static int counter = 0;
845         struct json_object *res = json_object_new_int(++counter);
846 printf("incr(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(res));
847         jbus_reply_j(jreq, res);
848 jbus_send_signal_j(jbus, "incremented", res);
849         json_object_put(res);
850         json_object_put(request);
851 }
852 int main()
853 {
854         int s1, s2, s3;
855         jbus = create_jbus(1, "/bzh/iot/jdbus");
856         s1 = jbus_add_service_j(jbus, "ping", ping, NULL);
857         s2 = jbus_add_service_j(jbus, "incr", incr, NULL);
858         s3 = jbus_start_serving(jbus);
859         printf("started %d %d %d\n", s1, s2, s3);
860         while (!jbus_read_write_dispatch (jbus, -1));
861 }
862 #endif
863 #ifdef CLIENT
864 #include <stdio.h>
865 #include <unistd.h>
866 struct jbus *jbus;
867 void onresp(int status, struct json_object *response, void *data)
868 {
869         printf("resp: %d, %s, %s\n",status,(char*)data,json_object_to_json_string(response));
870         json_object_put(response);
871 }
872 void signaled(const char *data)
873 {
874         printf("signaled with {%s}\n", data);
875 }
876 int main()
877 {
878         int i = 10;
879         jbus = create_jbus(1, "/bzh/iot/jdbus");
880         jbus_on_signal_s(jbus, "incremented", signaled);
881         while(i--) {
882                 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}", onresp, "ping");
883                 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp, "incr");
884                 jbus_read_write_dispatch (jbus, 1);
885         }
886         printf("[[[%s]]]\n", jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
887         while (!jbus_read_write_dispatch (jbus, -1));
888 }
889 #endif
890
891
892
893
894
895
896
897