3bea2c230b7a8a869d5531014bb1f1cd7e3133bc
[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 /*
33  * max depth of json messages
34  */
35 #define MAX_JSON_DEPTH 10
36
37 /*
38  * errors messages generated by jbus
39  */
40 #if defined(NO_JSON_ERROR_STRING)
41 static const char invalid_request_string[] = "invalid request";
42 static const char out_of_memory_string[] = "out of memory";
43 #else
44 static const char invalid_request_string[] = "\"invalid request\"";
45 static const char out_of_memory_string[] = "\"out of memory\"";
46 #endif
47
48 /*
49  * structure for handled requests
50  */
51 struct jreq {
52         DBusConnection *connection; /* connection of the request */
53         DBusMessage *request;       /* message of the request */
54 };
55
56 /*
57  * structure for services
58  */
59 struct jservice {
60         struct jservice *next;  /* link to the next service */
61         char *method;           /* method name for the service */
62         void (*oncall_s) (struct jreq *, const char *, void *);
63                                 /* string callback */
64         void (*oncall_j) (struct jreq *, struct json_object *, void *);
65                                 /* json callback */
66         void *data;             /* closure data for the callbacks */
67 };
68
69 /*
70  * structure for signals
71  */
72 struct jsignal {
73         struct jsignal *next;   /* link to the next signal */
74         char *name;             /* name of the expected signal */
75         void (*onsignal_s) (const char *, void *);
76                                 /* string callback */
77         void (*onsignal_j) (struct json_object *, void *);
78                                 /* json callback */
79         void *data;             /* closure data for the callbacks */
80 };
81
82 /*
83  * structure for asynchronous requests (resp-onse w-aiter)
84  */
85 struct jrespw {
86         struct jrespw *next;    /* next asynchronous */
87         dbus_uint32_t serial;   /* serial dbus number */
88         void *data;             /* closure data for the callbacks */
89         void (*onresp_s) (int, const char *, void *);
90                                 /* string callback */
91         void (*onresp_j) (int, struct json_object *, void *);
92                                 /* json callback */
93 };
94
95 /*
96  * structure for synchronous requests
97  */
98 struct respsync {
99         int replied;    /* boolean flag indicating reply */
100         char *value;    /* copy of the returned value */
101 };
102
103 /*
104  * structure for handling either client or server jbus on dbus
105  */
106 struct jbus {
107         int refcount;                   /* referenced how many time */
108         DBusConnection *connection;     /* connection to DBU */
109         struct json_tokener *tokener;   /* string to json tokenizer */
110         struct jservice *services;      /* first service */
111         struct jsignal *signals;        /* first signal */
112         struct jrespw *waiters;         /* first response waiter */
113         char *path;                     /* dbus path */
114         char *name;                     /* dbus name */
115         int watchnr;                    /* counter of watching need */
116         int watchfd;                    /* file to watch */
117         short watchflags;               /* watched flags */
118 };
119
120 /*********************** STATIC COMMON METHODS *****************/
121
122 /*
123  * Frees the ressources attached to a request
124  */
125 static inline void free_jreq(struct jreq *jreq)
126 {
127         dbus_message_unref(jreq->request);
128         dbus_connection_unref(jreq->connection);
129         free(jreq);
130 }
131
132 /*
133  * Replies the error "out of memory".
134  * This function is intended to be used in services when an
135  * allocation fails. Thus, it set errno to ENOMEM and
136  * returns -1.
137  */
138 static inline int reply_out_of_memory(struct jreq *jreq)
139 {
140         jbus_reply_error_s(jreq, out_of_memory_string);
141         errno = ENOMEM;
142         return -1;
143 }
144
145 /*
146  * Checks if the incoming 'message' matches the interface
147  * linked to 'jbus'.
148  *
149  * Returns 1 if it matches or 0 wether it does not matches.
150  */
151 static int matchitf(struct jbus *jbus, DBusMessage * message)
152 {
153         const char *itf = dbus_message_get_interface(message);
154         return itf != NULL && !strcmp(itf, jbus->name);
155 }
156
157 /*
158  * Adds to 'jbus' a service of name 'method'. The service is
159  * performed by one of the callback 'oncall_s' (for string) or
160  * 'oncall_j' (for json) that will receive the request and the
161  * closure parameter 'data'.
162  *
163  * returns 0 in case of success or -1 in case of error (ENOMEM).
164  */
165 static int add_service(
166                 struct jbus *jbus,
167                 const char *method,
168                 void (*oncall_s) (struct jreq *, const char *, void *),
169                 void (*oncall_j) (struct jreq *, struct json_object *, void *),
170                 void *data)
171 {
172         struct jservice *srv;
173
174         /* allocation */
175         srv = malloc(sizeof *srv);
176         if (srv == NULL) {
177                 errno = ENOMEM;
178                 goto error;
179         }
180         srv->method = strdup(method);
181         if (!srv->method) {
182                 errno = ENOMEM;
183                 goto error2;
184         }
185
186         /* record the service */
187         srv->oncall_s = oncall_s;
188         srv->oncall_j = oncall_j;
189         srv->data = data;
190         srv->next = jbus->services;
191         jbus->services = srv;
192
193         return 0;
194
195  error2:
196         free(srv);
197  error:
198         return -1;
199 }
200
201 /*
202  * Adds to 'jbus' a handler for the signal of 'name' emmited by
203  * the sender and the interface that 'jbus' is linked to.
204  * The signal is handled by one of the callback 'onsignal_s'
205  * (for string) or 'onsignal_j' (for json) that will receive
206  * parameters associated with the signal and the closure
207  * parameter 'data'.
208  *
209  * returns 0 in case of success or -1 in case of error (ENOMEM).
210  */
211 static int add_signal(
212                 struct jbus *jbus,
213                 const char *name,
214                 void (*onsignal_s) (const char *, void *),
215                 void (*onsignal_j) (struct json_object *, void *),
216                 void *data)
217 {
218         char *rule;
219         struct jsignal *sig;
220
221         /* record the signal */
222         if (jbus->signals == NULL) {
223                 if (0 >= asprintf(&rule,
224                           "type='signal',sender='%s',interface='%s',path='%s'",
225                                         jbus->name, jbus->name, jbus->path))
226                         return -1;
227                 dbus_bus_add_match(jbus->connection, rule, NULL);
228                 free(rule);
229         }
230
231         /* allocation */
232         sig = malloc(sizeof *sig);
233         if (sig == NULL)
234                 goto error;
235         sig->name = strdup(name);
236         if (!sig->name)
237                 goto error2;
238
239         /* record the signal */
240         sig->onsignal_s = onsignal_s;
241         sig->onsignal_j = onsignal_j;
242         sig->data = data;
243         sig->next = jbus->signals;
244         jbus->signals = sig;
245
246         return 0;
247
248  error2:
249         free(sig);
250  error:
251         errno = ENOMEM;
252         return -1;
253 }
254
255 /*
256  * Creates a message for 'method' with one string parameter being 'query'
257  * and sends it to the destination, object and interface linked to 'jbus'.
258  *
259  * Adds to 'jbus' the response handler defined by the callbacks 'onresp_s'
260  * (for string) and 'onresp_j' (for json) and the closure parameter 'data'.
261  *
262  * Returns 0 in case of success or -1 in case of error.
263  */
264 static int call(
265                 struct jbus *jbus,
266                 const char *method,
267                 const char *query,
268                 void (*onresp_s) (int, const char *, void *),
269                 void (*onresp_j) (int, struct json_object *, void *),
270                 void *data)
271 {
272         DBusMessage *msg;
273         struct jrespw *resp;
274
275         /* allocates the response structure */
276         resp = malloc(sizeof *resp);
277         if (resp == NULL) {
278                 errno = ENOMEM;
279                 goto error;
280         }
281
282         /* creates the message */
283         msg = dbus_message_new_method_call(jbus->name, jbus->path, jbus->name,
284                                                                 method);
285         if (msg == NULL) {
286                 errno = ENOMEM;
287                 goto error2;
288         }
289
290         /* fill it */
291         if (!dbus_message_append_args
292             (msg, DBUS_TYPE_STRING, &query, DBUS_TYPE_INVALID)) {
293                 errno = ENOMEM;
294                 goto error3;
295         }
296
297         /* send it */
298         if (!dbus_connection_send(jbus->connection, msg, &resp->serial)) {
299                 /* TODO: which error? */
300                 goto error3;
301         }
302
303         /* release the message that is not more used */
304         dbus_message_unref(msg);
305
306         /* fulfill the response structure */
307         resp->data = data;
308         resp->onresp_s = onresp_s;
309         resp->onresp_j = onresp_j;
310
311         /* links the response to list of reponse waiters */
312         resp->next = jbus->waiters;
313         jbus->waiters = resp;
314         return 0;
315
316  error3:
317         dbus_message_unref(msg);
318  error2:
319         free(resp);
320  error:
321         return -1;
322 }
323
324 /*
325  * Callback function for synchronous calls.
326  * This function fills the respsync structure pointed by 'data'
327  * with the copy of the answer.
328  */
329 static void sync_of_replies(int status, const char *value, void *data)
330 {
331         struct respsync *s = data;
332         s->value = status ? NULL : strdup(value ? value : "");
333         s->replied = 1;
334 }
335
336 /*
337  * Parses the json-string 'msg' to create a json object stored
338  * in 'obj'. It uses the tokener of 'jbus'. This is a small
339  * improvement to avoid recreation of tokeners.
340  *
341  * Returns 1 in case of success and put the result in *'obj'.
342  * Returns 0 in case of error and put NULL in *'obj'.
343  */
344 static int jparse(struct jbus *jbus, const char *msg, struct json_object **obj)
345 {
346         json_tokener_reset(jbus->tokener);
347         *obj = json_tokener_parse_ex(jbus->tokener, msg, -1);
348         if (json_tokener_get_error(jbus->tokener) == json_tokener_success)
349                 return 1;
350         json_object_put(*obj);
351         *obj = NULL;
352         return 0;
353 }
354
355 /*********************** STATIC DBUS MESSAGE HANDLING *****************/
356
357 /*
358  * Handles incomming responses 'message' on 'jbus'. Response are
359  * either expected if 'iserror' == 0 or errors if 'iserror' != 0.
360  *
361  * Returns DBUS_HANDLER_RESULT_HANDLED or DBUS_HANDLER_RESULT_NOT_YET_HANDLED
362  * as defined by the dbus function 'dbus_connection_add_filter'.
363  */
364 static DBusHandlerResult incoming_resp(
365                 struct jbus *jbus,
366                 DBusMessage * message,
367                 int iserror)
368 {
369         int status;
370         const char *str;
371         struct jrespw *jrw, **prv;
372         struct json_object *reply;
373         dbus_uint32_t serial;
374
375         /* search for the waiter */
376         serial = dbus_message_get_reply_serial(message);
377         prv = &jbus->waiters;
378         while ((jrw = *prv) != NULL && jrw->serial != serial)
379                 prv = &jrw->next;
380         if (jrw == NULL)
381                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
382         *prv = jrw->next;
383
384         /* retrieve the string value */
385         if (dbus_message_get_args
386             (message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID))
387                 status = 0;
388         else {
389                 status = -1;
390                 str = NULL;
391                 reply = NULL;
392         }
393
394         /* treat it */
395         if (jrw->onresp_s)
396                 jrw->onresp_s(iserror ? -1 : status, str, jrw->data);
397         else {
398                 status = jparse(jbus, str, &reply) - 1;
399                 jrw->onresp_j(iserror ? -1 : status, reply, jrw->data);
400                 json_object_put(reply);
401         }
402
403         free(jrw);
404         return DBUS_HANDLER_RESULT_HANDLED;
405 }
406
407 /*
408  * Handles incomming on 'jbus' method calls for 'message'.
409  *
410  * Returns DBUS_HANDLER_RESULT_HANDLED or DBUS_HANDLER_RESULT_NOT_YET_HANDLED
411  * as defined by the dbus function 'dbus_connection_add_filter'.
412  */
413 static DBusHandlerResult incoming_call(
414                 struct jbus *jbus,
415                 DBusMessage * message)
416 {
417         struct jservice *srv;
418         struct jreq *jreq;
419         const char *str;
420         const char *method;
421         struct json_object *query;
422
423         /* search for the service */
424         if (!matchitf(jbus, message))
425                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
426         method = dbus_message_get_member(message);
427         if (method == NULL)
428                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
429         srv = jbus->services;
430         while (srv != NULL && strcmp(method, srv->method))
431                 srv = srv->next;
432         if (srv == NULL)
433                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
434
435         /* creates and init the jreq structure */
436         jreq = malloc(sizeof *jreq);
437         if (jreq == NULL)
438                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
439         jreq->request = dbus_message_ref(message);
440         jreq->connection = dbus_connection_ref(jbus->connection);
441
442         /* retrieve the string parameter of the message */
443         if (!dbus_message_get_args
444             (message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID))
445                 goto invalid_request;
446
447         /* send the message to the callback */
448         if (srv->oncall_s) {
449                 /* handling strings only */
450                 srv->oncall_s(jreq, str, srv->data);
451         } else {
452                 /* handling json only */
453                 if (!jparse(jbus, str, &query))
454                         goto invalid_request;
455                 srv->oncall_j(jreq, query, srv->data);
456                 json_object_put(query);
457         }
458         return DBUS_HANDLER_RESULT_HANDLED;
459
460 invalid_request:
461         jbus_reply_error_s(jreq, invalid_request_string);
462         return DBUS_HANDLER_RESULT_HANDLED;
463 }
464
465 /*
466  * Handles incomming on 'jbus' signal propagated with 'message'.
467  *
468  * This is a design choice to ignore invalid signals.
469  *
470  * Returns DBUS_HANDLER_RESULT_HANDLED or DBUS_HANDLER_RESULT_NOT_YET_HANDLED
471  * as defined by the dbus function 'dbus_connection_add_filter'.
472  */
473 static DBusHandlerResult incoming_signal(
474                 struct jbus *jbus,
475                 DBusMessage * message)
476 {
477         struct jsignal *sig;
478         const char *str;
479         const char *name;
480         struct json_object *obj;
481
482         /* search for the signal name */
483         if (!matchitf(jbus, message))
484                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
485         name = dbus_message_get_member(message);
486         if (name == NULL)
487                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
488         sig = jbus->signals;
489         while (sig != NULL && strcmp(name, sig->name))
490                 sig = sig->next;
491         if (sig == NULL)
492                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
493
494         /* retrieve the string value */
495         if (dbus_message_get_args
496             (message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
497                 if (sig->onsignal_s) {
498                         /* handling strings only */
499                         sig->onsignal_s(str, sig->data);
500                 } else {
501                         /* handling json only (if valid) */
502                         if (jparse(jbus, str, &obj)) {
503                                 sig->onsignal_j(obj, sig->data);
504                                 json_object_put(obj);
505                         }
506                 }
507         }
508         return DBUS_HANDLER_RESULT_HANDLED;
509 }
510
511 /*
512  * Filters incomming messages as defined by the dbus function
513  * 'dbus_connection_add_filter'.
514  * Returns DBUS_HANDLER_RESULT_HANDLED or DBUS_HANDLER_RESULT_NOT_YET_HANDLED.
515  */
516 static DBusHandlerResult incoming(
517                 DBusConnection * connection,
518                 DBusMessage * message,
519                 void *data)
520 {
521         struct jbus *jbus = data;
522         switch (dbus_message_get_type(message)) {
523         case DBUS_MESSAGE_TYPE_METHOD_CALL:
524                 return incoming_call(jbus, message);
525         case DBUS_MESSAGE_TYPE_METHOD_RETURN:
526                 return incoming_resp(jbus, message, 0);
527         case DBUS_MESSAGE_TYPE_ERROR:
528                 return incoming_resp(jbus, message, 1);
529         case DBUS_MESSAGE_TYPE_SIGNAL:
530                 return incoming_signal(jbus, message);
531         }
532         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
533 }
534
535 /*********************** STATIC DBUS WATCH/POLLING INTERFACE **********/
536
537 /*
538  * Set the watched flags of 'jbus' following what DBUS expects by 'watch'
539  */
540 static void watchset(DBusWatch * watch, struct jbus *jbus)
541 {
542         unsigned int flags;
543         short wf;
544
545         flags = dbus_watch_get_flags(watch);
546         wf = jbus->watchflags;
547         if (dbus_watch_get_enabled(watch)) {
548                 if (flags & DBUS_WATCH_READABLE)
549                         wf |= POLLIN;
550                 if (flags & DBUS_WATCH_WRITABLE)
551                         wf |= POLLOUT;
552         } else {
553                 if (flags & DBUS_WATCH_READABLE)
554                         wf &= ~POLLIN;
555                 if (flags & DBUS_WATCH_WRITABLE)
556                         wf &= ~POLLOUT;
557         }
558         jbus->watchflags = wf;
559 }
560
561 /*
562  * DBUS Callback for removing a 'watch'.
563  * See function 'dbus_connection_set_watch_functions'
564  */
565 static void watchdel(DBusWatch * watch, void *data)
566 {
567         struct jbus *jbus = data;
568
569         assert(jbus->watchnr > 0);
570         assert(jbus->watchfd == dbus_watch_get_unix_fd(watch));
571         jbus->watchnr--;
572 }
573
574 /*
575  * DBUS Callback for changing a 'watch'.
576  * See function 'dbus_connection_set_watch_functions'
577  */
578 static void watchtoggle(DBusWatch * watch, void *data)
579 {
580         struct jbus *jbus = data;
581
582         assert(jbus->watchnr > 0);
583         assert(jbus->watchfd == dbus_watch_get_unix_fd(watch));
584         watchset(watch, jbus);
585 }
586
587 /*
588  * DBUS Callback for adding a 'watch'.
589  * See function 'dbus_connection_set_watch_functions'
590  */
591 static dbus_bool_t watchadd(DBusWatch * watch, void *data)
592 {
593         struct jbus *jbus = data;
594         if (jbus->watchnr == 0) {
595                 jbus->watchfd = dbus_watch_get_unix_fd(watch);
596                 jbus->watchflags = 0;
597         } else if (jbus->watchfd != dbus_watch_get_unix_fd(watch))
598                 return FALSE;
599         jbus->watchnr++;
600         watchset(watch, jbus);
601         return TRUE;
602 }
603
604 /********************* MAIN FUNCTIONS *****************************************/
605
606 /*
607  * Creates a 'jbus' bound to DBUS system using 'path' and returns it.
608  * See 'create_jbus'
609  */
610 struct jbus *create_jbus_system(const char *path)
611 {
612         return create_jbus(path, 0);
613 }
614
615 /*
616  * Creates a 'jbus' bound to DBUS session using 'path' and returns it.
617  * See 'create_jbus'
618  */
619 struct jbus *create_jbus_session(const char *path)
620 {
621         return create_jbus(path, 1);
622 }
623
624 /*
625  * Creates a 'jbus' bound the 'path' and it derived names and linked
626  * either to the DBUS SYSTEM when 'session' is nul or to the DBUS SESSION
627  * if 'session' is not nul.
628  *
629  * The parameter 'path' is intended to be the path of a DBUS single object.
630  * Single means that it exists only one instance of the object on the
631  * given bus. That path implies 2 derived DBUS names:
632  *   1. the destination name of the program that handles the object
633  *   2. the interface name of the object
634  * These names are derived by removing the heading slash (/) and
635  * by replacing all occurences of slashes by dots.
636  * For example, passing path = /a/b/c means that the object /a/b/c is
637  * handled by the destination a.b.c and replies to the interface a.b.c
638  *
639  * Returns the created jbus or NULL in case of error.
640  */
641 struct jbus *create_jbus(const char *path, int session)
642 {
643         struct jbus *jbus;
644         char *name;
645
646         /* create the jbus object */
647         jbus = calloc(1, sizeof *jbus);
648         if (jbus == NULL) {
649                 errno = ENOMEM;
650                 goto error;
651         }
652         jbus->refcount = 1;
653
654         /* create the tokener */
655         jbus->tokener = json_tokener_new_ex(MAX_JSON_DEPTH);
656         if (jbus->tokener == NULL) {
657                 errno = ENOMEM;
658                 goto error2;
659         }
660
661         /* records the path */
662         jbus->path = strdup(path);
663         if (jbus->path == NULL) {
664                 errno = ENOMEM;
665                 goto error2;
666         }
667
668         /* makes the name from the path */
669         while (*path == '/')
670                 path++;
671         jbus->name = name = strdup(path);
672         if (name == NULL) {
673                 errno = ENOMEM;
674                 goto error2;
675         }
676         while (*name) {
677                 if (*name == '/')
678                         *name = '.';
679                 name++;
680         }
681         name--;
682         while (name >= jbus->name && *name == '.')
683                 *name-- = 0;
684         if (!*jbus->name) {
685                 errno = EINVAL;
686                 goto error2;
687         }
688
689         /* connect and init */
690         jbus->connection = dbus_bus_get(session ? DBUS_BUS_SESSION
691                                                 : DBUS_BUS_SYSTEM, NULL);
692         if (jbus->connection == NULL
693             || !dbus_connection_add_filter(jbus->connection, incoming, jbus,
694                                                                         NULL)
695             || !dbus_connection_set_watch_functions(jbus->connection, watchadd,
696                                         watchdel, watchtoggle, jbus, NULL))
697                 goto error2;
698
699         return jbus;
700
701  error2:
702         jbus_unref(jbus);
703  error:
704         return NULL;
705 }
706
707 /*
708  * Adds one reference to 'jbus'.
709  */
710 void jbus_addref(struct jbus *jbus)
711 {
712         jbus->refcount++;
713 }
714
715 /*
716  * Removes one reference to 'jbus'. Destroys 'jbus' and it related
717  * data if the count of references decrease to zero.
718  */
719 void jbus_unref(struct jbus *jbus)
720 {
721         struct jservice *srv;
722         if (!--jbus->refcount) {
723                 if (jbus->connection != NULL)
724                         dbus_connection_unref(jbus->connection);
725                 while ((srv = jbus->services) != NULL) {
726                         jbus->services = srv->next;
727                         free(srv->method);
728                         free(srv);
729                 }
730                 if (jbus->tokener != NULL)
731                         json_tokener_free(jbus->tokener);
732                 free(jbus->name);
733                 free(jbus->path);
734                 free(jbus);
735         }
736 }
737
738 /*
739  * Replies an error of string 'error' to the request handled by 'jreq'.
740  * Also destroys the request 'jreq' that must not be used later.
741  *
742  * Returns 0 in case of success or -1 in case of error.
743  */
744 int jbus_reply_error_s(struct jreq *jreq, const char *error)
745 {
746         int rc = -1;
747         DBusMessage *message;
748
749         message = dbus_message_new_error(jreq->request, DBUS_ERROR_FAILED,
750                                                                 error);
751         if (message == NULL)
752                 errno = ENOMEM;
753         else {
754                 if (dbus_connection_send(jreq->connection, message, NULL))
755                         rc = 0;
756                 dbus_message_unref(message);
757         }
758         free_jreq(jreq);
759         return rc;
760 }
761
762 /*
763  * Replies an error of json 'reply' to the request handled by 'jreq'.
764  * Also destroys the request 'jreq' that must not be used later.
765  *
766  * Returns 0 in case of success or -1 in case of error.
767  */
768 int jbus_reply_error_j(struct jreq *jreq, struct json_object *reply)
769 {
770         const char *str = json_object_to_json_string(reply);
771         return str ? jbus_reply_error_s(jreq, str) : reply_out_of_memory(jreq);
772 }
773
774 /*
775  * Replies normally the string 'reply' to the request handled by 'jreq'.
776  * Also destroys the request 'jreq' that must not be used later.
777  *
778  * Returns 0 in case of success or -1 in case of error.
779  */
780 int jbus_reply_s(struct jreq *jreq, const char *reply)
781 {
782         int rc = -1;
783         DBusMessage *message;
784
785         message = dbus_message_new_method_return(jreq->request);
786         if (message == NULL)
787                 return reply_out_of_memory(jreq);
788
789         if (!dbus_message_append_args
790             (message, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
791                 dbus_message_unref(message);
792                 return reply_out_of_memory(jreq);
793         }
794
795         if (dbus_connection_send(jreq->connection, message, NULL))
796                 rc = 0;
797         dbus_message_unref(message);
798         free_jreq(jreq);
799         return rc;
800 }
801
802 /*
803  * Replies normally the json 'reply' to the request handled by 'jreq'.
804  * Also destroys the request 'jreq' that must not be used later.
805  *
806  * Returns 0 in case of success or -1 in case of error.
807  */
808 int jbus_reply_j(struct jreq *jreq, struct json_object *reply)
809 {
810         const char *str = json_object_to_json_string(reply);
811         return str ? jbus_reply_s(jreq, str) : reply_out_of_memory(jreq);
812 }
813
814 /*
815  * Sends from 'jbus' the signal of 'name' handling the string 'content'.
816  *
817  * Returns 0 in case of success or -1 in case of error.
818  */
819 int jbus_send_signal_s(struct jbus *jbus, const char *name, const char *content)
820 {
821         int rc = -1;
822         DBusMessage *message;
823
824         message = dbus_message_new_signal(jbus->path, jbus->name, name);
825         if (message == NULL)
826                 goto error;
827
828         if (!dbus_message_set_sender(message, jbus->name)
829             || !dbus_message_append_args(message, DBUS_TYPE_STRING, &content,
830                                          DBUS_TYPE_INVALID)) {
831                 dbus_message_unref(message);
832                 goto error;
833         }
834
835         if (dbus_connection_send(jbus->connection, message, NULL))
836                 rc = 0;
837         dbus_message_unref(message);
838         return rc;
839
840  error:
841         errno = ENOMEM;
842         return -1;
843 }
844
845 /*
846  * Sends from 'jbus' the signal of 'name' handling the json 'content'.
847  *
848  * Returns 0 in case of success or -1 in case of error.
849  */
850 int jbus_send_signal_j(struct jbus *jbus, const char *name,
851                        struct json_object *content)
852 {
853         const char *str = json_object_to_json_string(content);
854         if (str == NULL) {
855                 errno = ENOMEM;
856                 return -1;
857         }
858         return jbus_send_signal_s(jbus, name, str);
859 }
860
861 /*
862  * Adds to 'jbus' a service handling calls to the 'method' using
863  * the "string" callback 'oncall' and the closure value 'data'.
864  *
865  * The callback 'oncall' is invoked for handling incoming method
866  * calls. It receives 3 parameters:
867  *   1. struct jreq *: a handler to data to be used for replying
868  *   2. const char *: the received string
869  *   3. void *: the closure 'data' set by this function
870  *
871  * Returns 0 in case of success or -1 in case of error.
872  */
873 int jbus_add_service_s(
874                 struct jbus *jbus,
875                 const char *method,
876                 void (*oncall) (struct jreq *, const char *, void *),
877                 void *data)
878 {
879         return add_service(jbus, method, oncall, NULL, data);
880 }
881
882 /*
883  * Adds to 'jbus' a service handling calls to the 'method' using
884  * the "json" callback 'oncall' and the closure value 'data'.
885  *
886  * The callback 'oncall' is invoked for handling incoming method
887  * calls. It receives 3 parameters:
888  *   1. struct jreq *: a handler to data to be used for replying
889  *   2. struct json_object *: the received json
890  *   3. void *: the closure 'data' set by this function
891  *
892  * Returns 0 in case of success or -1 in case of error.
893  */
894 int jbus_add_service_j(
895                 struct jbus *jbus,
896                 const char *method,
897                 void (*oncall) (struct jreq *, struct json_object *, void *),
898                 void *data)
899 {
900         return add_service(jbus, method, NULL, oncall, data);
901 }
902
903 /*
904  * Start to serve: activate services declared for 'jbus'.
905  * This function, in fact, declares 'jbus' as the receiver
906  * for calls to the destination derived from the path set at
907  * 'jbus' creation.
908  * It also allows 'jbus' to emit signals of that origin.
909  *
910  * Returns 0 in case of success or -1 in case of error.
911  */
912 int jbus_start_serving(struct jbus *jbus)
913 {
914         int status = dbus_bus_request_name(jbus->connection, jbus->name,
915                                         DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
916         switch (status) {
917         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
918         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
919                 return 0;
920         case DBUS_REQUEST_NAME_REPLY_EXISTS:
921         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
922         default:
923                 errno = EADDRINUSE;
924                 return -1;
925         }
926 }
927
928 /*
929  * Fills the at least 'njbuses' structures of array 'fds' with data needed
930  * to poll the 'njbuses' buses pointed by 'jbuses'.
931  *
932  * Returns the count of 'fds' structures filled.
933  */
934 int jbus_fill_pollfds(struct jbus **jbuses, int njbuses, struct pollfd *fds)
935 {
936         int i, r;
937
938         for (r = i = 0; i < njbuses; i++) {
939                 if (jbuses[i]->watchnr) {
940                         fds[r].fd = jbuses[i]->watchfd;
941                         fds[r].events = jbuses[i]->watchflags;
942                         r++;
943                 }
944         }
945         return r;
946 }
947
948 /*
949  * Dispatchs a maximum of 'maxcount' events received by poll in 'fds' for the
950  * 'njbuses' jbuses of the array 'jbuses'.
951  *
952  * Returns the count of event dispatched.
953  */
954 int jbus_dispatch_pollfds(
955                 struct jbus **jbuses,
956                 int njbuses,
957                 struct pollfd *fds,
958                 int maxcount)
959 {
960         int i, r, n;
961         DBusDispatchStatus sts;
962
963         for (r = n = i = 0; i < njbuses && n < maxcount; i++) {
964                 if (jbuses[i]->watchnr && fds[r].fd == jbuses[i]->watchfd) {
965                         if (fds[r].revents) {
966                                 dbus_connection_read_write(
967                                                 jbuses[i]->connection, 0);
968                                 sts = dbus_connection_get_dispatch_status(
969                                                         jbuses[i]->connection);
970                                 while (sts == DBUS_DISPATCH_DATA_REMAINS
971                                                         && n < maxcount) {
972                                         sts = dbus_connection_dispatch(
973                                                         jbuses[i]->connection);
974                                         n++;
975                                 }
976                         }
977                         r++;
978                 }
979         }
980         return n;
981 }
982
983 /*
984  * Dispatches 'maxcount' of buffered data from the 'njbuses' jbuses of the
985  * array 'jbuses'.
986  *
987  * Returns the count of event dispatched.
988  */
989 int jbus_dispatch_multiple(struct jbus **jbuses, int njbuses, int maxcount)
990 {
991         int i, r;
992         DBusDispatchStatus sts;
993
994         for (i = r = 0; i < njbuses && r < maxcount; i++) {
995                 dbus_connection_read_write(jbuses[i]->connection, 0);
996                 sts = dbus_connection_get_dispatch_status(
997                                                         jbuses[i]->connection);
998                 while (sts == DBUS_DISPATCH_DATA_REMAINS && r < maxcount) {
999                         sts = dbus_connection_dispatch(jbuses[i]->connection);
1000                         r++;
1001                 }
1002         }
1003         return r;
1004 }
1005
1006 /*
1007  * Polls during at most 'toms' milliseconds and dispatches 'maxcount'
1008  * of events from the 'njbuses' jbuses of the array 'jbuses'.
1009  *
1010  * Returns the count of event dispatched or -1 in case of error.
1011  */
1012 int jbus_read_write_dispatch_multiple(
1013                 struct jbus **jbuses,
1014                 int njbuses,
1015                 int toms,
1016                 int maxcount)
1017 {
1018         int n, r, s;
1019         struct pollfd *fds;
1020
1021         if (njbuses < 0 || njbuses > 100) {
1022                 errno = EINVAL;
1023                 return -1;
1024         }
1025         fds = alloca((unsigned)njbuses * sizeof *fds);
1026         assert(fds != NULL);
1027
1028         r = jbus_dispatch_multiple(jbuses, njbuses, maxcount);
1029         if (r)
1030                 return r;
1031         n = jbus_fill_pollfds(jbuses, njbuses, fds);
1032         for (;;) {
1033                 s = poll(fds, (nfds_t) n, toms);
1034                 if (s >= 0)
1035                         break;
1036                 if (errno != EINTR)
1037                         return r ? r : s;
1038                 toms = 0;
1039         }
1040         n = jbus_dispatch_pollfds(jbuses, njbuses, fds, maxcount - r);
1041         return n >= 0 ? r + n : r ? r : n;
1042 }
1043
1044 /*
1045  * Polls during at most 'toms' milliseconds and dispatches
1046  * the events from 'jbus'.
1047  *
1048  * Returns the count of event dispatched or -1 in case of error.
1049  */
1050 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
1051 {
1052         int r = jbus_read_write_dispatch_multiple(&jbus, 1, toms, 1000);
1053         return r < 0 ? r : 0;
1054 }
1055
1056 /*
1057  * Asynchronous call to 'method' of 'jbus' passing the string 'query'.
1058  * On response, the function 'onresp' is called with the returned string
1059  * value and the closure 'data'.
1060  * The function 'onresp' is invoked with 3 parameters:
1061  *   1. int: 0 if no error or -1 if error.
1062  *   2. const char *: the returned string (might be NULL if error)
1063  *   3. void *: the closure 'data'
1064  *
1065  * Returns 0 in case of success or -1 in case of error.
1066  */
1067 int jbus_call_ss(
1068                 struct jbus *jbus,
1069                 const char *method,
1070                 const char *query,
1071                 void (*onresp) (int, const char *, void *),
1072                 void *data)
1073 {
1074         return call(jbus, method, query, onresp, NULL, data);
1075 }
1076
1077 /*
1078  * Asynchronous call to 'method' of 'jbus' passing the string 'query'.
1079  * On response, the function 'onresp' is called with the returned json
1080  * value and the closure 'data'.
1081  * The function 'onresp' is invoked with 3 parameters:
1082  *   1. int: 0 if no error or -1 if error.
1083  *   2. const char *: the returned json (might be NULL if error)
1084  *   3. void *: the closure 'data'
1085  *
1086  * Returns 0 in case of success or -1 in case of error.
1087  */
1088 int jbus_call_sj(
1089                 struct jbus *jbus,
1090                 const char *method,
1091                 const char *query,
1092                 void (*onresp) (int, struct json_object *, void *),
1093                 void *data)
1094 {
1095         return call(jbus, method, query, NULL, onresp, data);
1096 }
1097
1098 /*
1099  * Asynchronous call to 'method' of 'jbus' passing the json 'query'.
1100  * On response, the function 'onresp' is called with the returned string
1101  * value and the closure 'data'.
1102  * The function 'onresp' is invoked with 3 parameters:
1103  *   1. int: 0 if no error or -1 if error.
1104  *   2. const char *: the returned string (might be NULL if error)
1105  *   3. void *: the closure 'data'
1106  *
1107  * Returns 0 in case of success or -1 in case of error.
1108  */
1109 int jbus_call_js(
1110                 struct jbus *jbus,
1111                 const char *method,
1112                 struct json_object *query,
1113                 void (*onresp) (int, const char *, void *),
1114                 void *data)
1115 {
1116         const char *str = json_object_to_json_string(query);
1117         if (str == NULL) {
1118                 errno = ENOMEM;
1119                 return -1;
1120         }
1121         return call(jbus, method, str, onresp, NULL, data);
1122 }
1123
1124 /*
1125  * Asynchronous call to 'method' of 'jbus' passing the json 'query'.
1126  * On response, the function 'onresp' is called with the returned json
1127  * value and the closure 'data'.
1128  * The function 'onresp' is invoked with 3 parameters:
1129  *   1. int: 0 if no error or -1 if error.
1130  *   2. const char *: the returned json (might be NULL if error)
1131  *   3. void *: the closure 'data'
1132  *
1133  * Returns 0 in case of success or -1 in case of error.
1134  */
1135 int jbus_call_jj(
1136                 struct jbus *jbus,
1137                 const char *method,
1138                 struct json_object *query,
1139                 void (*onresp) (int, struct json_object *, void *),
1140                 void *data)
1141 {
1142         const char *str = json_object_to_json_string(query);
1143         if (str == NULL) {
1144                 errno = ENOMEM;
1145                 return -1;
1146         }
1147         return call(jbus, method, str, NULL, onresp, data);
1148 }
1149
1150 /*
1151  * Synchronous call to 'method' of 'jbus' passing the string 'query'.
1152  * The returned string response is returned.
1153  *
1154  * Returns the string response or NULL in case of error.
1155  */
1156 char *jbus_call_ss_sync(
1157                 struct jbus *jbus,
1158                 const char *method,
1159                 const char *query)
1160 {
1161         struct respsync synchro;
1162         synchro.value = NULL;
1163         synchro.replied =
1164             jbus_call_ss(jbus, method, query, sync_of_replies, &synchro);
1165         while (!synchro.replied && !jbus_read_write_dispatch(jbus, -1)) ;
1166         return synchro.value;
1167 }
1168
1169 /*
1170  * Synchronous call to 'method' of 'jbus' passing the string 'query'.
1171  * The returned json response is returned.
1172  *
1173  * Returns the json response or NULL in case of error.
1174  */
1175 struct json_object *jbus_call_sj_sync(
1176                 struct jbus *jbus,
1177                 const char *method,
1178                 const char *query)
1179 {
1180         struct json_object *obj;
1181         char *str = jbus_call_ss_sync(jbus, method, query);
1182         if (str == NULL)
1183                 obj = NULL;
1184         else {
1185                 jparse(jbus, str, &obj);
1186                 free(str);
1187         }
1188         return obj;
1189 }
1190
1191 /*
1192  * Synchronous call to 'method' of 'jbus' passing the json 'query'.
1193  * The returned string response is returned.
1194  *
1195  * Returns the string response or NULL in case of error.
1196  */
1197 char *jbus_call_js_sync(
1198                 struct jbus *jbus,
1199                 const char *method,
1200                 struct json_object *query)
1201 {
1202         const char *str = json_object_to_json_string(query);
1203         if (str == NULL) {
1204                 errno = ENOMEM;
1205                 return NULL;
1206         }
1207         return jbus_call_ss_sync(jbus, method, str);
1208 }
1209
1210 /*
1211  * Synchronous call to 'method' of 'jbus' passing the json 'query'.
1212  * The returned json response is returned.
1213  *
1214  * Returns the json response or NULL in case of error.
1215  */
1216 struct json_object *jbus_call_jj_sync(
1217                 struct jbus *jbus,
1218                 const char *method,
1219                 struct json_object *query)
1220 {
1221         const char *str = json_object_to_json_string(query);
1222         if (str == NULL) {
1223                 errno = ENOMEM;
1224                 return NULL;
1225         }
1226         return jbus_call_sj_sync(jbus, method, str);
1227 }
1228
1229 /*
1230  * Records for 'jbus' the string signal handler 'onsig' with closure 'data'
1231  * for the signal of 'name'.
1232  * The callback handler is called with 2 arguments:
1233  *   1. char *: the string parameter associated to the signal
1234  *   2. void *: the closure data.
1235  *
1236  * Returns 0 in case of success or -1 otherwise.
1237  */
1238 int jbus_on_signal_s(
1239                 struct jbus *jbus,
1240                 const char *name,
1241                 void (*onsig) (const char *, void *),
1242                 void *data)
1243 {
1244         return add_signal(jbus, name, onsig, NULL, data);
1245 }
1246
1247 /*
1248  * Records for 'jbus' the json signal handler 'onsig' with closure 'data'
1249  * for the signal of 'name'.
1250  * The callback handler is called with 2 arguments:
1251  *   1. struct json_object *: the json parameter associated to the signal
1252  *   2. void *: the closure data.
1253  *
1254  * Returns 0 in case of success or -1 otherwise.
1255  */
1256 int jbus_on_signal_j(
1257                 struct jbus *jbus,
1258                 const char *name,
1259                 void (*onsig) (struct json_object *, void *),
1260                 void *data)
1261 {
1262         return add_signal(jbus, name, NULL, onsig, data);
1263 }
1264
1265 /****************** FEW LITTLE TESTS *****************************************/
1266
1267 #ifdef SERVER
1268 #include <stdio.h>
1269 #include <unistd.h>
1270 struct jbus *jbus;
1271 void ping(struct jreq *jreq, struct json_object *request, void *unused)
1272 {
1273         printf("ping(%s) -> %s\n", json_object_to_json_string(request),
1274                json_object_to_json_string(request));
1275         jbus_reply_j(jreq, request);
1276         json_object_put(request);
1277 }
1278
1279 void incr(struct jreq *jreq, struct json_object *request, void *unused)
1280 {
1281         static int counter = 0;
1282         struct json_object *res = json_object_new_int(++counter);
1283         printf("incr(%s) -> %s\n", json_object_to_json_string(request),
1284                json_object_to_json_string(res));
1285         jbus_reply_j(jreq, res);
1286         jbus_send_signal_j(jbus, "incremented", res);
1287         json_object_put(res);
1288         json_object_put(request);
1289 }
1290
1291 int main()
1292 {
1293         int s1, s2, s3;
1294         jbus = create_jbus(1, "/bzh/iot/jdbus");
1295         s1 = jbus_add_service_j(jbus, "ping", ping, NULL);
1296         s2 = jbus_add_service_j(jbus, "incr", incr, NULL);
1297         s3 = jbus_start_serving(jbus);
1298         printf("started %d %d %d\n", s1, s2, s3);
1299         while (!jbus_read_write_dispatch(jbus, -1)) ;
1300 }
1301 #endif
1302 #ifdef CLIENT
1303 #include <stdio.h>
1304 #include <unistd.h>
1305 struct jbus *jbus;
1306 void onresp(int status, struct json_object *response, void *data)
1307 {
1308         printf("resp: %d, %s, %s\n", status, (char *)data,
1309                json_object_to_json_string(response));
1310         json_object_put(response);
1311 }
1312
1313 void signaled(const char *data)
1314 {
1315         printf("signaled with {%s}\n", data);
1316 }
1317
1318 int main()
1319 {
1320         int i = 10;
1321         jbus = create_jbus(1, "/bzh/iot/jdbus");
1322         jbus_on_signal_s(jbus, "incremented", signaled);
1323         while (i--) {
1324                 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}",
1325                              onresp, "ping");
1326                 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp,
1327                              "incr");
1328                 jbus_read_write_dispatch(jbus, 1);
1329         }
1330         printf("[[[%s]]]\n",
1331                jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
1332         while (!jbus_read_write_dispatch(jbus, -1)) ;
1333 }
1334 #endif