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