use upoll for event loop
[src/app-framework-binder.git] / plugins / afm-main-plugin / 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
29 #include "utils-sbus.h"
30 #include "utils-jbus.h"
31
32 /*
33  * max depth of json messages
34  */
35 #define MAX_JSON_DEPTH 10
36
37 /*
38  * errors messages generated by jbus
39  */
40 static const char out_of_memory_string[] = "out of memory";
41
42 /*
43  * structure for services
44  */
45 struct jservice {
46         struct jservice *next;  /* link to the next service */
47         char *method;           /* method name for the service */
48         void (*oncall_s) (struct sbusmsg *, const char *, void *);
49                                 /* string callback */
50         void (*oncall_j) (struct sbusmsg *, struct json_object *, void *);
51                                 /* json callback */
52         void *data;             /* closure data for the callbacks */
53 };
54
55 /*
56  * structure for signals
57  */
58 struct jsignal {
59         struct jsignal *next;   /* link to the next signal */
60         char *name;             /* name of the expected signal */
61         void (*onsignal_s) (const char *, void *);
62                                 /* string callback */
63         void (*onsignal_j) (struct json_object *, void *);
64                                 /* json callback */
65         void *data;             /* closure data for the callbacks */
66 };
67
68 /*
69  * structure for asynchronous requests
70  */
71 struct jrespw {
72         struct jbus *jbus;
73         void (*onresp) (int, struct json_object *, void *);
74                                 /* json callback */
75         void *data;             /* closure data for the callbacks */
76 };
77
78 /*
79  * structure for handling either client or server jbus on dbus
80  */
81 struct jbus {
82         int refcount;                   /* referenced how many time */
83         struct sbus *sbus;
84         struct sbus_service *sservice;
85         struct sbus_signal *ssignal;
86         struct json_tokener *tokener;   /* string to json tokenizer */
87         struct jservice *services;      /* first service */
88         struct jsignal *signals;        /* first signal */
89         char *path;                     /* dbus path */
90         char *name;                     /* dbus name */
91 };
92
93 /*********************** STATIC COMMON METHODS *****************/
94
95 /*
96  * Replies the error "out of memory".
97  * This function is intended to be used in services when an
98  * allocation fails. Thus, it set errno to ENOMEM and
99  * returns -1.
100  */
101 static inline int reply_out_of_memory(struct sbusmsg *smsg)
102 {
103         jbus_reply_error_s(smsg, out_of_memory_string);
104         errno = ENOMEM;
105         return -1;
106 }
107
108 /*
109  * Parses the json-string 'msg' to create a json object stored
110  * in 'obj'. It uses the tokener of 'jbus'. This is a small
111  * improvement to avoid recreation of tokeners.
112  *
113  * Returns 1 in case of success and put the result in *'obj'.
114  * Returns 0 in case of error and put NULL in *'obj'.
115  */
116 static int jparse(struct jbus *jbus, const char *msg, struct json_object **obj)
117 {
118         json_tokener_reset(jbus->tokener);
119         *obj = json_tokener_parse_ex(jbus->tokener, msg, -1);
120         if (json_tokener_get_error(jbus->tokener) == json_tokener_success)
121                 return 1;
122         json_object_put(*obj);
123         *obj = NULL;
124         return 0;
125 }
126
127 static void on_service_call(struct sbusmsg *smsg, const char *content, struct jbus *jbus)
128 {
129         struct jservice *service;
130         const char *member;
131         struct json_object *obj;
132
133         member = sbus_member(smsg);
134         service = jbus->services;
135         while (service != NULL) {
136                 if (!strcmp(service->method, member)) {
137                         if (service->oncall_s)
138                                 service->oncall_s(smsg, content, service->data);
139                         else if (service->oncall_j) {
140                                 if (!jparse(jbus, content, &obj))
141                                         obj = json_object_new_string(content);
142                                 service->oncall_j(smsg, obj, service->data);
143                                 json_object_put(obj);
144                         }
145                 }
146                 service = service->next;
147         }
148 }
149
150 /*
151  * Adds to 'jbus' a service of name 'method'. The service is
152  * performed by one of the callback 'oncall_s' (for string) or
153  * 'oncall_j' (for json) that will receive the request and the
154  * closure parameter 'data'.
155  *
156  * returns 0 in case of success or -1 in case of error (ENOMEM).
157  */
158 static int add_service(
159                 struct jbus *jbus,
160                 const char *method,
161                 void (*oncall_s) (struct sbusmsg *, const char *, void *),
162                 void (*oncall_j) (struct sbusmsg *, struct json_object *, void *),
163                 void *data)
164 {
165         struct jservice *srv;
166
167         /* connection of the service */
168         if (jbus->sservice == NULL) {
169                 jbus->sservice = sbus_add_service(jbus->sbus,
170                                 NULL, jbus->path, jbus->name, NULL,
171                                 (void*)on_service_call, jbus);
172                 if (jbus->sservice == NULL)
173                         goto error;
174         }
175
176         /* allocation */
177         srv = malloc(sizeof *srv);
178         if (srv == NULL) {
179                 errno = ENOMEM;
180                 goto error;
181         }
182         srv->method = strdup(method);
183         if (!srv->method) {
184                 errno = ENOMEM;
185                 goto error2;
186         }
187
188         /* record the service */
189         srv->oncall_s = oncall_s;
190         srv->oncall_j = oncall_j;
191         srv->data = data;
192         srv->next = jbus->services;
193         jbus->services = srv;
194
195         return 0;
196
197  error2:
198         free(srv);
199  error:
200         errno = ENOMEM;
201         return -1;
202 }
203
204 static void on_signal_event(const struct sbusmsg *smsg, const char *content, struct jbus *jbus)
205 {
206         struct jsignal *signal;
207         const char *member;
208         struct json_object *obj;
209
210         member = sbus_member(smsg);
211         signal = jbus->signals;
212         while (signal != NULL) {
213                 if (!strcmp(signal->name, member)) {
214                         if (signal->onsignal_s)
215                                 signal->onsignal_s(content, signal->data);
216                         else if (signal->onsignal_j) {
217                                 if (!jparse(jbus, content, &obj))
218                                         obj = json_object_new_string(content);
219                                 signal->onsignal_j(obj, signal->data);
220                                 json_object_put(obj);
221                         }
222                 }
223                 signal = signal->next;
224         }
225 }
226
227 /*
228  * Adds to 'jbus' a handler for the signal of 'name' emmited by
229  * the sender and the interface that 'jbus' is linked to.
230  * The signal is handled by one of the callback 'onsignal_s'
231  * (for string) or 'onsignal_j' (for json) that will receive
232  * parameters associated with the signal and the closure
233  * parameter 'data'.
234  *
235  * returns 0 in case of success or -1 in case of error (ENOMEM).
236  */
237 static int add_signal(
238                 struct jbus *jbus,
239                 const char *name,
240                 void (*onsignal_s) (const char *, void *),
241                 void (*onsignal_j) (struct json_object *, void *),
242                 void *data)
243 {
244         struct jsignal *sig;
245
246         /* connection of the signal */
247         if (jbus->ssignal == NULL) {
248                 jbus->ssignal = sbus_add_signal(jbus->sbus,
249                                 NULL, jbus->path, jbus->name, NULL,
250                                 (void*)on_signal_event, jbus);
251                 if (jbus->ssignal == NULL)
252                         goto error;
253         }
254
255         /* allocation */
256         sig = malloc(sizeof *sig);
257         if (sig == NULL)
258                 goto error;
259         sig->name = strdup(name);
260         if (!sig->name)
261                 goto error2;
262
263         /* record the signal */
264         sig->onsignal_s = onsignal_s;
265         sig->onsignal_j = onsignal_j;
266         sig->data = data;
267         sig->next = jbus->signals;
268         jbus->signals = sig;
269
270         return 0;
271
272  error2:
273         free(sig);
274  error:
275         errno = ENOMEM;
276         return -1;
277 }
278
279 static void on_reply_j(int status, const char *reply, struct jrespw *jrespw)
280 {
281         struct json_object *obj;
282
283         if (!jparse(jrespw->jbus, reply, &obj))
284                 obj = json_object_new_string(reply);
285         jrespw->onresp(status, obj, jrespw->data);
286         json_object_put(obj);
287         free(jrespw);
288 }
289
290 /*
291  * Creates a message for 'method' with one string parameter being 'query'
292  * and sends it to the destination, object and interface linked to 'jbus'.
293  *
294  * Adds to 'jbus' the response handler defined by the callbacks 'onresp_s'
295  * (for string) and 'onresp_j' (for json) and the closure parameter 'data'.
296  *
297  * Returns 0 in case of success or -1 in case of error.
298  */
299 static int call(
300                 struct jbus *jbus,
301                 const char *method,
302                 const char *query,
303                 void (*onresp_s) (int, const char *, void *),
304                 void (*onresp_j) (int, struct json_object *, void *),
305                 void *data)
306 {
307         struct jrespw *resp;
308
309         if (onresp_j == NULL)
310                 return sbus_call(jbus->sbus, jbus->name, jbus->path, jbus->name,
311                                 method, query, onresp_s, data);
312
313         /* allocates the response structure */
314         resp = malloc(sizeof *resp);
315         if (resp == NULL)
316                 goto error;
317
318         /* fulfill the response structure */
319         resp->jbus = jbus;
320         resp->onresp = onresp_j;
321         resp->data = data;
322         if (sbus_call(jbus->sbus, jbus->name, jbus->path, jbus->name,
323                                 method, query, (void*)on_reply_j, resp))
324                 goto error2;
325
326         return 0;
327
328  error2:
329         free(resp);
330  error:
331         errno = ENOMEM;
332         return -1;
333 }
334
335 /********************* MAIN FUNCTIONS *****************************************/
336
337 /*
338  * Creates a 'jbus' bound the 'path' and it derived names and linked
339  * either to the DBUS SYSTEM when 'session' is nul or to the DBUS SESSION
340  * if 'session' is not nul.
341  *
342  * The parameter 'path' is intended to be the path of a DBUS single object.
343  * Single means that it exists only one instance of the object on the
344  * given bus. That path implies 2 derived DBUS names:
345  *   1. the destination name of the program that handles the object
346  *   2. the interface name of the object
347  * These names are derived by removing the heading slash (/) and
348  * by replacing all occurences of slashes by dots.
349  * For example, passing path = /a/b/c means that the object /a/b/c is
350  * handled by the destination a.b.c and replies to the interface a.b.c
351  *
352  * Returns the created jbus or NULL in case of error.
353  */
354 struct jbus *create_jbus(struct sbus *sbus, const char *path)
355 {
356         struct jbus *jbus;
357         char *name;
358
359         /* create the jbus object */
360         jbus = calloc(1, sizeof *jbus);
361         if (jbus == NULL) {
362                 errno = ENOMEM;
363                 goto error;
364         }
365         jbus->refcount = 1;
366
367         /* create the tokener */
368         jbus->tokener = json_tokener_new_ex(MAX_JSON_DEPTH);
369         if (jbus->tokener == NULL) {
370                 errno = ENOMEM;
371                 goto error2;
372         }
373
374         /* records the path */
375         jbus->path = strdup(path);
376         if (jbus->path == NULL) {
377                 errno = ENOMEM;
378                 goto error2;
379         }
380
381         /* makes the name from the path */
382         while (*path == '/')
383                 path++;
384         jbus->name = name = strdup(path);
385         if (name == NULL) {
386                 errno = ENOMEM;
387                 goto error2;
388         }
389         while (*name) {
390                 if (*name == '/')
391                         *name = '.';
392                 name++;
393         }
394         name--;
395         while (name >= jbus->name && *name == '.')
396                 *name-- = 0;
397         if (!*jbus->name) {
398                 errno = EINVAL;
399                 goto error2;
400         }
401
402         /* connect and init */
403         jbus->sbus = sbus;
404
405         return jbus;
406
407  error2:
408         jbus_unref(jbus);
409  error:
410         return NULL;
411 }
412
413 /*
414  * Adds one reference to 'jbus'.
415  */
416 void jbus_addref(struct jbus *jbus)
417 {
418         jbus->refcount++;
419 }
420
421 /*
422  * Removes one reference to 'jbus'. Destroys 'jbus' and it related
423  * data if the count of references decrease to zero.
424  */
425 void jbus_unref(struct jbus *jbus)
426 {
427         struct jservice *srv;
428         struct jsignal *sig;
429         if (!--jbus->refcount) {
430                 while ((srv = jbus->services) != NULL) {
431                         jbus->services = srv->next;
432                         free(srv->method);
433                         free(srv);
434                 }
435                 while ((sig = jbus->signals) != NULL) {
436                         jbus->signals = sig->next;
437                         free(sig->name);
438                         free(sig);
439                 }
440                 if (jbus->sservice != NULL)
441                         sbus_remove_service(jbus->sbus, jbus->sservice);
442                 if (jbus->ssignal != NULL)
443                         sbus_remove_signal(jbus->sbus, jbus->ssignal);
444                 if (jbus->tokener != NULL)
445                         json_tokener_free(jbus->tokener);
446                 sbus_unref(jbus->sbus);
447                 free(jbus->name);
448                 free(jbus->path);
449                 free(jbus);
450         }
451 }
452
453 /*
454  * Replies an error of string 'error' to the request handled by 'smsg'.
455  * Also destroys the request 'smsg' that must not be used later.
456  *
457  * Returns 0 in case of success or -1 in case of error.
458  */
459 int jbus_reply_error_s(struct sbusmsg *smsg, const char *error)
460 {
461         return sbus_reply_error(smsg, error);
462 }
463
464 /*
465  * Replies an error of json 'reply' to the request handled by 'smsg'.
466  * Also destroys the request 'smsg' that must not be used later.
467  *
468  * Returns 0 in case of success or -1 in case of error.
469  */
470 int jbus_reply_error_j(struct sbusmsg *smsg, struct json_object *reply)
471 {
472         const char *str = json_object_to_json_string(reply);
473         return str ? jbus_reply_error_s(smsg, str) : reply_out_of_memory(smsg);
474 }
475
476 /*
477  * Replies normally the string 'reply' to the request handled by 'smsg'.
478  * Also destroys the request 'smsg' that must not be used later.
479  *
480  * Returns 0 in case of success or -1 in case of error.
481  */
482 int jbus_reply_s(struct sbusmsg *smsg, const char *reply)
483 {
484         return sbus_reply(smsg, reply);
485 }
486
487 /*
488  * Replies normally the json 'reply' to the request handled by 'smsg'.
489  * Also destroys the request 'smsg' that must not be used later.
490  *
491  * Returns 0 in case of success or -1 in case of error.
492  */
493 int jbus_reply_j(struct sbusmsg *smsg, struct json_object *reply)
494 {
495         const char *str = json_object_to_json_string(reply);
496         return str ? jbus_reply_s(smsg, str) : reply_out_of_memory(smsg);
497 }
498
499 /*
500  * Sends from 'jbus' the signal of 'name' handling the string 'content'.
501  *
502  * Returns 0 in case of success or -1 in case of error.
503  */
504 int jbus_send_signal_s(struct jbus *jbus, const char *name, const char *content)
505 {
506         return sbus_send_signal(jbus->sbus, jbus->name, jbus->path, jbus->name, name, content);
507 }
508
509 /*
510  * Sends from 'jbus' the signal of 'name' handling the json 'content'.
511  *
512  * Returns 0 in case of success or -1 in case of error.
513  */
514 int jbus_send_signal_j(struct jbus *jbus, const char *name,
515                        struct json_object *content)
516 {
517         const char *str = json_object_to_json_string(content);
518         if (str == NULL) {
519                 errno = ENOMEM;
520                 return -1;
521         }
522         return jbus_send_signal_s(jbus, name, str);
523 }
524
525 /*
526  * Adds to 'jbus' a service handling calls to the 'method' using
527  * the "string" callback 'oncall' and the closure value 'data'.
528  *
529  * The callback 'oncall' is invoked for handling incoming method
530  * calls. It receives 3 parameters:
531  *   1. struct sbusmsg *: a handler to data to be used for replying
532  *   2. const char *: the received string
533  *   3. void *: the closure 'data' set by this function
534  *
535  * Returns 0 in case of success or -1 in case of error.
536  */
537 int jbus_add_service_s(
538                 struct jbus *jbus,
539                 const char *method,
540                 void (*oncall) (struct sbusmsg *, const char *, void *),
541                 void *data)
542 {
543         return add_service(jbus, method, oncall, NULL, data);
544 }
545
546 /*
547  * Adds to 'jbus' a service handling calls to the 'method' using
548  * the "json" callback 'oncall' and the closure value 'data'.
549  *
550  * The callback 'oncall' is invoked for handling incoming method
551  * calls. It receives 3 parameters:
552  *   1. struct sbusmsg *: a handler to data to be used for replying
553  *   2. struct json_object *: the received json
554  *   3. void *: the closure 'data' set by this function
555  *
556  * Returns 0 in case of success or -1 in case of error.
557  */
558 int jbus_add_service_j(
559                 struct jbus *jbus,
560                 const char *method,
561                 void (*oncall) (struct sbusmsg *, struct json_object *, void *),
562                 void *data)
563 {
564         return add_service(jbus, method, NULL, oncall, data);
565 }
566
567 /*
568  * Start to serve: activate services declared for 'jbus'.
569  * This function, in fact, declares 'jbus' as the receiver
570  * for calls to the destination derived from the path set at
571  * 'jbus' creation.
572  * It also allows 'jbus' to emit signals of that origin.
573  *
574  * Returns 0 in case of success or -1 in case of error.
575  */
576 int jbus_start_serving(struct jbus *jbus)
577 {
578         return sbus_add_name(jbus->sbus, jbus->name);
579 }
580
581 /*
582  * Asynchronous call to 'method' of 'jbus' passing the string 'query'.
583  * On response, the function 'onresp' is called with the returned string
584  * value and the closure 'data'.
585  * The function 'onresp' is invoked with 3 parameters:
586  *   1. int: 0 if no error or -1 if error.
587  *   2. const char *: the returned string (might be NULL if error)
588  *   3. void *: the closure 'data'
589  *
590  * Returns 0 in case of success or -1 in case of error.
591  */
592 int jbus_call_ss(
593                 struct jbus *jbus,
594                 const char *method,
595                 const char *query,
596                 void (*onresp) (int, const char *, void *),
597                 void *data)
598 {
599         return call(jbus, method, query, onresp, NULL, data);
600 }
601
602 /*
603  * Asynchronous call to 'method' of 'jbus' passing the string 'query'.
604  * On response, the function 'onresp' is called with the returned json
605  * value and the closure 'data'.
606  * The function 'onresp' is invoked with 3 parameters:
607  *   1. int: 0 if no error or -1 if error.
608  *   2. const char *: the returned json (might be NULL if error)
609  *   3. void *: the closure 'data'
610  *
611  * Returns 0 in case of success or -1 in case of error.
612  */
613 int jbus_call_sj(
614                 struct jbus *jbus,
615                 const char *method,
616                 const char *query,
617                 void (*onresp) (int, struct json_object *, void *),
618                 void *data)
619 {
620         return call(jbus, method, query, NULL, onresp, data);
621 }
622
623 /*
624  * Asynchronous call to 'method' of 'jbus' passing the json 'query'.
625  * On response, the function 'onresp' is called with the returned string
626  * value and the closure 'data'.
627  * The function 'onresp' is invoked with 3 parameters:
628  *   1. int: 0 if no error or -1 if error.
629  *   2. const char *: the returned string (might be NULL if error)
630  *   3. void *: the closure 'data'
631  *
632  * Returns 0 in case of success or -1 in case of error.
633  */
634 int jbus_call_js(
635                 struct jbus *jbus,
636                 const char *method,
637                 struct json_object *query,
638                 void (*onresp) (int, const char *, void *),
639                 void *data)
640 {
641         const char *str = json_object_to_json_string(query);
642         if (str == NULL) {
643                 errno = ENOMEM;
644                 return -1;
645         }
646         return call(jbus, method, str, onresp, NULL, data);
647 }
648
649 /*
650  * Asynchronous call to 'method' of 'jbus' passing the json 'query'.
651  * On response, the function 'onresp' is called with the returned json
652  * value and the closure 'data'.
653  * The function 'onresp' is invoked with 3 parameters:
654  *   1. int: 0 if no error or -1 if error.
655  *   2. const char *: the returned json (might be NULL if error)
656  *   3. void *: the closure 'data'
657  *
658  * Returns 0 in case of success or -1 in case of error.
659  */
660 int jbus_call_jj(
661                 struct jbus *jbus,
662                 const char *method,
663                 struct json_object *query,
664                 void (*onresp) (int, struct json_object *, void *),
665                 void *data)
666 {
667         const char *str = json_object_to_json_string(query);
668         if (str == NULL) {
669                 errno = ENOMEM;
670                 return -1;
671         }
672         return call(jbus, method, str, NULL, onresp, data);
673 }
674
675 /*
676  * Synchronous call to 'method' of 'jbus' passing the string 'query'.
677  * The returned string response is returned.
678  *
679  * Returns the string response or NULL in case of error.
680  */
681 char *jbus_call_ss_sync(
682                 struct jbus *jbus,
683                 const char *method,
684                 const char *query)
685 {
686         return sbus_call_sync(jbus->sbus, jbus->name, jbus->path, jbus->name,
687                         method, query);
688 }
689
690 /*
691  * Synchronous call to 'method' of 'jbus' passing the string 'query'.
692  * The returned json response is returned.
693  *
694  * Returns the json response or NULL in case of error.
695  */
696 struct json_object *jbus_call_sj_sync(
697                 struct jbus *jbus,
698                 const char *method,
699                 const char *query)
700 {
701         struct json_object *obj;
702         char *str = jbus_call_ss_sync(jbus, method, query);
703         if (str == NULL)
704                 obj = NULL;
705         else {
706                 jparse(jbus, str, &obj);
707                 free(str);
708         }
709         return obj;
710 }
711
712 /*
713  * Synchronous call to 'method' of 'jbus' passing the json 'query'.
714  * The returned string response is returned.
715  *
716  * Returns the string response or NULL in case of error.
717  */
718 char *jbus_call_js_sync(
719                 struct jbus *jbus,
720                 const char *method,
721                 struct json_object *query)
722 {
723         const char *str = json_object_to_json_string(query);
724         if (str == NULL) {
725                 errno = ENOMEM;
726                 return NULL;
727         }
728         return jbus_call_ss_sync(jbus, method, str);
729 }
730
731 /*
732  * Synchronous call to 'method' of 'jbus' passing the json 'query'.
733  * The returned json response is returned.
734  *
735  * Returns the json response or NULL in case of error.
736  */
737 struct json_object *jbus_call_jj_sync(
738                 struct jbus *jbus,
739                 const char *method,
740                 struct json_object *query)
741 {
742         const char *str = json_object_to_json_string(query);
743         if (str == NULL) {
744                 errno = ENOMEM;
745                 return NULL;
746         }
747         return jbus_call_sj_sync(jbus, method, str);
748 }
749
750 /*
751  * Records for 'jbus' the string signal handler 'onsig' with closure 'data'
752  * for the signal of 'name'.
753  * The callback handler is called with 2 arguments:
754  *   1. char *: the string parameter associated to the signal
755  *   2. void *: the closure data.
756  *
757  * Returns 0 in case of success or -1 otherwise.
758  */
759 int jbus_on_signal_s(
760                 struct jbus *jbus,
761                 const char *name,
762                 void (*onsig) (const char *, void *),
763                 void *data)
764 {
765         return add_signal(jbus, name, onsig, NULL, data);
766 }
767
768 /*
769  * Records for 'jbus' the json signal handler 'onsig' with closure 'data'
770  * for the signal of 'name'.
771  * The callback handler is called with 2 arguments:
772  *   1. struct json_object *: the json parameter associated to the signal
773  *   2. void *: the closure data.
774  *
775  * Returns 0 in case of success or -1 otherwise.
776  */
777 int jbus_on_signal_j(
778                 struct jbus *jbus,
779                 const char *name,
780                 void (*onsig) (struct json_object *, void *),
781                 void *data)
782 {
783         return add_signal(jbus, name, NULL, onsig, data);
784 }
785
786 /****************** FEW LITTLE TESTS *****************************************/
787
788 #if defined(SERVER)||defined(CLIENT)
789 #include <stdio.h>
790 #include <unistd.h>
791 #include "utils-upoll.h"
792
793 static int mwait(int timeout, void *closure)
794 {
795         upoll_wait(-1);
796         return 0;
797 }
798
799 static const struct sbus_itf uitf = {
800         .wait = (void*)mwait,
801         .open = (void*)upoll_open,
802         .on_readable = (void*)upoll_on_readable,
803         .on_writable = (void*)upoll_on_writable,
804         .on_hangup = (void*)upoll_on_hangup,
805         .close = (void*)upoll_close
806 };
807
808 static struct sbus *sbus;
809 static struct jbus *jbus;
810
811 static struct sbus *msbus()
812 {
813         return sbus ? : (sbus = sbus_session(&uitf, NULL));
814 }
815
816 #ifdef SERVER
817 void ping(struct sbusmsg *smsg, struct json_object *request, void *unused)
818 {
819         printf("ping(%s) -> %s\n", json_object_to_json_string(request),
820                json_object_to_json_string(request));
821         jbus_reply_j(smsg, request);
822         json_object_put(request);
823 }
824
825 void incr(struct sbusmsg *smsg, struct json_object *request, void *unused)
826 {
827         static int counter = 0;
828         struct json_object *res = json_object_new_int(++counter);
829         printf("incr(%s) -> %s\n", json_object_to_json_string(request),
830                json_object_to_json_string(res));
831         jbus_reply_j(smsg, res);
832         jbus_send_signal_j(jbus, "incremented", res);
833         json_object_put(res);
834         json_object_put(request);
835 }
836
837 int main()
838 {
839         int s1, s2, s3;
840         jbus = create_jbus(msbus(), "/bzh/iot/jdbus");
841         s1 = jbus_add_service_j(jbus, "ping", ping, NULL);
842         s2 = jbus_add_service_j(jbus, "incr", incr, NULL);
843         s3 = jbus_start_serving(jbus);
844         printf("started %d %d %d\n", s1, s2, s3);
845         while (!mwait(-1,jbus)) ;
846         return 0;
847 }
848 #endif
849
850 #ifdef CLIENT
851 void onresp(int status, struct json_object *response, void *data)
852 {
853         printf("resp: %d, %s, %s\n", status, (char *)data,
854                json_object_to_json_string(response));
855         json_object_put(response);
856 }
857
858 void signaled(const char *content, void *data)
859 {
860         printf("signaled with {%s}/%s\n", content, (char*)data);
861 }
862
863 int main()
864 {
865         int i = 10;
866         jbus = create_jbus(msbus(), "/bzh/iot/jdbus");
867         jbus_on_signal_s(jbus, "incremented", signaled, "closure-signal");
868         while (i--) {
869                 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}",
870                              onresp, "ping");
871                 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp,
872                              "incr");
873                 mwait(-1,jbus);
874         }
875         printf("[[[%s]]]\n",
876                jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
877         while (!mwait(-1,jbus)) ;
878         return 0;
879 }
880 #endif
881 #endif
882