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