2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <json-c/json.h>
23 #include <systemd/sd-bus.h>
24 #include <systemd/sd-bus-protocol.h>
26 #define AFB_BINDING_VERSION 1
27 #include <afb/afb-binding.h>
30 * the interface to afb-daemon
32 const struct afb_binding_interface *afbitf;
35 * union of possible dbus values
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);
54 * Get the string of 'key' from 'obj'
55 * Returns NULL if 'key' isn't in 'obj'
57 static const char *strval(struct json_object *obj, const char *key)
59 struct json_object *keyval;
60 return json_object_object_get_ex(obj, key, &keyval) ? json_object_get_string(keyval) : NULL;
64 * Signature of a json object
66 static const char *signature_for_json(struct json_object *obj)
68 switch (json_object_get_type(obj)) {
72 case json_type_boolean:
74 case json_type_double:
78 case json_type_object:
82 case json_type_string:
88 * Length of a single complete type
90 static int lentype(const char *signature, int allows_dict, int allows_not_basic)
93 switch(signature[0]) {
95 case SD_BUS_TYPE_ARRAY:
96 if (!allows_not_basic)
98 rc = lentype(signature + 1, 1, 1);
103 case SD_BUS_TYPE_STRUCT_BEGIN:
104 if (!allows_not_basic)
107 rc = lentype(signature + len, 0, 1);
108 while (rc > 0 && signature[len] != SD_BUS_TYPE_STRUCT_END) {
110 rc = lentype(signature + len, 0, 1);
116 case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
117 if (!allows_not_basic || !allows_dict)
119 rc = lentype(signature + 1, 0, 0);
123 rc = lentype(signature + len, 0, 1);
124 if (rc < 0 || signature[len + rc] != SD_BUS_TYPE_DICT_ENTRY_END)
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:
143 * Unpack a D-Bus message to a json object
145 static int unpacksingle(struct sd_bus_message *msg, struct json_object **result)
151 struct json_object *item;
154 rc = sd_bus_message_peek_type(msg, &c, &content);
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);
175 case SD_BUS_TYPE_BOOLEAN:
176 *result = json_object_new_boolean(any.i32);
178 case SD_BUS_TYPE_BYTE:
179 *result = json_object_new_int(any.u8);
181 case SD_BUS_TYPE_INT16:
182 *result = json_object_new_int(any.i16);
184 case SD_BUS_TYPE_UINT16:
185 *result = json_object_new_int(any.u16);
187 case SD_BUS_TYPE_INT32:
188 *result = json_object_new_int(any.i32);
190 case SD_BUS_TYPE_UINT32:
191 *result = json_object_new_int64(any.u32);
193 case SD_BUS_TYPE_INT64:
194 *result = json_object_new_int64(any.i64);
196 case SD_BUS_TYPE_UINT64:
197 *result = json_object_new_int64((int64_t)any.u64);
199 case SD_BUS_TYPE_DOUBLE:
200 *result = json_object_new_string(any.cstr);
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);
208 return *result == NULL ? -1 : 1;
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);
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();
222 rc = sd_bus_message_enter_container(msg, 0, NULL);
227 rc = sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, &any);
230 rc = unpacksingle(msg, &item);
233 json_object_object_add(*result, any.cstr, item);
234 rc = sd_bus_message_exit_container(msg);
239 rc = unpacklist(msg, result);
243 rc = sd_bus_message_exit_container(msg);
251 json_object_put(*result);
256 * Unpack a D-Bus message to a json object
258 static int unpacklist(struct sd_bus_message *msg, struct json_object **result)
261 struct json_object *item;
263 /* allocates the result */
264 *result = json_object_new_array();
268 /* read the values */
270 rc = unpacksingle(msg, &item);
275 json_object_array_add(*result, item);
278 json_object_put(*result);
283 static int packsingle(struct sd_bus_message *msg, const char *signature, struct json_object *item)
285 int index, count, rc, len;
288 struct json_object_iterator it, end;
290 len = lentype(signature, 0, 1);
294 switch (*signature) {
295 case SD_BUS_TYPE_BOOLEAN:
296 any.i32 = json_object_get_boolean(item);
299 case SD_BUS_TYPE_BYTE:
300 any.i32 = json_object_get_int(item);
301 if (any.i32 != (int32_t)(uint8_t)any.i32)
303 any.u8 = (uint8_t)any.i32;
306 case SD_BUS_TYPE_INT16:
307 any.i32 = json_object_get_int(item);
308 if (any.i32 != (int32_t)(int16_t)any.i32)
310 any.i16 = (int16_t)any.i32;
313 case SD_BUS_TYPE_UINT16:
314 any.i32 = json_object_get_int(item);
315 if (any.i32 != (int32_t)(uint16_t)any.i32)
317 any.u16 = (uint16_t)any.i32;
320 case SD_BUS_TYPE_INT32:
321 any.i64 = json_object_get_int64(item);
322 if (any.i64 != (int64_t)(int32_t)any.i64)
324 any.i32 = (int32_t)any.i64;
327 case SD_BUS_TYPE_UINT32:
328 any.i64 = json_object_get_int64(item);
329 if (any.i64 != (int64_t)(uint32_t)any.i64)
331 any.u32 = (uint32_t)any.i64;
334 case SD_BUS_TYPE_INT64:
335 any.i64 = json_object_get_int64(item);
338 case SD_BUS_TYPE_UINT64:
339 any.u64 = (uint64_t)json_object_get_int64(item);
342 case SD_BUS_TYPE_DOUBLE:
343 any.dbl = json_object_get_double(item);
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);
352 case SD_BUS_TYPE_VARIANT:
353 signature = signature_for_json(item);
354 if (signature == NULL)
356 rc = sd_bus_message_open_container(msg, SD_BUS_TYPE_VARIANT, signature);
359 rc = packsingle(msg, signature, item);
362 rc = sd_bus_message_close_container(msg);
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);
372 if (json_object_is_type(item, json_type_array)) {
374 count = json_object_array_length(item);
376 while(index < count) {
377 rc = packsingle(msg, subsig, json_object_array_get_idx(item, index++));
382 /* Not an array! Check if it matches an string dictionnary */
383 if (!json_object_is_type(item, json_type_object))
385 if (*subsig++ != SD_BUS_TYPE_DICT_ENTRY_BEGIN)
387 if (*subsig != SD_BUS_TYPE_STRING)
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);
397 any.cstr = json_object_iter_peek_name(&it);
398 rc = sd_bus_message_append_basic(msg, *subsig, &any);
401 rc = packsingle(msg, subsig + 1, json_object_iter_peek_value(&it));
404 rc = sd_bus_message_close_container(msg);
407 json_object_iter_next(&it);
410 rc = sd_bus_message_close_container(msg);
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,
423 rc = packlist(msg, subsig, item);
426 rc = sd_bus_message_close_container(msg);
435 rc = sd_bus_message_append_basic(msg, *signature, &any);
444 static int packlist(struct sd_bus_message *msg, const char *signature, struct json_object *list)
446 int rc, count, index, scan;
447 struct json_object *item;
457 if (!json_object_is_type(list, json_type_array)) {
458 /* down grade gracefully to single */
459 rc = packsingle(msg, signature, list);
463 if (signature[scan] != 0)
468 /* iterate over elements */
469 count = json_object_array_length(list);
473 if (index == count && signature[scan] == 0)
475 if (index == count || signature[scan] == 0)
479 item = json_object_array_get_idx(list, index);
484 rc = packsingle(msg, signature + scan, item);
500 static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_error *ret_error)
502 struct json_object *obj = NULL;
504 const sd_bus_error *err;
506 err = sd_bus_message_get_error(msg);
508 afb_req_fail_f(*req, "failed", "DBus-error-name: %s, DBus-error-message: %s", err->name, err->message);
510 rc = unpacklist(msg, &obj);
512 afb_req_fail(*req, "failed", "can't unpack");
514 afb_req_success(*req, obj, NULL);
516 json_object_put(obj);
523 * Make a raw call to DBUS method
524 * The query should have:
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"
535 static void rawcall(struct afb_req req)
537 struct json_object *obj;
538 struct json_object *args;
541 const char *destination;
543 const char *interface;
545 const char *signature;
547 struct sd_bus_message *msg = NULL;
552 obj = afb_req_json(req);
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)
565 signature = strval(obj, "signature") ? : "";
567 json_object_object_get_ex(obj, "arguments", &args);
570 busname = strval(obj, "bus");
571 if (busname != NULL && !strcmp(busname, "system"))
572 bus = afb_daemon_get_system_bus(afbitf->daemon);
574 bus = afb_daemon_get_user_bus(afbitf->daemon);
576 /* creates the message */
577 rc = sd_bus_message_new_method_call(bus, &msg, destination, path, interface, member);
580 rc = packlist(msg, signature, args);
585 rc = sd_bus_call_async(bus, NULL, msg, (void*)on_rawcall_reply, afb_req_store(req), -1);
591 afb_req_fail(req, "failed", "internal error");
595 afb_req_fail(req, "failed", "bad request");
598 sd_bus_message_unref(msg);
602 * array of the verbs exported to afb-daemon
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 */
611 * description of the binding for afb-daemon
613 static const struct afb_binding binding_description =
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 */
625 * activation function for registering the binding called by afb-daemon
627 const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf)
629 afbitf = itf; /* records the interface for accessing afb-daemon */
630 return &binding_description; /* returns the description of the binding */