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 #include <afb/afb-binding.h>
29 * the interface to afb-daemon
31 const struct afb_binding_interface *afbitf;
34 * union of possible dbus values
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);
53 * Get the string of 'key' from 'obj'
54 * Returns NULL if 'key' isn't in 'obj'
56 static const char *strval(struct json_object *obj, const char *key)
58 struct json_object *keyval;
59 return json_object_object_get_ex(obj, key, &keyval) ? json_object_get_string(keyval) : NULL;
63 * Signature of a json object
65 static const char *signature_for_json(struct json_object *obj)
67 switch (json_object_get_type(obj)) {
71 case json_type_boolean:
73 case json_type_double:
77 case json_type_object:
81 case json_type_string:
87 * Length of a single complete type
89 static int lentype(const char *signature, int allows_dict, int allows_not_basic)
92 switch(signature[0]) {
94 case SD_BUS_TYPE_ARRAY:
95 if (!allows_not_basic)
97 rc = lentype(signature + 1, 1, 1);
102 case SD_BUS_TYPE_STRUCT_BEGIN:
103 if (!allows_not_basic)
106 rc = lentype(signature + len, 0, 1);
107 while (rc > 0 && signature[len] != SD_BUS_TYPE_STRUCT_END) {
109 rc = lentype(signature + len, 0, 1);
115 case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
116 if (!allows_not_basic || !allows_dict)
118 rc = lentype(signature + 1, 0, 0);
122 rc = lentype(signature + len, 0, 1);
123 if (rc < 0 || signature[len + rc] != SD_BUS_TYPE_DICT_ENTRY_END)
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:
142 * Unpack a D-Bus message to a json object
144 static int unpacksingle(struct sd_bus_message *msg, struct json_object **result)
150 struct json_object *item;
153 rc = sd_bus_message_peek_type(msg, &c, &content);
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);
174 case SD_BUS_TYPE_BOOLEAN:
175 *result = json_object_new_boolean(any.i32);
177 case SD_BUS_TYPE_BYTE:
178 *result = json_object_new_int(any.u8);
180 case SD_BUS_TYPE_INT16:
181 *result = json_object_new_int(any.i16);
183 case SD_BUS_TYPE_UINT16:
184 *result = json_object_new_int(any.u16);
186 case SD_BUS_TYPE_INT32:
187 *result = json_object_new_int(any.i32);
189 case SD_BUS_TYPE_UINT32:
190 *result = json_object_new_int64(any.u32);
192 case SD_BUS_TYPE_INT64:
193 *result = json_object_new_int64(any.i64);
195 case SD_BUS_TYPE_UINT64:
196 *result = json_object_new_int64((int64_t)any.u64);
198 case SD_BUS_TYPE_DOUBLE:
199 *result = json_object_new_string(any.cstr);
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);
207 return *result == NULL ? -1 : 1;
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);
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();
221 rc = sd_bus_message_enter_container(msg, 0, NULL);
226 rc = sd_bus_message_read_basic(msg, SD_BUS_TYPE_STRING, &any);
229 rc = unpacksingle(msg, &item);
232 json_object_object_add(*result, any.cstr, item);
233 rc = sd_bus_message_exit_container(msg);
238 rc = unpacklist(msg, result);
242 rc = sd_bus_message_exit_container(msg);
250 json_object_put(*result);
255 * Unpack a D-Bus message to a json object
257 static int unpacklist(struct sd_bus_message *msg, struct json_object **result)
260 struct json_object *item;
262 /* allocates the result */
263 *result = json_object_new_array();
267 /* read the values */
269 rc = unpacksingle(msg, &item);
274 json_object_array_add(*result, item);
277 json_object_put(*result);
282 static int packsingle(struct sd_bus_message *msg, const char *signature, struct json_object *item)
284 int index, count, rc, len;
287 struct json_object_iterator it, end;
289 len = lentype(signature, 0, 1);
293 switch (*signature) {
294 case SD_BUS_TYPE_BOOLEAN:
295 any.i32 = json_object_get_boolean(item);
298 case SD_BUS_TYPE_BYTE:
299 any.i32 = json_object_get_int(item);
300 if (any.i32 != (int32_t)(uint8_t)any.i32)
302 any.u8 = (uint8_t)any.i32;
305 case SD_BUS_TYPE_INT16:
306 any.i32 = json_object_get_int(item);
307 if (any.i32 != (int32_t)(int16_t)any.i32)
309 any.i16 = (int16_t)any.i32;
312 case SD_BUS_TYPE_UINT16:
313 any.i32 = json_object_get_int(item);
314 if (any.i32 != (int32_t)(uint16_t)any.i32)
316 any.u16 = (uint16_t)any.i32;
319 case SD_BUS_TYPE_INT32:
320 any.i64 = json_object_get_int64(item);
321 if (any.i64 != (int64_t)(int32_t)any.i64)
323 any.i32 = (int32_t)any.i64;
326 case SD_BUS_TYPE_UINT32:
327 any.i64 = json_object_get_int64(item);
328 if (any.i64 != (int64_t)(uint32_t)any.i64)
330 any.u32 = (uint32_t)any.i64;
333 case SD_BUS_TYPE_INT64:
334 any.i64 = json_object_get_int64(item);
337 case SD_BUS_TYPE_UINT64:
338 any.u64 = (uint64_t)json_object_get_int64(item);
341 case SD_BUS_TYPE_DOUBLE:
342 any.dbl = json_object_get_double(item);
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);
351 case SD_BUS_TYPE_VARIANT:
352 signature = signature_for_json(item);
353 if (signature == NULL)
355 rc = sd_bus_message_open_container(msg, SD_BUS_TYPE_VARIANT, signature);
358 rc = packsingle(msg, signature, item);
361 rc = sd_bus_message_close_container(msg);
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);
371 if (json_object_is_type(item, json_type_array)) {
373 count = json_object_array_length(item);
375 while(index < count) {
376 rc = packsingle(msg, subsig, json_object_array_get_idx(item, index++));
381 /* Not an array! Check if it matches an string dictionnary */
382 if (!json_object_is_type(item, json_type_object))
384 if (*subsig++ != SD_BUS_TYPE_DICT_ENTRY_BEGIN)
386 if (*subsig != SD_BUS_TYPE_STRING)
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);
396 any.cstr = json_object_iter_peek_name(&it);
397 rc = sd_bus_message_append_basic(msg, *subsig, &any);
400 rc = packsingle(msg, subsig + 1, json_object_iter_peek_value(&it));
403 rc = sd_bus_message_close_container(msg);
406 json_object_iter_next(&it);
409 rc = sd_bus_message_close_container(msg);
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,
422 rc = packlist(msg, subsig, item);
425 rc = sd_bus_message_close_container(msg);
434 rc = sd_bus_message_append_basic(msg, *signature, &any);
443 static int packlist(struct sd_bus_message *msg, const char *signature, struct json_object *list)
445 int rc, count, index, scan;
446 struct json_object *item;
456 if (!json_object_is_type(list, json_type_array)) {
457 /* down grade gracefully to single */
458 rc = packsingle(msg, signature, list);
462 if (signature[scan] != 0)
467 /* iterate over elements */
468 count = json_object_array_length(list);
472 if (index == count && signature[scan] == 0)
474 if (index == count || signature[scan] == 0)
478 item = json_object_array_get_idx(list, index);
483 rc = packsingle(msg, signature + scan, item);
499 static int on_rawcall_reply(sd_bus_message *msg, struct afb_req *req, sd_bus_error *ret_error)
501 struct json_object *obj = NULL;
503 const sd_bus_error *err;
505 err = sd_bus_message_get_error(msg);
507 afb_req_fail_f(*req, "failed", "DBus-error-name: %s, DBus-error-message: %s", err->name, err->message);
509 rc = unpacklist(msg, &obj);
511 afb_req_fail(*req, "failed", "can't unpack");
513 afb_req_success(*req, obj, NULL);
515 json_object_put(obj);
522 * Make a raw call to DBUS method
523 * The query should have:
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"
534 static void rawcall(struct afb_req req)
536 struct json_object *obj;
537 struct json_object *args;
540 const char *destination;
542 const char *interface;
544 const char *signature;
546 struct sd_bus_message *msg = NULL;
551 obj = afb_req_json(req);
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)
564 signature = strval(obj, "signature") ? : "";
566 json_object_object_get_ex(obj, "arguments", &args);
569 busname = strval(obj, "bus");
570 if (busname != NULL && !strcmp(busname, "system"))
571 bus = afb_daemon_get_system_bus(afbitf->daemon);
573 bus = afb_daemon_get_user_bus(afbitf->daemon);
575 /* creates the message */
576 rc = sd_bus_message_new_method_call(bus, &msg, destination, path, interface, member);
579 rc = packlist(msg, signature, args);
584 rc = sd_bus_call_async(bus, NULL, msg, (void*)on_rawcall_reply, afb_req_store(req), -1);
590 afb_req_fail(req, "failed", "internal error");
594 afb_req_fail(req, "failed", "bad request");
597 sd_bus_message_unref(msg);
601 * array of the verbs exported to afb-daemon
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 */
610 * description of the binding for afb-daemon
612 static const struct afb_binding binding_description =
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 */
624 * activation function for registering the binding called by afb-daemon
626 const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf)
628 afbitf = itf; /* records the interface for accessing afb-daemon */
629 return &binding_description; /* returns the description of the binding */