2 * Copyright (C) 2016 "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 #include <afb/afb-plugin.h>
27 #include <afb/afb-plugin.h>
28 #include <afb/afb-plugin.h>
31 * the interface to afb-daemon
33 const struct AFB_interface *afbitf;
36 * union of possible dbus values
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);
55 * Get the string of 'key' from 'obj'
56 * Returns NULL if 'key' isn't in 'obj'
58 static const char *strval(struct json_object *obj, const char *key)
60 struct json_object *keyval;
61 return json_object_object_get_ex(obj, key, &keyval) ? json_object_get_string(keyval) : NULL;
65 * Signature of a json object
67 static const char *signature_for_json(struct json_object *obj)
69 switch (json_object_get_type(obj)) {
73 case json_type_boolean:
75 case json_type_double:
79 case json_type_object:
83 case json_type_string:
89 * Length of a single complete type
91 static int lentype(const char *signature, int allows_dict, int allows_not_basic)
94 switch(signature[0]) {
96 case SD_BUS_TYPE_ARRAY:
97 if (!allows_not_basic)
99 rc = lentype(signature + 1, 1, 1);
104 case SD_BUS_TYPE_STRUCT_BEGIN:
105 if (!allows_not_basic)
108 rc = lentype(signature + len, 0, 1);
109 while (rc > 0 && signature[len] != SD_BUS_TYPE_STRUCT_END) {
111 rc = lentype(signature + len, 0, 1);
117 case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
118 if (!allows_not_basic || !allows_dict)
120 rc = lentype(signature + 1, 0, 0);
124 rc = lentype(signature + len, 0, 1);
125 if (rc < 0 || signature[len + rc] != SD_BUS_TYPE_DICT_ENTRY_END)
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:
144 * Unpack a D-Bus message to a json object
146 static int unpacksingle(struct sd_bus_message *msg, struct json_object **result)
152 struct json_object *item;
155 rc = sd_bus_message_peek_type(msg, &c, &content);
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);
176 case SD_BUS_TYPE_BOOLEAN:
177 *result = json_object_new_boolean(any.i32);
179 case SD_BUS_TYPE_BYTE:
180 *result = json_object_new_int(any.u8);
182 case SD_BUS_TYPE_INT16:
183 *result = json_object_new_int(any.i16);
185 case SD_BUS_TYPE_UINT16:
186 *result = json_object_new_int(any.u16);
188 case SD_BUS_TYPE_INT32:
189 *result = json_object_new_int(any.i32);
191 case SD_BUS_TYPE_UINT32:
192 *result = json_object_new_int64(any.u32);
194 case SD_BUS_TYPE_INT64:
195 *result = json_object_new_int64(any.i64);
197 case SD_BUS_TYPE_UINT64:
198 *result = json_object_new_int64((int64_t)any.u64);
200 case SD_BUS_TYPE_DOUBLE:
201 *result = json_object_new_string(any.cstr);
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);
209 return *result == NULL ? -1 : 1;
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);
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();
223 rc = sd_bus_message_enter_container(msg, 0, NULL);
228 rc = sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, &any);
231 rc = unpacksingle(msg, &item);
234 json_object_object_add(*result, any.cstr, item);
235 rc = sd_bus_message_exit_container(msg);
240 rc = unpacklist(msg, result);
244 rc = sd_bus_message_exit_container(msg);
252 json_object_put(*result);
257 * Unpack a D-Bus message to a json object
259 static int unpacklist(struct sd_bus_message *msg, struct json_object **result)
262 struct json_object *item;
264 /* allocates the result */
265 *result = json_object_new_array();
269 /* read the values */
271 rc = unpacksingle(msg, &item);
276 json_object_array_add(*result, item);
279 json_object_put(*result);
284 static int packsingle(struct sd_bus_message *msg, const char *signature, struct json_object *item)
286 int index, count, rc, len;
289 struct json_object_iterator it, end;
291 len = lentype(signature, 0, 1);
295 switch (*signature) {
296 case SD_BUS_TYPE_BOOLEAN:
297 any.i32 = json_object_get_boolean(item);
300 case SD_BUS_TYPE_BYTE:
301 any.i32 = json_object_get_int(item);
302 if (any.i32 != (int32_t)(uint8_t)any.i32)
304 any.u8 = (uint8_t)any.i32;
307 case SD_BUS_TYPE_INT16:
308 any.i32 = json_object_get_int(item);
309 if (any.i32 != (int32_t)(int16_t)any.i32)
311 any.i16 = (int16_t)any.i32;
314 case SD_BUS_TYPE_UINT16:
315 any.i32 = json_object_get_int(item);
316 if (any.i32 != (int32_t)(uint16_t)any.i32)
318 any.u16 = (uint16_t)any.i32;
321 case SD_BUS_TYPE_INT32:
322 any.i64 = json_object_get_int64(item);
323 if (any.i64 != (int64_t)(int32_t)any.i64)
325 any.i32 = (int32_t)any.i64;
328 case SD_BUS_TYPE_UINT32:
329 any.i64 = json_object_get_int64(item);
330 if (any.i64 != (int64_t)(uint32_t)any.i64)
332 any.u32 = (uint32_t)any.i64;
335 case SD_BUS_TYPE_INT64:
336 any.i64 = json_object_get_int64(item);
339 case SD_BUS_TYPE_UINT64:
340 any.u64 = (uint64_t)json_object_get_int64(item);
343 case SD_BUS_TYPE_DOUBLE:
344 any.dbl = json_object_get_double(item);
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);
353 case SD_BUS_TYPE_VARIANT:
354 signature = signature_for_json(item);
355 if (signature == NULL)
357 rc = sd_bus_message_open_container(msg, SD_BUS_TYPE_VARIANT, signature);
360 rc = packsingle(msg, signature, item);
363 rc = sd_bus_message_close_container(msg);
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);
373 if (json_object_is_type(item, json_type_array)) {
375 count = json_object_array_length(item);
377 while(index < count) {
378 rc = packsingle(msg, subsig, json_object_array_get_idx(item, index++));
383 /* Not an array! Check if it matches an string dictionnary */
384 if (!json_object_is_type(item, json_type_object))
386 if (*subsig++ != SD_BUS_TYPE_DICT_ENTRY_BEGIN)
388 if (*subsig != SD_BUS_TYPE_STRING)
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);
398 any.cstr = json_object_iter_peek_name(&it);
399 rc = sd_bus_message_append_basic(msg, *subsig, &any);
402 rc = packsingle(msg, subsig + 1, json_object_iter_peek_value(&it));
405 rc = sd_bus_message_close_container(msg);
408 json_object_iter_next(&it);
411 rc = sd_bus_message_close_container(msg);
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,
424 rc = packlist(msg, subsig, item);
427 rc = sd_bus_message_close_container(msg);
436 rc = sd_bus_message_append_basic(msg, *signature, &any);
445 static int packlist(struct sd_bus_message *msg, const char *signature, struct json_object *list)
447 int rc, count, index, scan;
448 struct json_object *item;
458 if (!json_object_is_type(list, json_type_array)) {
459 /* down grade gracefully to single */
460 rc = packsingle(msg, signature, list);
464 if (signature[scan] != 0)
469 /* iterate over elements */
470 count = json_object_array_length(list);
474 if (index == count && signature[scan] == 0)
476 if (index == count || signature[scan] == 0)
480 item = json_object_array_get_idx(list, index);
485 rc = packsingle(msg, signature + scan, item);
501 static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_error *ret_error)
503 struct json_object *obj = NULL;
505 const sd_bus_error *err;
507 err = sd_bus_message_get_error(msg);
509 afb_req_fail_f(*req, "failed", "DBus-error-name: %s, DBus-error-message: %s", err->name, err->message);
511 rc = unpacklist(msg, &obj);
513 afb_req_fail(*req, "failed", "can't unpack");
515 afb_req_success(*req, obj, NULL);
517 json_object_put(obj);
524 * Make a raw call to DBUS method
525 * The query should have:
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"
536 static void rawcall(struct afb_req req)
538 struct json_object *obj;
539 struct json_object *args;
542 const char *destination;
544 const char *interface;
546 const char *signature;
548 struct sd_bus_message *msg = NULL;
553 obj = afb_req_json(req);
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)
566 signature = strval(obj, "signature") ? : "";
568 json_object_object_get_ex(obj, "arguments", &args);
571 busname = strval(obj, "bus");
572 if (busname != NULL && !strcmp(busname, "system"))
573 bus = afb_daemon_get_system_bus(afbitf->daemon);
575 bus = afb_daemon_get_user_bus(afbitf->daemon);
577 /* creates the message */
578 rc = sd_bus_message_new_method_call(bus, &msg, destination, path, interface, member);
581 rc = packlist(msg, signature, args);
586 rc = sd_bus_call_async(bus, NULL, msg, (void*)on_rawcall_reply, afb_req_store(req), -1);
592 afb_req_fail(req, "failed", "internal error");
596 afb_req_fail(req, "failed", "bad request");
599 sd_bus_message_unref(msg);
603 * array of the verbs exported to afb-daemon
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 */
612 * description of the plugin for afb-daemon
614 static const struct AFB_plugin plugin_description =
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 */
626 * activation function for registering the plugin called by afb-daemon
628 const struct AFB_plugin *pluginAfbV1Register(const struct AFB_interface *itf)
630 afbitf = itf; /* records the interface for accessing afb-daemon */
631 return &plugin_description; /* returns the description of the plugin */