Add backward compatibility and remarks
[src/app-framework-binder.git] / bindings / intrinsics / afb-dbus-binding.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <string.h>
21 #include <json-c/json.h>
22
23 #include <systemd/sd-bus.h>
24 #include <systemd/sd-bus-protocol.h>
25
26 #define AFB_BINDING_VERSION 1
27 #include <afb/afb-binding.h>
28
29 /*
30  * the interface to afb-daemon
31  */
32 const struct afb_binding_interface *afbitf;
33
34 /*
35  * union of possible dbus values
36  */
37 union any {
38         uint8_t u8;
39         int16_t i16;
40         uint16_t u16;
41         int32_t i32;
42         uint32_t u32;
43         int64_t i64;
44         uint64_t u64;
45         double dbl;
46         const char *cstr;
47         char *str;
48 };
49
50 static int unpacklist(struct sd_bus_message *msg, struct json_object **result);
51 static int packlist(struct sd_bus_message *msg, const char *signature, struct json_object *list);
52
53 /*
54  * Get the string of 'key' from 'obj'
55  * Returns NULL if 'key' isn't in 'obj'
56  */
57 static const char *strval(struct json_object *obj, const char *key)
58 {
59         struct json_object *keyval;
60         return json_object_object_get_ex(obj, key, &keyval) ? json_object_get_string(keyval) : NULL;
61 }
62
63 /*
64  * Signature of a json object
65  */
66 static const char *signature_for_json(struct json_object *obj)
67 {
68         switch (json_object_get_type(obj)) {
69         default:
70         case json_type_null:
71                 return NULL;
72         case json_type_boolean:
73                 return "b";
74         case json_type_double:
75                 return "d";
76         case json_type_int:
77                 return "i";
78         case json_type_object:
79                 return "a{sv}";
80         case json_type_array:
81                 return "av";
82         case json_type_string:
83                 return "s";
84         }
85 }
86
87 /*
88  * Length of a single complete type
89  */
90 static int lentype(const char *signature, int allows_dict, int allows_not_basic)
91 {
92         int rc, len;
93         switch(signature[0]) {
94
95         case SD_BUS_TYPE_ARRAY:
96                 if (!allows_not_basic)
97                         break;
98                 rc = lentype(signature + 1, 1, 1);
99                 if (rc < 0)
100                         break;
101                 return 1 + rc;
102
103         case SD_BUS_TYPE_STRUCT_BEGIN:
104                 if (!allows_not_basic)
105                         break;
106                 len = 1;
107                 rc = lentype(signature + len, 0, 1);
108                 while (rc > 0 && signature[len] != SD_BUS_TYPE_STRUCT_END) {
109                         len += rc;
110                         rc = lentype(signature + len, 0, 1);
111                 }
112                 if (rc < 0)
113                         break;
114                 return 1 + len;
115
116         case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
117                 if (!allows_not_basic || !allows_dict)
118                         break;
119                 rc = lentype(signature + 1, 0, 0);
120                 if (rc < 0)
121                         break;
122                 len = 1 + rc;
123                 rc = lentype(signature + len, 0, 1);
124                 if (rc < 0 || signature[len + rc] != SD_BUS_TYPE_DICT_ENTRY_END)
125                         break;
126                 return len + rc + 1;
127
128         case '\x0':
129         case SD_BUS_TYPE_STRUCT:
130         case SD_BUS_TYPE_STRUCT_END:
131         case SD_BUS_TYPE_DICT_ENTRY:
132         case SD_BUS_TYPE_DICT_ENTRY_END:
133                 break;
134
135         default:
136                 return 1;
137         }
138         return -1;
139 }
140
141
142 /*
143  * Unpack a D-Bus message to a json object
144  */
145 static int unpacksingle(struct sd_bus_message *msg, struct json_object **result)
146 {
147         char c;
148         int rc;
149         union any any;
150         const char *content;
151         struct json_object *item;
152
153         *result = NULL;
154         rc = sd_bus_message_peek_type(msg, &c, &content);
155         if (rc <= 0)
156                 return rc;
157
158         switch (c) {
159         case SD_BUS_TYPE_BYTE:
160         case SD_BUS_TYPE_BOOLEAN:
161         case SD_BUS_TYPE_INT16:
162         case SD_BUS_TYPE_UINT16:
163         case SD_BUS_TYPE_INT32:
164         case SD_BUS_TYPE_UINT32:
165         case SD_BUS_TYPE_INT64:
166         case SD_BUS_TYPE_UINT64:
167         case SD_BUS_TYPE_DOUBLE:
168         case SD_BUS_TYPE_STRING:
169         case SD_BUS_TYPE_OBJECT_PATH:
170         case SD_BUS_TYPE_SIGNATURE:
171                 rc = sd_bus_message_read_basic(msg, c, &any);
172                 if (rc < 0)
173                         goto error;
174                 switch (c) {
175                 case SD_BUS_TYPE_BOOLEAN:
176                         *result = json_object_new_boolean(any.i32);
177                         break;
178                 case SD_BUS_TYPE_BYTE:
179                         *result = json_object_new_int(any.u8);
180                         break;
181                 case SD_BUS_TYPE_INT16:
182                         *result = json_object_new_int(any.i16);
183                         break;
184                 case SD_BUS_TYPE_UINT16:
185                         *result = json_object_new_int(any.u16);
186                         break;
187                 case SD_BUS_TYPE_INT32:
188                         *result = json_object_new_int(any.i32);
189                         break;
190                 case SD_BUS_TYPE_UINT32:
191                         *result = json_object_new_int64(any.u32);
192                         break;
193                 case SD_BUS_TYPE_INT64:
194                         *result = json_object_new_int64(any.i64);
195                         break;
196                 case SD_BUS_TYPE_UINT64:
197                         *result = json_object_new_int64((int64_t)any.u64);
198                         break;
199                 case SD_BUS_TYPE_DOUBLE:
200                         *result = json_object_new_string(any.cstr);
201                         break;
202                 case SD_BUS_TYPE_STRING:
203                 case SD_BUS_TYPE_OBJECT_PATH:
204                 case SD_BUS_TYPE_SIGNATURE:
205                         *result = json_object_new_string(any.cstr);
206                         break;
207                 }
208                 return *result == NULL ? -1 : 1;
209
210         case SD_BUS_TYPE_ARRAY:
211         case SD_BUS_TYPE_VARIANT:
212         case SD_BUS_TYPE_STRUCT:
213         case SD_BUS_TYPE_DICT_ENTRY:
214                 rc = sd_bus_message_enter_container(msg, c, content);
215                 if (rc < 0)
216                         goto error;
217                 if (c == SD_BUS_TYPE_ARRAY && content[0] == SD_BUS_TYPE_DICT_ENTRY_BEGIN && content[1] == SD_BUS_TYPE_STRING) {
218                         *result = json_object_new_object();
219                         if (*result == NULL)
220                                 return -1;
221                         for(;;) {
222                                 rc = sd_bus_message_enter_container(msg, 0, NULL);
223                                 if (rc < 0)
224                                         goto error;
225                                 if (rc == 0)
226                                         break;
227                                 rc = sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, &any);
228                                 if (rc < 0)
229                                         goto error;
230                                 rc = unpacksingle(msg, &item);
231                                 if (rc < 0)
232                                         goto error;
233                                 json_object_object_add(*result, any.cstr, item);
234                                 rc = sd_bus_message_exit_container(msg);
235                                 if (rc < 0)
236                                         goto error;
237                         }
238                 } else {
239                         rc = unpacklist(msg, result);
240                         if (rc < 0)
241                                 goto error;
242                 }
243                 rc = sd_bus_message_exit_container(msg);
244                 if (rc < 0)
245                         goto error;
246                 return 1;
247         default:
248                 goto error;
249         }
250 error:
251         json_object_put(*result);
252         return -1;
253 }
254
255 /*
256  * Unpack a D-Bus message to a json object
257  */
258 static int unpacklist(struct sd_bus_message *msg, struct json_object **result)
259 {
260         int rc;
261         struct json_object *item;
262
263         /* allocates the result */
264         *result = json_object_new_array();
265         if (*result == NULL)
266                 goto error;
267
268         /* read the values */
269         for (;;) {
270                 rc = unpacksingle(msg, &item);
271                 if (rc < 0)
272                         goto error;
273                 if (rc == 0)
274                         return 0;
275                 json_object_array_add(*result, item);
276         }
277 error:
278         json_object_put(*result);
279         *result = NULL;
280         return -1;
281 }
282
283 static int packsingle(struct sd_bus_message *msg, const char *signature, struct json_object *item)
284 {
285         int index, count, rc, len;
286         union any any;
287         char *subsig;
288         struct json_object_iterator it, end;
289
290         len = lentype(signature, 0, 1);
291         if (len < 0)
292                 goto error;
293
294         switch (*signature) {
295         case SD_BUS_TYPE_BOOLEAN:
296                 any.i32 = json_object_get_boolean(item);
297                 break;
298
299         case SD_BUS_TYPE_BYTE:
300                 any.i32 = json_object_get_int(item);
301                 if (any.i32 != (int32_t)(uint8_t)any.i32)
302                         goto error;
303                 any.u8 = (uint8_t)any.i32;
304                 break;
305
306         case SD_BUS_TYPE_INT16:
307                 any.i32 = json_object_get_int(item);
308                 if (any.i32 != (int32_t)(int16_t)any.i32)
309                         goto error;
310                 any.i16 = (int16_t)any.i32;
311                 break;
312
313         case SD_BUS_TYPE_UINT16:
314                 any.i32 = json_object_get_int(item);
315                 if (any.i32 != (int32_t)(uint16_t)any.i32)
316                         goto error;
317                 any.u16 = (uint16_t)any.i32;
318                 break;
319
320         case SD_BUS_TYPE_INT32:
321                 any.i64 = json_object_get_int64(item);
322                 if (any.i64 != (int64_t)(int32_t)any.i64)
323                         goto error;
324                 any.i32 = (int32_t)any.i64;
325                 break;
326
327         case SD_BUS_TYPE_UINT32:
328                 any.i64 = json_object_get_int64(item);
329                 if (any.i64 != (int64_t)(uint32_t)any.i64)
330                         goto error;
331                 any.u32 = (uint32_t)any.i64;
332                 break;
333
334         case SD_BUS_TYPE_INT64:
335                 any.i64 = json_object_get_int64(item);
336                 break;
337
338         case SD_BUS_TYPE_UINT64:
339                 any.u64 = (uint64_t)json_object_get_int64(item);
340                 break;
341
342         case SD_BUS_TYPE_DOUBLE:
343                 any.dbl = json_object_get_double(item);
344                 break;
345
346         case SD_BUS_TYPE_STRING:
347         case SD_BUS_TYPE_OBJECT_PATH:
348         case SD_BUS_TYPE_SIGNATURE:
349                 any.cstr = json_object_get_string(item);
350                 break;
351
352         case SD_BUS_TYPE_VARIANT:
353                 signature = signature_for_json(item);
354                 if (signature == NULL)
355                         goto error;
356                 rc = sd_bus_message_open_container(msg, SD_BUS_TYPE_VARIANT, signature);
357                 if (rc < 0)
358                         goto error;
359                 rc = packsingle(msg, signature, item);
360                 if (rc < 0)
361                         goto error;
362                 rc = sd_bus_message_close_container(msg);
363                 if (rc < 0)
364                         goto error;
365                 return len;
366
367         case SD_BUS_TYPE_ARRAY:
368                 subsig = strndupa(signature + 1, len - 1);
369                 rc = sd_bus_message_open_container(msg, SD_BUS_TYPE_ARRAY, subsig);
370                 if (rc < 0)
371                         goto error;
372                 if (json_object_is_type(item, json_type_array)) {
373                         /* Is an array! */
374                         count = json_object_array_length(item);
375                         index = 0;
376                         while(index < count) {
377                                 rc = packsingle(msg, subsig, json_object_array_get_idx(item, index++));
378                                 if (rc < 0)
379                                         goto error;
380                         }
381                 } else {
382                         /* Not an array! Check if it matches an string dictionnary */
383                         if (!json_object_is_type(item, json_type_object))
384                                 goto error;
385                         if (*subsig++ != SD_BUS_TYPE_DICT_ENTRY_BEGIN)
386                                 goto error;
387                         if (*subsig != SD_BUS_TYPE_STRING)
388                                 goto error;
389                         /* iterate the object values */
390                         subsig[strlen(subsig) - 1] = 0;
391                         it = json_object_iter_begin(item);
392                         end = json_object_iter_end(item);
393                         while (!json_object_iter_equal(&it, &end)) {
394                                 rc = sd_bus_message_open_container(msg, SD_BUS_TYPE_DICT_ENTRY, subsig);
395                                 if (rc < 0)
396                                         goto error;
397                                 any.cstr = json_object_iter_peek_name(&it);
398                                 rc = sd_bus_message_append_basic(msg, *subsig, &any);
399                                 if (rc < 0)
400                                         goto error;
401                                 rc = packsingle(msg, subsig + 1, json_object_iter_peek_value(&it));
402                                 if (rc < 0)
403                                         goto error;
404                                 rc = sd_bus_message_close_container(msg);
405                                 if (rc < 0)
406                                         goto error;
407                                 json_object_iter_next(&it);
408                         }
409                 }
410                 rc = sd_bus_message_close_container(msg);
411                 if (rc < 0)
412                         goto error;
413                 return len;
414
415         case SD_BUS_TYPE_STRUCT_BEGIN:
416         case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
417                 subsig = strndupa(signature + 1, len - 2);
418                 rc = sd_bus_message_open_container(msg,
419                         ((*signature) == SD_BUS_TYPE_STRUCT_BEGIN) ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY,
420                         subsig);
421                 if (rc < 0)
422                         goto error;
423                 rc = packlist(msg, subsig, item);
424                 if (rc < 0)
425                         goto error;
426                 rc = sd_bus_message_close_container(msg);
427                 if (rc < 0)
428                         goto error;
429                 return len;
430
431         default:
432                 goto error;
433         }
434
435         rc = sd_bus_message_append_basic(msg, *signature, &any);
436         if (rc < 0)
437                 goto error;
438         return len;
439
440 error:
441         return -1;
442 }
443
444 static int packlist(struct sd_bus_message *msg, const char *signature, struct json_object *list)
445 {
446         int rc, count, index, scan;
447         struct json_object *item;
448
449         scan = 0;
450         if (list == NULL) {
451                 /* empty case */
452                 if (*signature)
453                         goto error;
454                 return scan;
455         }
456
457         if (!json_object_is_type(list, json_type_array)) {
458                 /* down grade gracefully to single */
459                 rc = packsingle(msg, signature, list);
460                 if (rc < 0)
461                         goto error;
462                 scan = rc;
463                 if (signature[scan] != 0)
464                         goto error;
465                 return scan;
466         }
467
468         /* iterate over elements */
469         count = json_object_array_length(list);
470         index = 0;
471         for (;;) {
472                 /* check state */
473                 if (index == count && signature[scan] == 0)
474                         return scan;
475                 if (index == count || signature[scan] == 0)
476                         goto error;
477
478                 /* get the item */
479                 item = json_object_array_get_idx(list, index);
480                 if (item == NULL)
481                         goto error;
482
483                 /* pack the item */
484                 rc = packsingle(msg, signature + scan, item);
485                 if (rc < 0)
486                         goto error;
487
488                 /* advance */
489                 scan += rc;
490                 index++;
491         }
492
493 error:
494         return -(scan + 1);
495 }
496
497 /*
498  * handle the reply
499  */
500 static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_error *ret_error)
501 {
502         struct json_object *obj = NULL;
503         int rc;
504         const sd_bus_error *err;
505
506         err = sd_bus_message_get_error(msg);
507         if (err != NULL)
508                 afb_req_fail_f(*req, "failed", "DBus-error-name: %s, DBus-error-message: %s", err->name, err->message);
509         else {
510                 rc = unpacklist(msg, &obj);
511                 if (rc < 0)
512                         afb_req_fail(*req, "failed", "can't unpack");
513                 else
514                         afb_req_success(*req, obj, NULL);
515         }
516         json_object_put(obj);
517         afb_req_unref(*req);
518         free(req);
519         return 1;
520 }
521
522 /*
523  * Make a raw call to DBUS method
524  * The query should have:
525  *   {
526  *     "bus": "optional: 'system' or 'user' (default)"
527  *     "destination": "destination handling the object",
528  *     "path": "object path",
529  *     "interface": "interface of the call",
530  *     "member": "member of the interface of the call",
531  *     "signature": "signature of the arguments",
532  *     "arguments": "ARRAY of arguments"
533  *   }
534  */
535 static void rawcall(struct afb_req req)
536 {
537         struct json_object *obj;
538         struct json_object *args;
539
540         const char *busname;
541         const char *destination;
542         const char *path;
543         const char *interface;
544         const char *member;
545         const char *signature;
546
547         struct sd_bus_message *msg = NULL;
548         struct sd_bus *bus;
549         int rc;
550
551         /* get the query */
552         obj = afb_req_json(req);
553         if (obj == NULL)
554                 goto internal_error;
555
556         /* get parameters */
557         destination = strval(obj, "destination");
558         path = strval(obj, "path");
559         interface = strval(obj, "interface");
560         member = strval(obj, "member");
561         if (path == NULL || member == NULL)
562                 goto bad_request;
563
564         /* get arguments */
565         signature = strval(obj, "signature") ? : "";
566         args = NULL;
567         json_object_object_get_ex(obj, "arguments", &args);
568
569         /* get bus */
570         busname = strval(obj, "bus");
571         if (busname != NULL && !strcmp(busname, "system"))
572                 bus = afb_daemon_get_system_bus(afbitf->daemon);
573         else
574                 bus = afb_daemon_get_user_bus(afbitf->daemon);
575
576         /* creates the message */
577         rc = sd_bus_message_new_method_call(bus, &msg, destination, path, interface, member);
578         if (rc != 0)
579                 goto internal_error;
580         rc = packlist(msg, signature, args);
581         if (rc < 0)
582                 goto bad_request;
583
584         /*  */
585         rc = sd_bus_call_async(bus, NULL, msg, (void*)on_rawcall_reply, afb_req_store(req), -1);
586         if (rc < 0)
587                 goto internal_error;
588         goto cleanup;
589
590 internal_error:
591         afb_req_fail(req, "failed", "internal error");
592         goto cleanup;
593
594 bad_request:
595         afb_req_fail(req, "failed", "bad request");
596
597 cleanup:
598         sd_bus_message_unref(msg);
599 }
600
601 /*
602  * array of the verbs exported to afb-daemon
603  */
604 static const struct afb_verb_desc_v1 binding_verbs[] = {
605   /* VERB'S NAME       SESSION MANAGEMENT          FUNCTION TO CALL     SHORT DESCRIPTION */
606   { .name= "rawcall",  .session= AFB_SESSION_NONE, .callback= rawcall,  .info= "raw call to dbus method" },
607   { .name= NULL } /* marker for end of the array */
608 };
609
610 /*
611  * description of the binding for afb-daemon
612  */
613 static const struct afb_binding binding_description =
614 {
615   /* description conforms to VERSION 1 */
616   .type= AFB_BINDING_VERSION_1,
617   .v1= {                        /* fills the v1 field of the union when AFB_BINDING_VERSION_1 */
618     .prefix= "dbus",            /* the API name (or binding name or prefix) */
619     .info= "raw dbus binding",  /* short description of of the binding */
620     .verbs = binding_verbs      /* the array describing the verbs of the API */
621   }
622 };
623
624 /*
625  * activation function for registering the binding called by afb-daemon
626  */
627 const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf)
628 {
629         afbitf = itf;                   /* records the interface for accessing afb-daemon */
630         return &binding_description;    /* returns the description of the binding */
631 }
632