blob: cc3e249a04087222f541a8d26b582d345f4285b0 [file] [edit]
/*
*
* Copyright (c) 2016 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Description:
* Implementation of various helper functions related to DBus
* funcitonality.
*
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "DBUSHelpers.h"
#include "Data.h"
#include <syslog.h>
#include <string>
#include <list>
#include <map>
#include <set>
#include <exception>
#include <stdexcept>
#include "ValueMap.h"
using namespace DBUSHelpers;
nl::ValueMap
DBUSHelpers::value_map_from_dbus_iter(DBusMessageIter *iter)
{
nl::ValueMap ret;
DBusMessageIter sub_iter, dict_iter;
switch (dbus_message_iter_get_arg_type(iter)) {
case DBUS_TYPE_INVALID:
// Treat no arguments in message as an empty dictionary.
goto bail;
case DBUS_TYPE_ARRAY:
break;
default:
throw std::invalid_argument("Wrong type for value map");
break;
}
dbus_message_iter_recurse(iter, &sub_iter);
if (dbus_message_iter_get_arg_type(&sub_iter) != DBUS_TYPE_DICT_ENTRY) {
throw std::invalid_argument("Wrong type for value map");
}
do {
const char* key_cstr;
dbus_message_iter_recurse(&sub_iter, &dict_iter);
if (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_STRING) {
throw std::invalid_argument("Wrong type for value map");
}
dbus_message_iter_get_basic(&dict_iter, &key_cstr);
dbus_message_iter_next(&dict_iter);
ret[key_cstr] = any_from_dbus_iter(&dict_iter);
} while (dbus_message_iter_next(&sub_iter));
bail:
return ret;
}
boost::any
DBUSHelpers::any_from_dbus_iter(DBusMessageIter *iter)
{
boost::any ret;
switch (dbus_message_iter_get_arg_type(iter)) {
case DBUS_TYPE_ARRAY: {
DBusMessageIter sub_iter;
dbus_message_iter_recurse(iter, &sub_iter);
if (dbus_message_iter_get_arg_type(&sub_iter) == DBUS_TYPE_BYTE) {
const uint8_t* value = NULL;
int nelements = 0;
dbus_message_iter_get_fixed_array(&sub_iter, &value, &nelements);
ret = nl::Data(value, nelements);
} else if (dbus_message_iter_get_arg_type(&sub_iter) == DBUS_TYPE_DICT_ENTRY) {
ret = value_map_from_dbus_iter(iter);
} else {
syslog(LOG_NOTICE,
"Unsupported DBUS array type for any: %d",
dbus_message_iter_get_arg_type(&sub_iter));
}
} break;
case DBUS_TYPE_VARIANT: {
DBusMessageIter sub_iter;
dbus_message_iter_recurse(iter, &sub_iter);
ret = any_from_dbus_iter(&sub_iter);
} break;
case DBUS_TYPE_STRING: {
const char* v;
dbus_message_iter_get_basic(iter, &v);
ret = std::string(v);
} break;
case DBUS_TYPE_BOOLEAN: {
dbus_bool_t v;
dbus_message_iter_get_basic(iter, &v);
ret = bool(v);
} break;
case DBUS_TYPE_BYTE: {
uint8_t v;
dbus_message_iter_get_basic(iter, &v);
ret = v;
} break;
case DBUS_TYPE_DOUBLE: {
double v;
dbus_message_iter_get_basic(iter, &v);
ret = v;
} break;
case DBUS_TYPE_UINT16: {
uint16_t v;
dbus_message_iter_get_basic(iter, &v);
ret = v;
} break;
case DBUS_TYPE_INT16: {
int16_t v;
dbus_message_iter_get_basic(iter, &v);
ret = v;
} break;
case DBUS_TYPE_UINT32: {
uint32_t v;
dbus_message_iter_get_basic(iter, &v);
ret = v;
} break;
case DBUS_TYPE_INT32: {
int32_t v;
dbus_message_iter_get_basic(iter, &v);
ret = v;
} break;
case DBUS_TYPE_UINT64: {
uint64_t v;
dbus_message_iter_get_basic(iter, &v);
ret = v;
} break;
case DBUS_TYPE_INT64: {
int64_t v;
dbus_message_iter_get_basic(iter, &v);
ret = v;
} break;
}
return ret;
}
void
DBUSHelpers::append_any_to_dbus_iter(
DBusMessageIter *iter, const boost::any &value
)
{
if (value.type() == typeid(std::string)) {
std::string v = boost::any_cast<std::string>(value);
const char* cstr = v.c_str();
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cstr);
} else if (value.type() == typeid(char*)) {
std::string v = boost::any_cast<char*>(value);
const char* cstr = v.c_str();
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cstr);
} else if (value.type() == typeid(bool)) {
dbus_bool_t v = boost::any_cast<bool>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &v);
} else if (value.type() == typeid(uint8_t)) {
uint8_t v = boost::any_cast<uint8_t>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &v);
} else if (value.type() == typeid(int8_t)) {
int16_t v = boost::any_cast<int8_t>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_INT16, &v);
} else if (value.type() == typeid(uint16_t)) {
uint16_t v = boost::any_cast<uint16_t>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &v);
} else if (value.type() == typeid(int16_t)) {
int16_t v = boost::any_cast<int16_t>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_INT16, &v);
} else if (value.type() == typeid(uint32_t)) {
uint32_t v = boost::any_cast<uint32_t>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &v);
} else if (value.type() == typeid(int32_t)) {
int32_t v = boost::any_cast<int32_t>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &v);
} else if (value.type() == typeid(uint64_t)) {
uint64_t v = boost::any_cast<uint64_t>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &v);
} else if (value.type() == typeid(int64_t)) {
int64_t v = boost::any_cast<int64_t>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &v);
} else if (value.type() == typeid(double)) {
double v = boost::any_cast<double>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &v);
} else if (value.type() == typeid(float)) {
double v = boost::any_cast<float>(value);
dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &v);
} else if (value.type() == typeid(std::list<std::string>)) {
DBusMessageIter array_iter;
const std::list<std::string>& list_of_strings =
boost::any_cast< std::list<std::string> >(value);
std::list<std::string>::const_iterator list_iter;
dbus_message_iter_open_container(
iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING,
&array_iter
);
for (list_iter = list_of_strings.begin();
list_iter != list_of_strings.end();
list_iter++) {
const char* cstr = list_iter->c_str();
dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
&cstr);
}
dbus_message_iter_close_container(iter, &array_iter);
} else if (value.type() == typeid(std::set<std::string>)) {
DBusMessageIter array_iter;
const std::set<std::string>& set_of_strings =
boost::any_cast< std::set<std::string> >(value);
std::set<std::string>::const_iterator set_iter;
dbus_message_iter_open_container(
iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING,
&array_iter
);
for (set_iter = set_of_strings.begin();
set_iter != set_of_strings.end();
set_iter++) {
const char* cstr = set_iter->c_str();
dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
&cstr);
}
dbus_message_iter_close_container(iter, &array_iter);
} else if (value.type() == typeid(nl::Data)) {
DBusMessageIter array_iter;
const nl::Data& vector = boost::any_cast< nl::Data >(value);
nl::Data::const_iterator vector_iter;
dbus_message_iter_open_container(
iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&array_iter
);
for (vector_iter = vector.begin();
vector_iter != vector.end();
vector_iter++) {
dbus_message_iter_append_basic(&array_iter,
DBUS_TYPE_BYTE,
&*vector_iter);
}
dbus_message_iter_close_container(iter, &array_iter);
} else if (value.type() == typeid(std::vector<uint8_t>)) {
DBusMessageIter array_iter;
const std::vector<uint8_t>& vector =
boost::any_cast< std::vector<uint8_t> >(value);
std::vector<uint8_t>::const_iterator vector_iter;
dbus_message_iter_open_container(
iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&array_iter
);
for (vector_iter = vector.begin();
vector_iter != vector.end();
vector_iter++) {
dbus_message_iter_append_basic(&array_iter,
DBUS_TYPE_BYTE,
&*vector_iter);
}
dbus_message_iter_close_container(iter, &array_iter);
} else if (value.type() == typeid(std::set<int>)) {
DBusMessageIter array_iter;
const std::set<int>& container =
boost::any_cast< std::set<int> >(value);
std::set<int>::const_iterator container_iter;
dbus_message_iter_open_container(
iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_INT32_AS_STRING,
&array_iter
);
for (container_iter = container.begin();
container_iter != container.end();
container_iter++) {
dbus_message_iter_append_basic(&array_iter,
DBUS_TYPE_INT32,
&*container_iter);
}
dbus_message_iter_close_container(iter, &array_iter);
} else if (value.type() == typeid(nl::ValueMap)) {
DBusMessageIter array_iter;
const nl::ValueMap& value_map = boost::any_cast<nl::ValueMap>(value);
nl::ValueMap::const_iterator value_map_iter;
// Open a container as "Dictionary/Array of Strings to Variants" (dbus type "a{sv}")
dbus_message_iter_open_container(
iter,
DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
&array_iter
);
for (value_map_iter = value_map.begin(); value_map_iter != value_map.end(); ++value_map_iter) {
append_dict_entry(&array_iter, value_map_iter->first.c_str(), value_map_iter->second);
}
dbus_message_iter_close_container(iter, &array_iter);
} else if (value.type() == typeid(std::list<nl::ValueMap>)) {
DBusMessageIter array_iter;
const std::list<nl::ValueMap>& value_map_list = boost::any_cast< std::list<nl::ValueMap> >(value);
std::list<nl::ValueMap>::const_iterator list_iter;
// Open a container as "Array of Dictionaries/Arrays of Strings to Variants" (dbus type "aa{sv}")
dbus_message_iter_open_container(
iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
&array_iter
);
for (list_iter = value_map_list.begin(); list_iter != value_map_list.end(); ++list_iter) {
append_any_to_dbus_iter(&array_iter, *list_iter);
}
dbus_message_iter_close_container(iter, &array_iter);
} else {
throw std::invalid_argument("Unsupported type");
}
}
std::string
DBUSHelpers::any_to_dbus_type_string(const boost::any &value)
{
if (value.type() == typeid(std::string)) {
return DBUS_TYPE_STRING_AS_STRING;
} else if (value.type() == typeid(bool)) {
return DBUS_TYPE_BOOLEAN_AS_STRING;
} else if (value.type() == typeid(uint8_t)) {
return DBUS_TYPE_BYTE_AS_STRING;
} else if (value.type() == typeid(int8_t)) {
return DBUS_TYPE_INT16_AS_STRING;
} else if (value.type() == typeid(uint16_t)) {
return DBUS_TYPE_UINT16_AS_STRING;
} else if (value.type() == typeid(int16_t)) {
return DBUS_TYPE_INT16_AS_STRING;
} else if (value.type() == typeid(uint32_t)) {
return DBUS_TYPE_UINT32_AS_STRING;
} else if (value.type() == typeid(int32_t)) {
return DBUS_TYPE_INT32_AS_STRING;
} else if (value.type() == typeid(uint64_t)) {
return DBUS_TYPE_UINT64_AS_STRING;
} else if (value.type() == typeid(int64_t)) {
return DBUS_TYPE_INT64_AS_STRING;
} else if (value.type() == typeid(double)) {
return DBUS_TYPE_DOUBLE_AS_STRING;
} else if (value.type() == typeid(float)) {
return DBUS_TYPE_DOUBLE_AS_STRING;
} else if (value.type() == typeid(nl::Data)) {
return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
} else if (value.type() == typeid(std::vector<uint8_t>)) {
return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
} else if (value.type() == typeid(std::list<std::string>)) {
return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
} else if (value.type() == typeid(std::set<std::string>)) {
return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
} else if (value.type() == typeid(nl::ValueMap)) {
return std::string(DBUS_TYPE_ARRAY_AS_STRING) +
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING +
DBUS_TYPE_STRING_AS_STRING +
DBUS_TYPE_VARIANT_AS_STRING +
DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
} else if (value.type() == typeid(std::list<nl::ValueMap>)) {
return std::string(DBUS_TYPE_ARRAY_AS_STRING) +
DBUS_TYPE_ARRAY_AS_STRING +
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING +
DBUS_TYPE_STRING_AS_STRING +
DBUS_TYPE_VARIANT_AS_STRING +
DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
}
return "";
}
void
DBUSHelpers::append_dict_entry(
DBusMessageIter *dict, const char *key, const boost::any& value
)
{
DBusMessageIter entry;
DBusMessageIter value_iter;
std::string sig = any_to_dbus_type_string(value);
dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
sig.c_str(), &value_iter);
append_any_to_dbus_iter(&value_iter, value);
dbus_message_iter_close_container(&entry, &value_iter);
dbus_message_iter_close_container(dict, &entry);
}
void
DBUSHelpers::append_dict_entry(
DBusMessageIter *dict, const char *key, char type, void *val
)
{
DBusMessageIter entry;
DBusMessageIter value_iter;
char sig[2] = { type, '\0' };
if (type == DBUS_TYPE_STRING) {
const char *str = *((const char**)val);
if (str == NULL)
return;
}
dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, sig,
&value_iter);
dbus_message_iter_append_basic(&value_iter, type, val);
dbus_message_iter_close_container(&entry, &value_iter);
dbus_message_iter_close_container(dict, &entry);
}