cleaner cleanup
[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         struct jsignal *sig;
723         struct jrespw *wtr;
724         if (!--jbus->refcount) {
725                 if (jbus->connection != NULL)
726                         dbus_connection_unref(jbus->connection);
727                 while ((wtr = jbus->waiters) != NULL) {
728                         jbus->waiters = wtr->next;
729                         free(wtr);
730                 }
731                 while ((sig = jbus->signals) != NULL) {
732                         jbus->signals = sig->next;
733                         free(sig->name);
734                         free(sig);
735                 }
736                 while ((srv = jbus->services) != NULL) {
737                         jbus->services = srv->next;
738                         free(srv->method);
739                         free(srv);
740                 }
741                 if (jbus->tokener != NULL)
742                         json_tokener_free(jbus->tokener);
743                 free(jbus->name);
744                 free(jbus->path);
745                 free(jbus);
746         }
747 }
748
749 /*
750  * Replies an error of string 'error' to the request handled by 'jreq'.
751  * Also destroys the request 'jreq' that must not be used later.
752  *
753  * Returns 0 in case of success or -1 in case of error.
754  */
755 int jbus_reply_error_s(struct jreq *jreq, const char *error)
756 {
757         int rc = -1;
758         DBusMessage *message;
759
760         message = dbus_message_new_error(jreq->request, DBUS_ERROR_FAILED,
761                                                                 error);
762         if (message == NULL)
763                 errno = ENOMEM;
764         else {
765                 if (dbus_connection_send(jreq->connection, message, NULL))
766                         rc = 0;
767                 dbus_message_unref(message);
768         }
769         free_jreq(jreq);
770         return rc;
771 }
772
773 /*
774  * Replies an error of json 'reply' to the request handled by 'jreq'.
775  * Also destroys the request 'jreq' that must not be used later.
776  *
777  * Returns 0 in case of success or -1 in case of error.
778  */
779 int jbus_reply_error_j(struct jreq *jreq, struct json_object *reply)
780 {
781         const char *str = json_object_to_json_string(reply);
782         return str ? jbus_reply_error_s(jreq, str) : reply_out_of_memory(jreq);
783 }
784
785 /*
786  * Replies normally the string 'reply' to the request handled by 'jreq'.
787  * Also destroys the request 'jreq' that must not be used later.
788  *
789  * Returns 0 in case of success or -1 in case of error.
790  */
791 int jbus_reply_s(struct jreq *jreq, const char *reply)
792 {
793         int rc = -1;
794         DBusMessage *message;
795
796         message = dbus_message_new_method_return(jreq->request);
797         if (message == NULL)
798                 return reply_out_of_memory(jreq);
799
800         if (!dbus_message_append_args
801             (message, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
802                 dbus_message_unref(message);
803                 return reply_out_of_memory(jreq);
804         }
805
806         if (dbus_connection_send(jreq->connection, message, NULL))
807                 rc = 0;
808         dbus_message_unref(message);
809         free_jreq(jreq);
810         return rc;
811 }
812
813 /*
814  * Replies normally the json 'reply' to the request handled by 'jreq'.
815  * Also destroys the request 'jreq' that must not be used later.
816  *
817  * Returns 0 in case of success or -1 in case of error.
818  */
819 int jbus_reply_j(struct jreq *jreq, struct json_object *reply)
820 {
821         const char *str = json_object_to_json_string(reply);
822         return str ? jbus_reply_s(jreq, str) : reply_out_of_memory(jreq);
823 }
824
825 /*
826  * Sends from 'jbus' the signal of 'name' handling the string 'content'.
827  *
828  * Returns 0 in case of success or -1 in case of error.
829  */
830 int jbus_send_signal_s(struct jbus *jbus, const char *name, const char *content)
831 {
832         int rc = -1;
833         DBusMessage *message;
834
835         message = dbus_message_new_signal(jbus->path, jbus->name, name);
836         if (message == NULL)
837                 goto error;
838
839         if (!dbus_message_set_sender(message, jbus->name)
840             || !dbus_message_append_args(message, DBUS_TYPE_STRING, &content,
841                                          DBUS_TYPE_INVALID)) {
842                 dbus_message_unref(message);
843                 goto error;
844         }
845
846         if (dbus_connection_send(jbus->connection, message, NULL))
847                 rc = 0;
848         dbus_message_unref(message);
849         return rc;
850
851  error:
852         errno = ENOMEM;
853         return -1;
854 }
855
856 /*
857  * Sends from 'jbus' the signal of 'name' handling the json 'content'.
858  *
859  * Returns 0 in case of success or -1 in case of error.
860  */
861 int jbus_send_signal_j(struct jbus *jbus, const char *name,
862                        struct json_object *content)
863 {
864         const char *str = json_object_to_json_string(content);
865         if (str == NULL) {
866                 errno = ENOMEM;
867                 return -1;
868         }
869         return jbus_send_signal_s(jbus, name, str);
870 }
871
872 /*
873  * Adds to 'jbus' a service handling calls to the 'method' using
874  * the "string" callback 'oncall' and the closure value 'data'.
875  *
876  * The callback 'oncall' is invoked for handling incoming method
877  * calls. It receives 3 parameters:
878  *   1. struct jreq *: a handler to data to be used for replying
879  *   2. const char *: the received string
880  *   3. void *: the closure 'data' set by this function
881  *
882  * Returns 0 in case of success or -1 in case of error.
883  */
884 int jbus_add_service_s(
885                 struct jbus *jbus,
886                 const char *method,
887                 void (*oncall) (struct jreq *, const char *, void *),
888                 void *data)
889 {
890         return add_service(jbus, method, oncall, NULL, data);
891 }
892
893 /*
894  * Adds to 'jbus' a service handling calls to the 'method' using
895  * the "json" callback 'oncall' and the closure value 'data'.
896  *
897  * The callback 'oncall' is invoked for handling incoming method
898  * calls. It receives 3 parameters:
899  *   1. struct jreq *: a handler to data to be used for replying
900  *   2. struct json_object *: the received json
901  *   3. void *: the closure 'data' set by this function
902  *
903  * Returns 0 in case of success or -1 in case of error.
904  */
905 int jbus_add_service_j(
906                 struct jbus *jbus,
907                 const char *method,
908                 void (*oncall) (struct jreq *, struct json_object *, void *),
909                 void *data)
910 {
911         return add_service(jbus, method, NULL, oncall, data);
912 }
913
914 /*
915  * Start to serve: activate services declared for 'jbus'.
916  * This function, in fact, declares 'jbus' as the receiver
917  * for calls to the destination derived from the path set at
918  * 'jbus' creation.
919  * It also allows 'jbus' to emit signals of that origin.
920  *
921  * Returns 0 in case of success or -1 in case of error.
922  */
923 int jbus_start_serving(struct jbus *jbus)
924 {
925         int status = dbus_bus_request_name(jbus->connection, jbus->name,
926                                         DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
927         switch (status) {
928         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
929         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
930                 return 0;
931         case DBUS_REQUEST_NAME_REPLY_EXISTS:
932         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
933         default:
934                 errno = EADDRINUSE;
935                 return -1;
936         }
937 }
938
939 /*
940  * Fills the at least 'njbuses' structures of array 'fds' with data needed
941  * to poll the 'njbuses' buses pointed by 'jbuses'.
942  *
943  * Returns the count of 'fds' structures filled.
944  */
945 int jbus_fill_pollfds(struct jbus **jbuses, int njbuses, struct pollfd *fds)
946 {
947         int i, r;
948
949         for (r = i = 0; i < njbuses; i++) {
950                 if (jbuses[i]->watchnr) {
951                         fds[r].fd = jbuses[i]->watchfd;
952                         fds[r].events = jbuses[i]->watchflags;
953                         r++;
954                 }
955         }
956         return r;
957 }
958
959 /*
960  * Dispatchs a maximum of 'maxcount' events received by poll in 'fds' for the
961  * 'njbuses' jbuses of the array 'jbuses'.
962  *
963  * Returns the count of event dispatched.
964  */
965 int jbus_dispatch_pollfds(
966                 struct jbus **jbuses,
967                 int njbuses,
968                 struct pollfd *fds,
969                 int maxcount)
970 {
971         int i, r, n;
972         DBusDispatchStatus sts;
973
974         for (r = n = i = 0; i < njbuses && n < maxcount; i++) {
975                 if (jbuses[i]->watchnr && fds[r].fd == jbuses[i]->watchfd) {
976                         if (fds[r].revents) {
977                                 dbus_connection_read_write(
978                                                 jbuses[i]->connection, 0);
979                                 sts = dbus_connection_get_dispatch_status(
980                                                         jbuses[i]->connection);
981                                 while (sts == DBUS_DISPATCH_DATA_REMAINS
982                                                         && n < maxcount) {
983                                         sts = dbus_connection_dispatch(
984                                                         jbuses[i]->connection);
985                                         n++;
986                                 }
987                         }
988                         r++;
989                 }
990         }
991         return n;
992 }
993
994 /*
995  * Dispatches 'maxcount' of buffered data from the 'njbuses' jbuses of the
996  * array 'jbuses'.
997  *
998  * Returns the count of event dispatched.
999  */
1000 int jbus_dispatch_multiple(struct jbus **jbuses, int njbuses, int maxcount)
1001 {
1002         int i, r;
1003         DBusDispatchStatus sts;
1004
1005         for (i = r = 0; i < njbuses && r < maxcount; i++) {
1006                 dbus_connection_read_write(jbuses[i]->connection, 0);
1007                 sts = dbus_connection_get_dispatch_status(
1008                                                         jbuses[i]->connection);
1009                 while (sts == DBUS_DISPATCH_DATA_REMAINS && r < maxcount) {
1010                         sts = dbus_connection_dispatch(jbuses[i]->connection);
1011                         r++;
1012                 }
1013         }
1014         return r;
1015 }
1016
1017 /*
1018  * Polls during at most 'toms' milliseconds and dispatches 'maxcount'
1019  * of events from the 'njbuses' jbuses of the array 'jbuses'.
1020  *
1021  * Returns the count of event dispatched or -1 in case of error.
1022  */
1023 int jbus_read_write_dispatch_multiple(
1024                 struct jbus **jbuses,
1025                 int njbuses,
1026                 int toms,
1027                 int maxcount)
1028 {
1029         int n, r, s;
1030         struct pollfd *fds;
1031
1032         if (njbuses < 0 || njbuses > 100) {
1033                 errno = EINVAL;
1034                 return -1;
1035         }
1036         fds = alloca((unsigned)njbuses * sizeof *fds);
1037         assert(fds != NULL);
1038
1039         r = jbus_dispatch_multiple(jbuses, njbuses, maxcount);
1040         if (r)
1041                 return r;
1042         n = jbus_fill_pollfds(jbuses, njbuses, fds);
1043         for (;;) {
1044                 s = poll(fds, (nfds_t) n, toms);
1045                 if (s >= 0)
1046                         break;
1047                 if (errno != EINTR)
1048                         return r ? r : s;
1049                 toms = 0;
1050         }
1051         n = jbus_dispatch_pollfds(jbuses, njbuses, fds, maxcount - r);
1052         return n >= 0 ? r + n : r ? r : n;
1053 }
1054
1055 /*
1056  * Polls during at most 'toms' milliseconds and dispatches
1057  * the events from 'jbus'.
1058  *
1059  * Returns the count of event dispatched or -1 in case of error.
1060  */
1061 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
1062 {
1063         int r = jbus_read_write_dispatch_multiple(&jbus, 1, toms, 1000);
1064         return r < 0 ? r : 0;
1065 }
1066
1067 /*
1068  * Asynchronous call to 'method' of 'jbus' passing the string 'query'.
1069  * On response, the function 'onresp' is called with the returned string
1070  * value and the closure 'data'.
1071  * The function 'onresp' is invoked with 3 parameters:
1072  *   1. int: 0 if no error or -1 if error.
1073  *   2. const char *: the returned string (might be NULL if error)
1074  *   3. void *: the closure 'data'
1075  *
1076  * Returns 0 in case of success or -1 in case of error.
1077  */
1078 int jbus_call_ss(
1079                 struct jbus *jbus,
1080                 const char *method,
1081                 const char *query,
1082                 void (*onresp) (int, const char *, void *),
1083                 void *data)
1084 {
1085         return call(jbus, method, query, onresp, NULL, data);
1086 }
1087
1088 /*
1089  * Asynchronous call to 'method' of 'jbus' passing the string 'query'.
1090  * On response, the function 'onresp' is called with the returned json
1091  * value and the closure 'data'.
1092  * The function 'onresp' is invoked with 3 parameters:
1093  *   1. int: 0 if no error or -1 if error.
1094  *   2. const char *: the returned json (might be NULL if error)
1095  *   3. void *: the closure 'data'
1096  *
1097  * Returns 0 in case of success or -1 in case of error.
1098  */
1099 int jbus_call_sj(
1100                 struct jbus *jbus,
1101                 const char *method,
1102                 const char *query,
1103                 void (*onresp) (int, struct json_object *, void *),
1104                 void *data)
1105 {
1106         return call(jbus, method, query, NULL, onresp, data);
1107 }
1108
1109 /*
1110  * Asynchronous call to 'method' of 'jbus' passing the json 'query'.
1111  * On response, the function 'onresp' is called with the returned string
1112  * value and the closure 'data'.
1113  * The function 'onresp' is invoked with 3 parameters:
1114  *   1. int: 0 if no error or -1 if error.
1115  *   2. const char *: the returned string (might be NULL if error)
1116  *   3. void *: the closure 'data'
1117  *
1118  * Returns 0 in case of success or -1 in case of error.
1119  */
1120 int jbus_call_js(
1121                 struct jbus *jbus,
1122                 const char *method,
1123                 struct json_object *query,
1124                 void (*onresp) (int, const char *, void *),
1125                 void *data)
1126 {
1127         const char *str = json_object_to_json_string(query);
1128         if (str == NULL) {
1129                 errno = ENOMEM;
1130                 return -1;
1131         }
1132         return call(jbus, method, str, onresp, NULL, data);
1133 }
1134
1135 /*
1136  * Asynchronous call to 'method' of 'jbus' passing the json 'query'.
1137  * On response, the function 'onresp' is called with the returned json
1138  * value and the closure 'data'.
1139  * The function 'onresp' is invoked with 3 parameters:
1140  *   1. int: 0 if no error or -1 if error.
1141  *   2. const char *: the returned json (might be NULL if error)
1142  *   3. void *: the closure 'data'
1143  *
1144  * Returns 0 in case of success or -1 in case of error.
1145  */
1146 int jbus_call_jj(
1147                 struct jbus *jbus,
1148                 const char *method,
1149                 struct json_object *query,
1150                 void (*onresp) (int, struct json_object *, void *),
1151                 void *data)
1152 {
1153         const char *str = json_object_to_json_string(query);
1154         if (str == NULL) {
1155                 errno = ENOMEM;
1156                 return -1;
1157         }
1158         return call(jbus, method, str, NULL, onresp, data);
1159 }
1160
1161 /*
1162  * Synchronous call to 'method' of 'jbus' passing the string 'query'.
1163  * The returned string response is returned.
1164  *
1165  * Returns the string response or NULL in case of error.
1166  */
1167 char *jbus_call_ss_sync(
1168                 struct jbus *jbus,
1169                 const char *method,
1170                 const char *query)
1171 {
1172         struct respsync synchro;
1173         synchro.value = NULL;
1174         synchro.replied =
1175             jbus_call_ss(jbus, method, query, sync_of_replies, &synchro);
1176         while (!synchro.replied && !jbus_read_write_dispatch(jbus, -1)) ;
1177         return synchro.value;
1178 }
1179
1180 /*
1181  * Synchronous call to 'method' of 'jbus' passing the string 'query'.
1182  * The returned json response is returned.
1183  *
1184  * Returns the json response or NULL in case of error.
1185  */
1186 struct json_object *jbus_call_sj_sync(
1187                 struct jbus *jbus,
1188                 const char *method,
1189                 const char *query)
1190 {
1191         struct json_object *obj;
1192         char *str = jbus_call_ss_sync(jbus, method, query);
1193         if (str == NULL)
1194                 obj = NULL;
1195         else {
1196                 jparse(jbus, str, &obj);
1197                 free(str);
1198         }
1199         return obj;
1200 }
1201
1202 /*
1203  * Synchronous call to 'method' of 'jbus' passing the json 'query'.
1204  * The returned string response is returned.
1205  *
1206  * Returns the string response or NULL in case of error.
1207  */
1208 char *jbus_call_js_sync(
1209                 struct jbus *jbus,
1210                 const char *method,
1211                 struct json_object *query)
1212 {
1213         const char *str = json_object_to_json_string(query);
1214         if (str == NULL) {
1215                 errno = ENOMEM;
1216                 return NULL;
1217         }
1218         return jbus_call_ss_sync(jbus, method, str);
1219 }
1220
1221 /*
1222  * Synchronous call to 'method' of 'jbus' passing the json 'query'.
1223  * The returned json response is returned.
1224  *
1225  * Returns the json response or NULL in case of error.
1226  */
1227 struct json_object *jbus_call_jj_sync(
1228                 struct jbus *jbus,
1229                 const char *method,
1230                 struct json_object *query)
1231 {
1232         const char *str = json_object_to_json_string(query);
1233         if (str == NULL) {
1234                 errno = ENOMEM;
1235                 return NULL;
1236         }
1237         return jbus_call_sj_sync(jbus, method, str);
1238 }
1239
1240 /*
1241  * Records for 'jbus' the string signal handler 'onsig' with closure 'data'
1242  * for the signal of 'name'.
1243  * The callback handler is called with 2 arguments:
1244  *   1. char *: the string parameter associated to the signal
1245  *   2. void *: the closure data.
1246  *
1247  * Returns 0 in case of success or -1 otherwise.
1248  */
1249 int jbus_on_signal_s(
1250                 struct jbus *jbus,
1251                 const char *name,
1252                 void (*onsig) (const char *, void *),
1253                 void *data)
1254 {
1255         return add_signal(jbus, name, onsig, NULL, data);
1256 }
1257
1258 /*
1259  * Records for 'jbus' the json signal handler 'onsig' with closure 'data'
1260  * for the signal of 'name'.
1261  * The callback handler is called with 2 arguments:
1262  *   1. struct json_object *: the json parameter associated to the signal
1263  *   2. void *: the closure data.
1264  *
1265  * Returns 0 in case of success or -1 otherwise.
1266  */
1267 int jbus_on_signal_j(
1268                 struct jbus *jbus,
1269                 const char *name,
1270                 void (*onsig) (struct json_object *, void *),
1271                 void *data)
1272 {
1273         return add_signal(jbus, name, NULL, onsig, data);
1274 }
1275
1276 /****************** FEW LITTLE TESTS *****************************************/
1277
1278 #ifdef SERVER
1279 #include <stdio.h>
1280 #include <unistd.h>
1281 struct jbus *jbus;
1282 void ping(struct jreq *jreq, struct json_object *request, void *unused)
1283 {
1284         printf("ping(%s) -> %s\n", json_object_to_json_string(request),
1285                json_object_to_json_string(request));
1286         jbus_reply_j(jreq, request);
1287         json_object_put(request);
1288 }
1289
1290 void incr(struct jreq *jreq, struct json_object *request, void *unused)
1291 {
1292         static int counter = 0;
1293         struct json_object *res = json_object_new_int(++counter);
1294         printf("incr(%s) -> %s\n", json_object_to_json_string(request),
1295                json_object_to_json_string(res));
1296         jbus_reply_j(jreq, res);
1297         jbus_send_signal_j(jbus, "incremented", res);
1298         json_object_put(res);
1299         json_object_put(request);
1300 }
1301
1302 int main()
1303 {
1304         int s1, s2, s3;
1305         jbus = create_jbus(1, "/bzh/iot/jdbus");
1306         s1 = jbus_add_service_j(jbus, "ping", ping, NULL);
1307         s2 = jbus_add_service_j(jbus, "incr", incr, NULL);
1308         s3 = jbus_start_serving(jbus);
1309         printf("started %d %d %d\n", s1, s2, s3);
1310         while (!jbus_read_write_dispatch(jbus, -1)) ;
1311 }
1312 #endif
1313 #ifdef CLIENT
1314 #include <stdio.h>
1315 #include <unistd.h>
1316 struct jbus *jbus;
1317 void onresp(int status, struct json_object *response, void *data)
1318 {
1319         printf("resp: %d, %s, %s\n", status, (char *)data,
1320                json_object_to_json_string(response));
1321         json_object_put(response);
1322 }
1323
1324 void signaled(const char *data)
1325 {
1326         printf("signaled with {%s}\n", data);
1327 }
1328
1329 int main()
1330 {
1331         int i = 10;
1332         jbus = create_jbus(1, "/bzh/iot/jdbus");
1333         jbus_on_signal_s(jbus, "incremented", signaled);
1334         while (i--) {
1335                 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}",
1336                              onresp, "ping");
1337                 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp,
1338                              "incr");
1339                 jbus_read_write_dispatch(jbus, 1);
1340         }
1341         printf("[[[%s]]]\n",
1342                jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
1343         while (!jbus_read_write_dispatch(jbus, -1)) ;
1344 }
1345 #endif