summaryrefslogtreecommitdiff
path: root/src/components/dbus/src/dbus_adapter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/dbus/src/dbus_adapter.cc')
-rw-r--r--src/components/dbus/src/dbus_adapter.cc918
1 files changed, 918 insertions, 0 deletions
diff --git a/src/components/dbus/src/dbus_adapter.cc b/src/components/dbus/src/dbus_adapter.cc
new file mode 100644
index 0000000000..5f38e3d80f
--- /dev/null
+++ b/src/components/dbus/src/dbus_adapter.cc
@@ -0,0 +1,918 @@
+/*
+ * Copyright (c) 2013-2014, Ford Motor Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Ford Motor Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dbus/dbus_adapter.h"
+#include <dbus/dbus.h>
+#include <sstream>
+#include "formatters/CSmartFactory.hpp"
+#include "utils/logger.h"
+
+using ford_message_descriptions::ParameterDescription;
+namespace sos = NsSmartDeviceLink::NsJSONHandler::strings;
+namespace smart_objects = NsSmartDeviceLink::NsSmartObjects;
+
+extern char introspection_xml[];
+
+namespace dbus {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "HMIMessageHandler")
+
+std::vector<std::string> &split(const std::string& s, char delim,
+ std::vector<std::string> &elems) {
+ std::stringstream ss(s);
+ std::string item;
+ while (std::getline(ss, item, delim)) {
+ elems.push_back(item);
+ }
+ return elems;
+}
+
+DBusAdapter::DBusAdapter(const std::string& sdlServiceName,
+ const std::string& sdlObjectPath,
+ const std::string& hmiServiceName,
+ const std::string& hmiObjectPath)
+ : sdl_service_name_(sdlServiceName),
+ sdl_object_path_(sdlObjectPath),
+ hmi_service_name_(hmiServiceName),
+ hmi_object_path_(hmiObjectPath),
+ conn_(NULL),
+ schema_(new DBusSchema(ford_message_descriptions::message_descriptions)) {
+}
+
+DBusAdapter::~DBusAdapter() {
+ dbus_shutdown();
+ delete schema_;
+}
+
+bool DBusAdapter::Init() {
+ DBusError err;
+ int ret;
+ dbus_error_init(&err);
+ if (!dbus_threads_init_default()) {
+ LOG4CXX_ERROR(logger_, "DBus: Can't initializes threads");
+ return false;
+ }
+ conn_ = dbus_bus_get(DBUS_BUS_SESSION, &err);
+ if (dbus_error_is_set(&err)) {
+ LOG4CXX_ERROR(logger_, "DBus: Connection Error " << err.message);
+ dbus_error_free(&err);
+ return false;
+ }
+ ret = dbus_bus_request_name(conn_, sdl_service_name_.c_str(),
+ DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ &err);
+ if (ret == -1 || dbus_error_is_set(&err)) {
+ LOG4CXX_ERROR(logger_, "DBus: Can't request name " << err.name);
+ dbus_error_free(&err);
+ return false;
+ }
+ if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
+ LOG4CXX_ERROR(
+ logger_,
+ "DBus: Service '" << sdl_service_name_ << "' is already running");
+ return false;
+ }
+
+ LOG4CXX_INFO(logger_, "DBus: Success init dbus adaptor");
+ return true;
+}
+
+bool DBusAdapter::Process(smart_objects::SmartObject& obj) {
+ if (conn_ == NULL) {
+ LOG4CXX_ERROR(logger_, "DBus: DBusAdaptor isn't initialized");
+ return false;
+ }
+ DBusMessage* msg = dbus_connection_pop_message(conn_);
+ if (msg != NULL) {
+ switch (dbus_message_get_type(msg)) {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ return ProcessMethodCall(msg, obj);
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ return ProcessMethodReturn(msg, obj);
+ case DBUS_MESSAGE_TYPE_ERROR:
+ return ProcessError(msg, obj);
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ return ProcessSignal(msg, obj);
+ default:
+ return false;
+ }
+ } else {
+ dbus_connection_read_write(conn_, 50);
+ }
+ return false;
+}
+
+void DBusAdapter::MethodReturn(uint id, const MessageId func_id,
+ const MessageName& name,
+ const smart_objects::SmartObject& obj) {
+ LOG4CXX_DEBUG(logger_, "Method return " << name.first << "." << name.second);
+ if (conn_ == NULL) {
+ LOG4CXX_ERROR(logger_, "DBus: DBusAdaptor isn't init");
+ return;
+ }
+
+ if (func_id == hmi_apis::FunctionID::INVALID_ENUM) {
+ LOG4CXX_ERROR(logger_, "DBus: Invalid name method");
+ return;
+ }
+
+ DBusMessage* msg = GetRequestFromHMI(id);
+ if (!msg) {
+ LOG4CXX_WARN(logger_, "DBus: request from HMI is not found");
+ return;
+ }
+
+ DBusMessage* reply;
+ reply = dbus_message_new_method_return(msg);
+ if (NULL == reply) {
+ LOG4CXX_WARN(logger_, "DBus: Failed call method (Message Null)");
+ return;
+ }
+
+ const ListArgs& args = schema_->getListArgs(func_id,
+ hmi_apis::messageType::response);
+ if (!SetArguments(reply, args, obj)) {
+ LOG4CXX_ERROR(logger_, "DBus: Failed call method (Signature is wrong)");
+ dbus_message_unref(reply);
+ dbus_message_unref(msg);
+ return;
+ }
+
+ dbus_uint32_t serial;
+ if (!dbus_connection_send(conn_, reply, &serial)) {
+ LOG4CXX_ERROR(logger_, "DBus: Failed call method (Can't send message)");
+ dbus_message_unref(reply);
+ dbus_message_unref(msg);
+ return;
+ }
+ dbus_connection_flush(conn_);
+ dbus_message_unref(reply);
+ dbus_message_unref(msg);
+ LOG4CXX_INFO(logger_, "DBus: Success return method");
+}
+
+void DBusAdapter::Error(uint id, const std::string& name,
+ const std::string& description) {
+ LOG4CXX_DEBUG(logger_, "Error " << name << ": " << description);
+ if (conn_ == NULL) {
+ LOG4CXX_ERROR(logger_, "DBus: DBusAdaptor isn't init");
+ return;
+ }
+
+ DBusMessage* msg = GetRequestFromHMI(id);
+ if (!msg) {
+ LOG4CXX_WARN(logger_, "DBus: request from HMI is not found");
+ return;
+ }
+
+ DBusMessage* error;
+ error = dbus_message_new_error(msg, name.c_str(), description.c_str());
+ if (NULL == error) {
+ LOG4CXX_WARN(logger_, "DBus: Failed call method (Message Null)");
+ return;
+ }
+
+ dbus_uint32_t serial;
+ if (!dbus_connection_send(conn_, error, &serial)) {
+ LOG4CXX_ERROR(logger_, "DBus: Failed call method (Can't send message)");
+ dbus_message_unref(error);
+ dbus_message_unref(msg);
+ return;
+ }
+ dbus_connection_flush(conn_);
+ dbus_message_unref(error);
+ dbus_message_unref(msg);
+ LOG4CXX_INFO(logger_, "DBus: Success error");
+}
+
+void DBusAdapter::MethodCall(uint id, const MessageId func_id,
+ const MessageName& name,
+ const smart_objects::SmartObject& obj) {
+ LOG4CXX_DEBUG(logger_, "Method call " << name.first << "." << name.second);
+ if (conn_ == NULL) {
+ LOG4CXX_ERROR(logger_, "DBus: DBusAdaptor isn't init");
+ return;
+ }
+
+ if (func_id == hmi_apis::FunctionID::INVALID_ENUM) {
+ LOG4CXX_ERROR(logger_, "DBus: Invalid name method");
+ return;
+ }
+
+ DBusMessage* msg;
+ msg = dbus_message_new_method_call(
+ hmi_service_name_.c_str(), hmi_object_path_.c_str(),
+ (hmi_service_name_ + "." + name.first).c_str(), name.second.c_str());
+ if (NULL == msg) {
+ LOG4CXX_WARN(logger_, "DBus: Failed call method (Message Null)");
+ return;
+ }
+
+ const ListArgs& args = schema_->getListArgs(func_id,
+ hmi_apis::messageType::request);
+ if (!SetArguments(msg, args, obj)) {
+ LOG4CXX_ERROR(logger_, "DBus: Failed call method (Signature is wrong)");
+ dbus_message_unref(msg);
+ return;
+ }
+
+ dbus_uint32_t serial;
+ if (!dbus_connection_send(conn_, msg, &serial)) {
+ LOG4CXX_ERROR(logger_, "DBus: Failed call method (Can't send message)");
+ dbus_message_unref(msg);
+ return;
+ }
+ SaveRequestToHMI(serial, std::make_pair(id, func_id));
+ dbus_message_unref(msg);
+ LOG4CXX_INFO(logger_, "DBus: Success call method");
+}
+
+void DBusAdapter::Signal(const MessageId func_id, const MessageName& name,
+ const smart_objects::SmartObject& obj) {
+ LOG4CXX_DEBUG(logger_, "Signal " << name.first << "." << name.second);
+ if (conn_ == NULL) {
+ LOG4CXX_ERROR(logger_, "DBus: DBusAdaptor isn't init");
+ return;
+ }
+
+ if (func_id == hmi_apis::FunctionID::INVALID_ENUM) {
+ LOG4CXX_ERROR(logger_, "DBus: Invalid name method");
+ return;
+ }
+
+ DBusMessage *msg;
+ msg = dbus_message_new_signal(sdl_object_path_.c_str(),
+ (sdl_service_name_ + "." + name.first).c_str(),
+ name.second.c_str());
+ if (NULL == msg) {
+ LOG4CXX_WARN(logger_, "DBus: Failed emit signal (Message Null)");
+ return;
+ }
+
+ const ListArgs& args = schema_->getListArgs(
+ func_id, hmi_apis::messageType::notification);
+ if (!SetArguments(msg, args, obj)) {
+ LOG4CXX_ERROR(logger_, "DBus: Failed call method (Signature is wrong)");
+ dbus_message_unref(msg);
+ return;
+ }
+
+ if (!dbus_connection_send(conn_, msg, NULL)) { // serial isn't required
+ LOG4CXX_WARN(logger_, "DBus: Failed emit signal (Out Of Memory)");
+ dbus_message_unref(msg);
+ return;
+ }
+ dbus_message_unref(msg);
+ LOG4CXX_INFO(logger_, "DBus: Success emit signal");
+}
+
+void DBusAdapter::AddMatch(const std::string& rule) {
+ LOG4CXX_INFO(logger_, "Subscription: " << rule);
+ dbus_bus_add_match(conn_, rule.c_str(), NULL);
+}
+
+bool DBusAdapter::ProcessMethodCall(DBusMessage* msg,
+ smart_objects::SmartObject& obj) {
+ std::string method = dbus_message_get_member(msg);
+ std::string interface = dbus_message_get_interface(msg);
+ LOG4CXX_INFO(logger_, "DBus: name of method " << interface << " " << method);
+
+ if (interface == "org.freedesktop.DBus.Introspectable"
+ && method == "Introspect") {
+ LOG4CXX_INFO(logger_, "DBus: INTROSPECT");
+ Introspect(msg);
+ return false;
+ }
+
+ std::vector<std::string> elems;
+ split(interface, '.', elems);
+ MessageName name(elems.back(), method);
+ MessageId m_id = schema_->getMessageId(name);
+ if (m_id == hmi_apis::FunctionID::INVALID_ENUM) {
+ LOG4CXX_ERROR(logger_, "DBus: Invalid name method call from hmi");
+ return false;
+ }
+
+ uint32_t serial = dbus_message_get_serial(msg);
+ if (!serial) {
+ LOG4CXX_ERROR(logger_, "DBus: Serial of request from HMI isn't defined");
+ return false;
+ }
+
+ obj[sos::S_PARAMS][sos::S_CORRELATION_ID] = serial;
+ obj[sos::S_PARAMS][sos::S_FUNCTION_ID] = m_id;
+ obj[sos::S_PARAMS][sos::S_MESSAGE_TYPE] = hmi_apis::messageType::request;
+ obj[sos::S_MSG_PARAMS] = smart_objects::SmartObject(
+ smart_objects::SmartType_Map);
+
+ const ListArgs args = schema_->getListArgs(name,
+ hmi_apis::messageType::request);
+
+ DBusMessageIter iter;
+ dbus_message_iter_init(msg, &iter);
+ if (GetArguments(&iter, args, obj[sos::S_MSG_PARAMS])) {
+ SaveRequestFromHMI(serial, msg);
+ return true;
+ }
+ return false;
+}
+
+bool DBusAdapter::ProcessMethodReturn(DBusMessage* msg,
+ smart_objects::SmartObject& obj) {
+ LOG4CXX_INFO(logger_, "ProcessMethodReturn");
+ dbus_uint32_t reply_serial = dbus_message_get_reply_serial(msg);
+ std::pair<uint, MessageId> ids = GetRequestToHMI(reply_serial);
+ if (ids.second == hmi_apis::FunctionID::INVALID_ENUM) {
+ LOG4CXX_ERROR(logger_, "DBus: Invalid name method");
+ return false;
+ }
+
+ obj[sos::S_MSG_PARAMS] = smart_objects::SmartObject(
+ smart_objects::SmartType_Map);
+
+ ListArgs args = schema_->getListArgs(ids.second,
+ hmi_apis::messageType::response);
+ DBusMessageIter iter;
+ dbus_message_iter_init(msg, &iter);
+ int code = 0;
+ std::string message;
+ smart_objects::SmartObject description(smart_objects::SmartType_Map);
+ bool ret = GetHeader(&iter, &code, &message)
+ && GetArguments(&iter, args, description);
+
+ if (ret) {
+ obj[sos::S_PARAMS][sos::S_CORRELATION_ID] = ids.first;
+ obj[sos::S_PARAMS][sos::S_FUNCTION_ID] = ids.second;
+ obj[sos::S_PARAMS][sos::S_MESSAGE_TYPE] = hmi_apis::messageType::response;
+ obj[sos::S_PARAMS][sos::kCode] = code;
+ obj[sos::S_PARAMS][sos::kMessage] = message;
+ if (code != hmi_apis::Common_Result::SUCCESS) {
+ MessageName name = schema_->getMessageName(ids.second);
+ description["method"] = name.first + "." + name.second;
+ obj[sos::S_PARAMS]["data"] = description;
+ } else {
+ obj[sos::S_MSG_PARAMS] = description;
+ }
+ }
+
+ dbus_message_unref(msg);
+ return ret;
+}
+
+bool DBusAdapter::ProcessError(DBusMessage* msg,
+ smart_objects::SmartObject& obj) {
+ dbus_uint32_t reply_serial = dbus_message_get_reply_serial(msg);
+ std::pair<uint, MessageId> ids = GetRequestToHMI(reply_serial);
+ if (ids.second == hmi_apis::FunctionID::INVALID_ENUM) {
+ LOG4CXX_ERROR(logger_, "DBus: Invalid name method");
+ return false;
+ }
+
+ const char* error_name;
+ bool ret = false;
+ if ((error_name = dbus_message_get_error_name(msg)) != NULL) {
+ smart_objects::SmartObject name(smart_objects::SmartType_String);
+ name = error_name;
+ ford_message_descriptions::ParameterDescription rule = { "description",
+ ford_message_descriptions::String, true };
+ ListArgs args;
+ args.push_back(&rule);
+ smart_objects::SmartObject description(smart_objects::SmartType_Map);
+ description[rule.name] = smart_objects::SmartObject(
+ smart_objects::SmartType_String);
+
+ DBusMessageIter iter;
+ dbus_message_iter_init(msg, &iter);
+ ret = GetArguments(&iter, args, description);
+ MessageName method = schema_->getMessageName(ids.second);
+
+ obj[sos::S_PARAMS][sos::S_CORRELATION_ID] = ids.first;
+ obj[sos::S_PARAMS][sos::S_FUNCTION_ID] = ids.second;
+ obj[sos::S_PARAMS][sos::S_MESSAGE_TYPE] =
+ hmi_apis::messageType::error_response;
+ obj[sos::S_PARAMS][sos::kCode] = name.asInt();
+ obj[sos::S_PARAMS][sos::kMessage] = description[rule.name].asString();
+ obj[sos::S_MSG_PARAMS] = smart_objects::SmartObject(
+ smart_objects::SmartType_Map);
+ obj[sos::S_PARAMS]["data"]["method"] = method.first + "." + method.second;
+
+ LOG4CXX_WARN(
+ logger_,
+ "DBus: Call of method " << method.first << "." << method.second << " returned error " << name.asInt() << ": " << description[rule.name].asString());
+ } else {
+ LOG4CXX_ERROR(logger_, "DBus: Type message isn't error");
+ }
+
+ dbus_message_unref(msg);
+ return ret;
+}
+
+bool DBusAdapter::ProcessSignal(DBusMessage* msg,
+ smart_objects::SmartObject& obj) {
+ std::string method = dbus_message_get_member(msg);
+ std::string interface = dbus_message_get_interface(msg);
+ LOG4CXX_INFO(logger_, "DBus: name of signal " << method);
+
+ std::vector<std::string> elems;
+ split(interface, '.', elems);
+ MessageName name(elems.back(), method);
+ MessageId m_id = schema_->getMessageId(name);
+ if (m_id == hmi_apis::FunctionID::INVALID_ENUM) {
+ LOG4CXX_ERROR(logger_, "DBus: Invalid name signal");
+ return false;
+ }
+
+ obj[sos::S_PARAMS][sos::S_FUNCTION_ID] = m_id;
+ obj[sos::S_PARAMS][sos::S_MESSAGE_TYPE] = hmi_apis::messageType::notification;
+ obj[sos::S_MSG_PARAMS] = smart_objects::SmartObject(
+ smart_objects::SmartType_Map);
+
+ const ListArgs args = schema_->getListArgs(
+ name, hmi_apis::messageType::notification);
+
+ DBusMessageIter iter;
+ dbus_message_iter_init(msg, &iter);
+ bool ret = GetArguments(&iter, args, obj[sos::S_MSG_PARAMS]);
+ dbus_message_unref(msg);
+ return ret;
+}
+
+bool DBusAdapter::SetArguments(DBusMessage* msg, const ListArgs& rules,
+ const smart_objects::SmartObject& args) {
+ DBusMessageIter iter;
+ dbus_message_iter_init_append(msg, &iter);
+ size_t size = rules.size();
+ for (size_t i = 0; i < size; ++i) {
+ const smart_objects::SmartObject& param = args.getElement(rules[i]->name);
+ if (!SetOneArgument(&iter, rules[i], param)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool DBusAdapter::SetOneArgument(DBusMessageIter* iter,
+ const ParameterDescription* rules,
+ const smart_objects::SmartObject& param) {
+ if (rules->obligatory) {
+ if (param.isValid()) {
+ return SetValue(iter, rules, param);
+ } else {
+ LOG4CXX_WARN(logger_,
+ "DBus: Argument '" << rules->name << "' is obligatory!");
+ return false;
+ }
+ } else {
+ return SetOptionalValue(iter, rules, param);
+ }
+}
+
+bool DBusAdapter::SetValue(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::ParameterDescription* rules,
+ const smart_objects::SmartObject& param) {
+ // LOG4CXX_DEBUG(logger_, "DBus: Set param " << rules->name << " = " << param.asString());
+ int type = 0;
+ void* value = 0;
+ dbus_int32_t integerValue = 0;
+ double floatValue = 0;
+ dbus_bool_t booleanValue = false;
+ const char* stringValue;
+ switch (rules->type) {
+ case ford_message_descriptions::ParameterType::Array:
+ return SetArrayValue(
+ iter,
+ reinterpret_cast<const ford_message_descriptions::ArrayDescription*>(rules),
+ param);
+ break;
+ case ford_message_descriptions::ParameterType::Struct:
+ return SetStructValue(
+ iter,
+ reinterpret_cast<const ford_message_descriptions::StructDescription*>(rules),
+ param);
+ break;
+ case ford_message_descriptions::ParameterType::Enum:
+ case ford_message_descriptions::ParameterType::Integer:
+ type = DBUS_TYPE_INT32;
+ integerValue = param.asInt();
+ value = &integerValue;
+ break;
+ case ford_message_descriptions::ParameterType::Float:
+ type = DBUS_TYPE_DOUBLE;
+ floatValue = param.asDouble();
+ value = &floatValue;
+ break;
+ case ford_message_descriptions::ParameterType::Boolean:
+ type = DBUS_TYPE_BOOLEAN;
+ booleanValue = param.asBool();
+ value = &booleanValue;
+ break;
+ case ford_message_descriptions::ParameterType::String:
+ type = DBUS_TYPE_STRING;
+ stringValue = param.asString().c_str();
+ value = &stringValue;
+ break;
+ default:
+ LOG4CXX_ERROR(logger_, "DBus: Unknown type of argument")
+ ;
+ return false;
+ }
+ return dbus_message_iter_append_basic(iter, type, value);
+}
+
+bool DBusAdapter::SetOptionalValue(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::ParameterDescription* rules,
+ const smart_objects::SmartObject &param) {
+ DBusMessageIter sub_iter;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL,
+ &sub_iter)) {
+ LOG4CXX_ERROR(
+ logger_,
+ "DBus: Can't open container type (STRUCT) for optional parameter");
+ return false;
+ }
+
+ ford_message_descriptions::ParameterDescription flagRules = { "flag",
+ ford_message_descriptions::Boolean, true };
+ smart_objects::SmartObject flag(
+ param.getType() != smart_objects::SmartType_Invalid);
+ if (!SetValue(&sub_iter, &flagRules, flag)
+ || !SetValue(&sub_iter, rules, param)) {
+ return false;
+ }
+
+ if (!dbus_message_iter_close_container(iter, &sub_iter)) {
+ LOG4CXX_ERROR(
+ logger_,
+ "DBus: Can't close container type (STRUCT) for optional parameter");
+ return false;
+ }
+ return true;
+}
+
+bool DBusAdapter::SetArrayValue(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::ArrayDescription* rules,
+ const smart_objects::SmartObject& param) {
+ smart_objects::SmartType type = param.getType();
+ if (type != smart_objects::SmartType_Array
+ && type != smart_objects::SmartType_Invalid) {
+ LOG4CXX_ERROR(logger_, "DBus: SmartObject is not a map");
+ return false;
+ }
+ DBusMessageIter sub_iter;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ rules->element_dbus_signature,
+ &sub_iter)) {
+ LOG4CXX_ERROR(logger_, "DBus: Can't open container type (ARRAY)");
+ return false;
+ }
+ size_t size = param.length();
+ for (size_t i = 0; i < size; ++i) {
+ if (!SetValue(&sub_iter, rules->element, param[i])) {
+ return false;
+ }
+ }
+ if (!dbus_message_iter_close_container(iter, &sub_iter)) {
+ LOG4CXX_ERROR(logger_, "DBus: Can't close container type (ARRAY)");
+ return false;
+ }
+ return true;
+}
+
+bool DBusAdapter::SetStructValue(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::StructDescription* rules,
+ const smart_objects::SmartObject& structure) {
+ smart_objects::SmartType type = structure.getType();
+ if (type != smart_objects::SmartType_Map
+ && type != smart_objects::SmartType_Invalid) {
+ LOG4CXX_ERROR(logger_, "DBus: SmartObject is not a map");
+ return false;
+ }
+ DBusMessageIter sub_iter;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL,
+ &sub_iter)) {
+ LOG4CXX_ERROR(logger_, "DBus: Can't open container type (STRUCT)");
+ return false;
+ }
+ const ParameterDescription** entry;
+ entry = rules->parameters;
+ while (*entry != NULL) {
+ const smart_objects::SmartObject& param = structure.getElement(
+ (*entry)->name);
+ if (!SetOneArgument(&sub_iter, *entry, param)) {
+ return false;
+ }
+ entry++;
+ }
+ if (!dbus_message_iter_close_container(iter, &sub_iter)) {
+ LOG4CXX_ERROR(logger_, "DBus: Can't close container type (STRUCT)");
+ return false;
+ }
+ return true;
+}
+
+bool DBusAdapter::GetHeader(DBusMessageIter* iter, int* code,
+ std::string* message) {
+ // Get code of response
+ dbus_int32_t intValue;
+ int type = dbus_message_iter_get_arg_type(iter);
+ if (type != DBUS_TYPE_INT32) {
+ LOG4CXX_ERROR(logger_, "DBus: Unknown format of header");
+ return false;
+ }
+ dbus_message_iter_get_basic(iter, &intValue);
+ *code = intValue;
+ LOG4CXX_DEBUG(logger_, "DBus: Code of response " << *code);
+
+ dbus_message_iter_next(iter);
+
+ // Get message of response
+ type = dbus_message_iter_get_arg_type(iter);
+ if (type != DBUS_TYPE_STRING) {
+ LOG4CXX_ERROR(logger_, "DBus: Unknown format of header");
+ return false;
+ }
+ const char* stringValue;
+ dbus_message_iter_get_basic(iter, &stringValue);
+ *message = stringValue;
+ LOG4CXX_DEBUG(logger_, "DBus: message of response " << *message);
+
+ dbus_message_iter_next(iter);
+ return true;
+}
+
+bool DBusAdapter::GetArguments(DBusMessageIter* iter, const ListArgs& rules,
+ smart_objects::SmartObject& args) {
+ LOG4CXX_TRACE(logger_, "GetArguments");
+
+ size_t size = rules.size();
+ for (size_t i = 0; i < size; ++i) {
+ if (!GetOneArgument(iter, rules[i], args)) {
+ return false;
+ }
+ dbus_message_iter_next(iter);
+ }
+ return true;
+}
+
+const DBusSchema& DBusAdapter::get_schema() const {
+ return *schema_;
+}
+
+bool DBusAdapter::GetOneArgument(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::ParameterDescription* rules,
+ smart_objects::SmartObject& args) {
+ if (rules->obligatory) {
+ return GetValue(iter, rules, args[rules->name]);
+ } else {
+ return GetOptionalValue(iter, rules, args);
+ }
+}
+
+bool DBusAdapter::GetValue(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::ParameterDescription* rules,
+ smart_objects::SmartObject& param) {
+ LOG4CXX_DEBUG(logger_, "DBus: Get param " << rules->name);
+ int type = dbus_message_iter_get_arg_type(iter);
+ switch (rules->type) {
+ case ford_message_descriptions::ParameterType::Array:
+ if (type == DBUS_TYPE_ARRAY) {
+ return GetArrayValue(
+ iter,
+ // FIXME (dchmerev@luxoft.com): not portable, danger cast.
+ reinterpret_cast<const ford_message_descriptions::ArrayDescription*>(rules),
+ param);
+ } else {
+ LOG4CXX_ERROR(logger_, "DBus: Not expected type of argument");
+ return false;
+ }
+ break;
+ case ford_message_descriptions::ParameterType::Struct:
+ if (type == DBUS_TYPE_STRUCT) {
+ return GetStructValue(
+ iter,
+ reinterpret_cast<const ford_message_descriptions::StructDescription*>(rules),
+ param);
+ } else {
+ LOG4CXX_ERROR(logger_, "DBus: Not expected type of argument");
+ return false;
+ }
+ break;
+ case ford_message_descriptions::ParameterType::Enum:
+ case ford_message_descriptions::ParameterType::Integer:
+ if (type == DBUS_TYPE_INT32) {
+ dbus_int32_t integerValue;
+ dbus_message_iter_get_basic(iter, &integerValue);
+ smart_objects::SmartObject value(integerValue);
+ param = value;
+ LOG4CXX_DEBUG(logger_, "DBus: " << rules->name << " = " << integerValue);
+ } else {
+ LOG4CXX_ERROR(logger_, "DBus: Not expected type of argument");
+ return false;
+ }
+ break;
+ case ford_message_descriptions::ParameterType::Float:
+ if (type == DBUS_TYPE_DOUBLE) {
+ double floatValue;
+ dbus_message_iter_get_basic(iter, &floatValue);
+ smart_objects::SmartObject value(floatValue);
+ param = value;
+ LOG4CXX_DEBUG(logger_, "DBus: " << rules->name << " = " << floatValue);
+ } else {
+ LOG4CXX_ERROR(logger_, "DBus: Not expected type of argument");
+ return false;
+ }
+ break;
+ case ford_message_descriptions::ParameterType::Boolean:
+ if (type == DBUS_TYPE_BOOLEAN) {
+ dbus_bool_t booleanValue;
+ dbus_message_iter_get_basic(iter, &booleanValue);
+ smart_objects::SmartObject value(static_cast<bool>(booleanValue));
+ param = value;
+ LOG4CXX_DEBUG(
+ logger_,
+ "DBus: " << rules->name << " = " << std::boolalpha << booleanValue);
+ } else {
+ LOG4CXX_ERROR(logger_, "DBus: Not expected type of argument");
+ return false;
+ }
+ break;
+ case ford_message_descriptions::ParameterType::String:
+ if (type == DBUS_TYPE_STRING) {
+ const char* stringValue;
+ dbus_message_iter_get_basic(iter, &stringValue);
+ std::string strValue = stringValue;
+ smart_objects::SmartObject value(strValue);
+ param = value;
+ LOG4CXX_DEBUG(logger_,
+ "DBus: " << rules->name << " = \"" << strValue << "\"");
+ } else {
+ LOG4CXX_ERROR(logger_, "DBus: Not expected type of argument");
+ return false;
+ }
+ break;
+ default:
+ LOG4CXX_ERROR(logger_, "DBus: Unknown type of argument")
+ ;
+ return false;
+ }
+ return true;
+}
+
+bool DBusAdapter::GetArrayValue(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::ArrayDescription* rules,
+ smart_objects::SmartObject& param) {
+ smart_objects::SmartObject array(smart_objects::SmartType_Array);
+
+ int i = 0;
+ DBusMessageIter sub_iter;
+ dbus_message_iter_recurse(iter, &sub_iter);
+ while (dbus_message_iter_get_arg_type(&sub_iter) != DBUS_TYPE_INVALID) {
+ if (!GetValue(&sub_iter, rules->element, array[i])) {
+ return false;
+ }
+ dbus_message_iter_next(&sub_iter);
+ i++;
+ }
+ param = array;
+ return true;
+}
+
+bool DBusAdapter::GetStructValue(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::StructDescription* rules,
+ smart_objects::SmartObject& param) {
+
+ DBusMessageIter sub_iter;
+ dbus_message_iter_recurse(iter, &sub_iter);
+ const ParameterDescription** entry;
+ entry = rules->parameters;
+ smart_objects::SmartObject structure(smart_objects::SmartType_Map);
+ while (*entry != NULL) {
+ if (!GetOneArgument(&sub_iter, *entry, structure)) {
+ return false;
+ }
+ dbus_message_iter_next(&sub_iter);
+ entry++;
+ }
+ param = structure;
+ return true;
+}
+
+bool DBusAdapter::GetOptionalValue(
+ DBusMessageIter* iter,
+ const ford_message_descriptions::ParameterDescription* rules,
+ smart_objects::SmartObject& param) {
+ int type = dbus_message_iter_get_arg_type(iter);
+ if (type != DBUS_TYPE_STRUCT) {
+ LOG4CXX_WARN(logger_, "DBus: Not expected type of argument. It is not optional parameter.");
+ return false;
+ }
+
+ DBusMessageIter sub_iter;
+ dbus_message_iter_recurse(iter, &sub_iter);
+ ford_message_descriptions::ParameterDescription flagRules = { "flag",
+ ford_message_descriptions::Boolean, true };
+ smart_objects::SmartObject flag;
+ if (!GetValue(&sub_iter, &flagRules, flag)) {
+ return false;
+ }
+ if (flag.asBool()) {
+ dbus_message_iter_next(&sub_iter);
+ return GetValue(&sub_iter, rules, param[rules->name]);
+ } else {
+ return true;
+ }
+}
+
+std::pair<uint, MessageId> DBusAdapter::GetRequestToHMI(uint32_t serial) {
+ std::map<uint32_t, std::pair<uint, MessageId> >::iterator it;
+ it = requests_to_hmi_.find(serial);
+ if (it != requests_to_hmi_.end()) {
+ std::pair<uint, MessageId> ids = it->second;
+ requests_to_hmi_.erase(it);
+ return ids;
+ }
+ return std::make_pair(0, hmi_apis::FunctionID::INVALID_ENUM);
+}
+
+void DBusAdapter::SaveRequestToHMI(uint32_t serial,
+ const std::pair<uint, MessageId>& ids) {
+ requests_to_hmi_.insert(std::make_pair(serial, ids));
+}
+
+void DBusAdapter::Introspect(DBusMessage* msg) {
+ DBusMessage *reply;
+
+ dbus_uint32_t serial = dbus_message_get_serial(msg);
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOG4CXX_WARN(logger_, "DBus: Failed return method for introspection");
+ return;
+ }
+
+ DBusMessageIter iter;
+ dbus_message_iter_init_append(reply, &iter);
+ char* value = introspection_xml;
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &value);
+ dbus_connection_send(conn_, reply, &serial);
+ dbus_connection_flush(conn_);
+ dbus_message_unref(reply);
+ dbus_message_unref(msg);
+}
+
+void DBusAdapter::SaveRequestFromHMI(uint32_t serial, DBusMessage* request) {
+ LOG4CXX_DEBUG(logger_, "Save correlation id (serial id) : " << serial);
+ LOG4CXX_DEBUG(logger_, "D-Bus message: " << request);
+ requests_from_hmi_.insert(std::make_pair(serial, request));
+}
+
+DBusMessage* DBusAdapter::GetRequestFromHMI(uint32_t serial) {
+ LOG4CXX_DEBUG(logger_, "Get correlation id (serial id) : " << serial);
+ std::map<uint32_t, DBusMessage*>::iterator it;
+ it = requests_from_hmi_.find(serial);
+ if (it != requests_from_hmi_.end()) {
+ DBusMessage *msg = it->second;
+ requests_from_hmi_.erase(it);
+ LOG4CXX_DEBUG(logger_, "D-Bus message: " << msg);
+ return msg;
+ }
+ return 0;
+}
+
+} // namespace dbus