2 * Copyright (C) 2016-2019 "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 3
27 #include <afb/afb-binding.h>
30 * union of possible dbus values
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);
49 * Get the string of 'key' from 'obj'
50 * Returns NULL if 'key' isn't in 'obj'
52 static const char *strval(struct json_object *obj, const char *key)
54 struct json_object *keyval;
55 return json_object_object_get_ex(obj, key, &keyval) ? json_object_get_string(keyval) : NULL;
59 * Signature of a json object
61 static const char *signature_for_json(struct json_object *obj)
63 switch (json_object_get_type(obj)) {
67 case json_type_boolean:
69 case json_type_double:
73 case json_type_object:
77 case json_type_string:
83 * Length of a single complete type
85 static int lentype(const char *signature, int allows_dict, int allows_not_basic)
88 switch(signature[0]) {
90 case SD_BUS_TYPE_ARRAY:
91 if (!allows_not_basic)
93 rc = lentype(signature + 1, 1, 1);
98 case SD_BUS_TYPE_STRUCT_BEGIN:
99 if (!allows_not_basic)
102 rc = lentype(signature + len, 0, 1);
103 while (rc > 0 && signature[len] != SD_BUS_TYPE_STRUCT_END) {
105 rc = lentype(signature + len, 0, 1);
111 case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
112 if (!allows_not_basic || !allows_dict)
114 rc = lentype(signature + 1, 0, 0);
118 rc = lentype(signature + len, 0, 1);
119 if (rc < 0 || signature[len + rc] != SD_BUS_TYPE_DICT_ENTRY_END)
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:
138 * Unpack a D-Bus message to a json object
140 static int unpacksingle(struct sd_bus_message *msg, struct json_object **result)
146 struct json_object *item;
149 rc = sd_bus_message_peek_type(msg, &c, &content);
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);
170 case SD_BUS_TYPE_BOOLEAN:
171 *result = json_object_new_boolean(any.i32);
173 case SD_BUS_TYPE_BYTE:
174 *result = json_object_new_int(any.u8);
176 case SD_BUS_TYPE_INT16:
177 *result = json_object_new_int(any.i16);
179 case SD_BUS_TYPE_UINT16:
180 *result = json_object_new_int(any.u16);
182 case SD_BUS_TYPE_INT32:
183 *result = json_object_new_int(any.i32);
185 case SD_BUS_TYPE_UINT32:
186 *result = json_object_new_int64(any.u32);
188 case SD_BUS_TYPE_INT64:
189 *result = json_object_new_int64(any.i64);
191 case SD_BUS_TYPE_UINT64:
192 *result = json_object_new_int64((int64_t)any.u64);
194 case SD_BUS_TYPE_DOUBLE:
195 *result = json_object_new_string(any.cstr);
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);
203 return *result == NULL ? -1 : 1;
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);
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();
217 rc = sd_bus_message_enter_container(msg, 0, NULL);
222 rc = sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, &any);
225 rc = unpacksingle(msg, &item);
228 json_object_object_add(*result, any.cstr, item);
229 rc = sd_bus_message_exit_container(msg);
234 rc = unpacklist(msg, result);
238 rc = sd_bus_message_exit_container(msg);
246 json_object_put(*result);
251 * Unpack a D-Bus message to a json object
253 static int unpacklist(struct sd_bus_message *msg, struct json_object **result)
256 struct json_object *item;
258 /* allocates the result */
259 *result = json_object_new_array();
263 /* read the values */
265 rc = unpacksingle(msg, &item);
270 json_object_array_add(*result, item);
273 json_object_put(*result);
278 static int packsingle(struct sd_bus_message *msg, const char *signature, struct json_object *item)
280 int index, count, rc, len;
283 struct json_object_iterator it, end;
285 len = lentype(signature, 0, 1);
289 switch (*signature) {
290 case SD_BUS_TYPE_BOOLEAN:
291 any.i32 = json_object_get_boolean(item);
294 case SD_BUS_TYPE_BYTE:
295 any.i32 = json_object_get_int(item);
296 if (any.i32 != (int32_t)(uint8_t)any.i32)
298 any.u8 = (uint8_t)any.i32;
301 case SD_BUS_TYPE_INT16:
302 any.i32 = json_object_get_int(item);
303 if (any.i32 != (int32_t)(int16_t)any.i32)
305 any.i16 = (int16_t)any.i32;
308 case SD_BUS_TYPE_UINT16:
309 any.i32 = json_object_get_int(item);
310 if (any.i32 != (int32_t)(uint16_t)any.i32)
312 any.u16 = (uint16_t)any.i32;
315 case SD_BUS_TYPE_INT32:
316 any.i64 = json_object_get_int64(item);
317 if (any.i64 != (int64_t)(int32_t)any.i64)
319 any.i32 = (int32_t)any.i64;
322 case SD_BUS_TYPE_UINT32:
323 any.i64 = json_object_get_int64(item);
324 if (any.i64 != (int64_t)(uint32_t)any.i64)
326 any.u32 = (uint32_t)any.i64;
329 case SD_BUS_TYPE_INT64:
330 any.i64 = json_object_get_int64(item);
333 case SD_BUS_TYPE_UINT64:
334 any.u64 = (uint64_t)json_object_get_int64(item);
337 case SD_BUS_TYPE_DOUBLE:
338 any.dbl = json_object_get_double(item);
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);
347 case SD_BUS_TYPE_VARIANT:
348 signature = signature_for_json(item);
349 if (signature == NULL)
351 rc = sd_bus_message_open_container(msg, SD_BUS_TYPE_VARIANT, signature);
354 rc = packsingle(msg, signature, item);
357 rc = sd_bus_message_close_container(msg);
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);
367 if (json_object_is_type(item, json_type_array)) {
369 count = (int)json_object_array_length(item);
371 while(index < count) {
372 rc = packsingle(msg, subsig, json_object_array_get_idx(item, index++));
377 /* Not an array! Check if it matches an string dictionnary */
378 if (!json_object_is_type(item, json_type_object))
380 if (*subsig++ != SD_BUS_TYPE_DICT_ENTRY_BEGIN)
382 if (*subsig != SD_BUS_TYPE_STRING)
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);
392 any.cstr = json_object_iter_peek_name(&it);
393 rc = sd_bus_message_append_basic(msg, *subsig, &any);
396 rc = packsingle(msg, subsig + 1, json_object_iter_peek_value(&it));
399 rc = sd_bus_message_close_container(msg);
402 json_object_iter_next(&it);
405 rc = sd_bus_message_close_container(msg);
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,
418 rc = packlist(msg, subsig, item);
421 rc = sd_bus_message_close_container(msg);
430 rc = sd_bus_message_append_basic(msg, *signature, &any);
439 static int packlist(struct sd_bus_message *msg, const char *signature, struct json_object *list)
441 int rc, count, index, scan;
442 struct json_object *item;
452 if (!json_object_is_type(list, json_type_array)) {
453 /* down grade gracefully to single */
454 rc = packsingle(msg, signature, list);
458 if (signature[scan] != 0)
463 /* iterate over elements */
464 count = (int)json_object_array_length(list);
468 if (index == count && signature[scan] == 0)
470 if (index == count || signature[scan] == 0)
474 item = json_object_array_get_idx(list, index);
479 rc = packsingle(msg, signature + scan, item);
495 static int on_rawcall_reply(sd_bus_message *msg, afb_req_t *req, sd_bus_error *ret_error)
497 struct json_object *obj = NULL;
499 const sd_bus_error *err;
501 err = sd_bus_message_get_error(msg);
503 afb_req_fail_f(*req, "failed", "DBus-error-name: %s, DBus-error-message: %s", err->name, err->message);
505 rc = unpacklist(msg, &obj);
507 afb_req_fail(*req, "failed", "can't unpack");
509 afb_req_success(*req, obj, NULL);
511 json_object_put(obj);
518 * Make a raw call to DBUS method
519 * The query should have:
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"
530 static void rawcall(afb_req_t req)
532 struct json_object *obj;
533 struct json_object *args;
536 const char *destination;
538 const char *interface;
540 const char *signature;
542 struct sd_bus_message *msg = NULL;
547 obj = afb_req_json(req);
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)
560 signature = strval(obj, "signature") ? : "";
562 json_object_object_get_ex(obj, "arguments", &args);
565 busname = strval(obj, "bus");
566 if (busname != NULL && !strcmp(busname, "system"))
567 bus = afb_api_get_system_bus(req->api);
569 bus = afb_api_get_user_bus(req->api);
571 /* creates the message */
572 rc = sd_bus_message_new_method_call(bus, &msg, destination, path, interface, member);
575 rc = packlist(msg, signature, args);
580 rc = sd_bus_call_async(bus, NULL, msg, (void*)on_rawcall_reply, afb_req_store(req), -1);
586 afb_req_fail(req, "failed", "internal error");
590 afb_req_fail(req, "failed", "bad request");
593 sd_bus_message_unref(msg);
597 * array of the verbs exported to afb-daemon
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 */
606 * description of the binding for afb-daemon
608 const struct afb_binding_v3 afbBindingV3 =
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 */