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