diff options
Diffstat (limited to 'src/CommonAPI/DBus/DBusAddressTranslator.cpp')
-rw-r--r-- | src/CommonAPI/DBus/DBusAddressTranslator.cpp | 370 |
1 files changed, 258 insertions, 112 deletions
diff --git a/src/CommonAPI/DBus/DBusAddressTranslator.cpp b/src/CommonAPI/DBus/DBusAddressTranslator.cpp index 92f432c..5c5e3f1 100644 --- a/src/CommonAPI/DBus/DBusAddressTranslator.cpp +++ b/src/CommonAPI/DBus/DBusAddressTranslator.cpp @@ -1,149 +1,295 @@ -/* Copyright (C) 2013 BMW Group - * Author: Manfred Bathelt (manfred.bathelt@bmw.de) - * Author: Juergen Gehring (juergen.gehring@bmw.de) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (C) 2013-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifdef WIN32 +#include <Windows.h> +#else +#include <unistd.h> +#endif -#include <CommonAPI/utils.h> +#include <sys/stat.h> -#include "DBusAddressTranslator.h" - -#include "DBusConnection.h" -#include "DBusFactory.h" - -#include "DBusConnection.h" -#include "DBusFactory.h" - -#include <unordered_set> -#include <string.h> -#include <iostream> -#include <fstream> -#include <cassert> -#include <sstream> +#include <algorithm> +#include <CommonAPI/IniFileReader.hpp> +#include <CommonAPI/Logger.hpp> +#include <CommonAPI/Runtime.hpp> +#include <CommonAPI/DBus/DBusAddressTranslator.hpp> namespace CommonAPI { namespace DBus { +const char *COMMONAPI_DBUS_DEFAULT_CONFIG_FILE = "commonapi-dbus.ini"; +const char *COMMONAPI_DBUS_DEFAULT_CONFIG_FOLDER = "/etc/"; + +const std::size_t DBUS_MAXIMUM_NAME_LENGTH = 255; -DBusAddressTranslator::DBusAddressTranslator() {} +static std::shared_ptr<DBusAddressTranslator> theTranslator = std::make_shared<DBusAddressTranslator>(); -void DBusAddressTranslator::init() { - commonApiAddressDetails_ = DBusConfiguration::getInstance().getCommonApiAddressDetails(); - for (auto& addressDetail: commonApiAddressDetails_) { - fillUndefinedValues(addressDetail.second, addressDetail.first); - DBusServiceAddress dbusServiceDefinition = std::get<0>(addressDetail.second); - dbusToCommonApiAddress_.insert( {dbusServiceDefinition, addressDetail.first}); - } +std::shared_ptr<DBusAddressTranslator> DBusAddressTranslator::get() { + return theTranslator; } -DBusAddressTranslator& DBusAddressTranslator::getInstance() { - static DBusAddressTranslator* dbusAddressTranslator; - if(!dbusAddressTranslator) { - dbusAddressTranslator = new DBusAddressTranslator(); - dbusAddressTranslator->init(); - } - return *dbusAddressTranslator; +DBusAddressTranslator::DBusAddressTranslator() + : defaultDomain_("local") { + init(); + + isDefault_ = ("dbus" == Runtime::get()->getDefaultBinding()); } +void +DBusAddressTranslator::init() { + // Determine default configuration file + const char *config = getenv("COMMONAPI_DBUS_DEFAULT_CONFIG"); + if (config) { + defaultConfig_ = config; + } else { + defaultConfig_ = COMMONAPI_DBUS_DEFAULT_CONFIG_FOLDER; + defaultConfig_ += "/"; + defaultConfig_ += COMMONAPI_DBUS_DEFAULT_CONFIG_FILE; + } -void DBusAddressTranslator::searchForDBusAddress(const std::string& domain, - const std::string& interf, - const std::string& instance, - std::string& interfaceName, - std::string& connectionName, - std::string& objectPath) { - std::stringstream ss; - ss << domain << ":" << interf << ":" << instance; - searchForDBusAddress(ss.str(), interfaceName, connectionName, objectPath); + (void)readConfiguration(); } -void DBusAddressTranslator::searchForDBusAddress(const std::string& commonApiAddress, - std::string& interfaceName, - std::string& connectionName, - std::string& objectPath) { - - const auto& foundAddressMapping = commonApiAddressDetails_.find(commonApiAddress); - - if (foundAddressMapping != commonApiAddressDetails_.end()) { - connectionName = std::get<0>(std::get<0>(foundAddressMapping->second)); - objectPath = std::get<1>(std::get<0>(foundAddressMapping->second)); - interfaceName = std::get<2>(std::get<0>(foundAddressMapping->second)); - } else { - findFallbackDBusAddress(commonApiAddress, interfaceName, connectionName, objectPath); - commonApiAddressDetails_.insert( {commonApiAddress, std::make_tuple(std::make_tuple(connectionName, objectPath, interfaceName), false) } ); - } +bool +DBusAddressTranslator::translate(const std::string &_key, DBusAddress &_value) { + return translate(CommonAPI::Address(_key), _value); } +bool +DBusAddressTranslator::translate(const CommonAPI::Address &_key, DBusAddress &_value) { + bool result(true); + std::lock_guard<std::mutex> itsLock(mutex_); + + const auto it = forwards_.find(_key); + if (it != forwards_.end()) { + _value = it->second; + } else if (isDefault_) { + std::string interfaceName(_key.getInterface()); + std::string objectPath("/" + _key.getInstance()); + std::replace(objectPath.begin(), objectPath.end(), '.', '/'); + std::string service(_key.getInterface() + "_" + _key.getInstance()); -void DBusAddressTranslator::fillUndefinedValues(CommonApiServiceDetails& serviceDetails, const std::string& commonApiAddress) const { - std::string connectionName; - std::string objectPath; - std::string interfaceName; + if (isValid(service, '.', false, false, true) + && isValid(objectPath, '/', true) + && isValid(interfaceName, '.')) { + _value.setInterface(interfaceName); + _value.setObjectPath(objectPath); + _value.setService(service); - findFallbackDBusAddress(commonApiAddress, interfaceName, connectionName, objectPath); + forwards_.insert({ _key, _value }); + backwards_.insert({ _value, _key }); + } + } else { + result = false; + } - std::get<0>(std::get<0>(serviceDetails)) = std::get<0>(std::get<0>(serviceDetails)) == "" ? connectionName : std::get<0>(std::get<0>(serviceDetails)); - std::get<1>(std::get<0>(serviceDetails)) = std::get<1>(std::get<0>(serviceDetails)) == "" ? objectPath : std::get<1>(std::get<0>(serviceDetails)); - std::get<2>(std::get<0>(serviceDetails)) = std::get<2>(std::get<0>(serviceDetails)) == "" ? interfaceName : std::get<2>(std::get<0>(serviceDetails)); + return result; } +bool +DBusAddressTranslator::translate(const DBusAddress &_key, std::string &_value) { + CommonAPI::Address address; + if (translate(_key, address)) { + _value = address.getAddress(); + return true; + } + return false; +} -void DBusAddressTranslator::searchForCommonAddress(const std::string& interfaceName, - const std::string& connectionName, - const std::string& objectPath, - std::string& commonApiAddress) { +bool +DBusAddressTranslator::translate(const DBusAddress &_key, CommonAPI::Address &_value) { + bool result(true); + std::lock_guard<std::mutex> itsLock(mutex_); - DBusServiceAddress dbusAddress(connectionName, objectPath, interfaceName); + const auto it = backwards_.find(_key); + if (it != backwards_.end()) { + _value = it->second; + } else if (isDefault_) { + if (isValid(_key.getObjectPath(), '/', true) && isValid(_key.getInterface(), '.')) { + std::string interfaceName(_key.getInterface()); + std::string instance(_key.getObjectPath().substr(1)); + std::replace(instance.begin(), instance.end(), '/', '.'); - const auto& foundAddressMapping = dbusToCommonApiAddress_.find(dbusAddress); - if (foundAddressMapping != dbusToCommonApiAddress_.end()) { - commonApiAddress = foundAddressMapping->second; - } else { - findFallbackCommonAddress(commonApiAddress, interfaceName, connectionName, objectPath); - dbusToCommonApiAddress_.insert( {std::move(dbusAddress), commonApiAddress} ); - } -} + _value.setDomain(defaultDomain_); + _value.setInterface(interfaceName); + _value.setInstance(instance); -void DBusAddressTranslator::getPredefinedInstances(const std::string& connectionName, - std::vector<DBusServiceAddress>& instances) { - instances.clear(); - auto dbusAddress = commonApiAddressDetails_.begin(); - while (dbusAddress != commonApiAddressDetails_.end()) { - CommonApiServiceDetails serviceDetails = dbusAddress->second; - if (connectionName == std::get<0>(std::get<0>(serviceDetails)) - && true == std::get<1>(serviceDetails)) { - instances.push_back(std::get<0>(serviceDetails)); - } - dbusAddress++; - } + forwards_.insert({_value, _key}); + backwards_.insert({_key, _value}); + } else { + result = false; + } + } else { + result = false; + } + + return result; } -void DBusAddressTranslator::findFallbackDBusAddress(const std::string& commonApiAddress, - std::string& interfaceName, - std::string& connectionName, - std::string& objectPath) const { - std::vector<std::string> parts = split(commonApiAddress, ':'); - interfaceName = parts[1]; - connectionName = parts[2]; - objectPath = '/' + parts[2]; - std::replace(objectPath.begin(), objectPath.end(), '.', '/'); + +void +DBusAddressTranslator::insert( + const std::string &_address, + const std::string &_service, const std::string &_path, const std::string &_interface) { + + if (isValid(_service, '.', + (_service.length() > 0 && _service[0] == ':'), + (_service.length() > 0 && _service[0] == ':'), + true) + && isValid(_path, '/', true) + && isValid(_interface, '.')) { + CommonAPI::Address address(_address); + DBusAddress dbusAddress(_service, _path, _interface); + + std::lock_guard<std::mutex> itsLock(mutex_); + auto fw = forwards_.find(address); + auto bw = backwards_.find(dbusAddress); + if (fw == forwards_.end() && bw == backwards_.end()) { + forwards_[address] = dbusAddress; + backwards_[dbusAddress] = address; + COMMONAPI_DEBUG( + "Added address mapping: ", address, " <--> ", dbusAddress); + } else if(bw != backwards_.end() && bw->second != address) { + COMMONAPI_ERROR("Trying to overwrite existing DBus address " + "which is already mapped to a CommonAPI address: ", + dbusAddress, " <--> ", _address); + } else if(fw != forwards_.end() && fw->second != dbusAddress) { + COMMONAPI_ERROR("Trying to overwrite existing CommonAPI address " + "which is already mapped to a DBus address: ", + _address, " <--> ", dbusAddress); + } + } } -void DBusAddressTranslator::findFallbackCommonAddress(std::string& commonApiAddress, - const std::string& interfaceName, - const std::string& connectionName, - const std::string& objectPath) const { - commonApiAddress = "local:" + interfaceName + ":" + transfromObjectPathToInstance(objectPath); +bool +DBusAddressTranslator::readConfiguration() { +#define MAX_PATH_LEN 255 + std::string config; + char currentDirectory[MAX_PATH_LEN]; +#ifdef WIN32 + if (GetCurrentDirectory(MAX_PATH_LEN, currentDirectory)) { +#else + if (getcwd(currentDirectory, MAX_PATH_LEN)) { +#endif + config = currentDirectory; + config += "/"; + config += COMMONAPI_DBUS_DEFAULT_CONFIG_FILE; + + struct stat s; + if (stat(config.c_str(), &s) != 0) { + config = defaultConfig_; + } + } + + IniFileReader reader; + if (!reader.load(config)) + return false; + + for (auto itsMapping : reader.getSections()) { + CommonAPI::Address itsAddress(itsMapping.first); + + std::string service = itsMapping.second->getValue("service"); + std::string path = itsMapping.second->getValue("path"); + std::string interfaceName = itsMapping.second->getValue("interface"); + + insert(itsMapping.first, service, path, interfaceName); + } + + return true; } -std::string DBusAddressTranslator::transfromObjectPathToInstance(const std::string& path) const { - std::string out = path.substr(1, std::string::npos); - std::replace(out.begin(), out.end(), '/', '.'); - return out; +bool +DBusAddressTranslator::isValid( + const std::string &_name, const char _separator, + bool _ignoreFirst, bool _isAllowedToStartWithDigit, bool _isBusName) const { + // DBus addresses must contain at least one separator + std::size_t separatorPos = _name.find(_separator); + if (separatorPos == std::string::npos) { + COMMONAPI_ERROR( + "Invalid name \'", _name, + "\'. Contains no \'", _separator, "\'"); + return false; + } + + bool isInitial(true); + std::size_t start(0); + + if (_ignoreFirst) { + start = 1; + if (separatorPos == 0) + separatorPos = _name.find(_separator, separatorPos+1); + } + + while (start != std::string::npos) { + // DBus names parts must not be empty + std::string part; + + if (isInitial) { + isInitial = false; + } else { + start++; + } + + if (separatorPos == std::string::npos) { + part = _name.substr(start); + } else { + part = _name.substr(start, separatorPos-start); + } + + if ("" == part) { + COMMONAPI_ERROR( + "Invalid interface name \'", _name, + "\'. Must not contain empty parts."); + return false; + } + + // DBus name parts must not start with a digit (not valid for unique names) + if (!_isAllowedToStartWithDigit) { + if (part[0] >= '0' && part[0] <= '9') { + COMMONAPI_ERROR( + "Invalid interface name \'", _name, + "\'. First character must not be a digit."); + return false; + } + } + + // DBus name parts consist of the ASCII characters [0-9][A-Z][a-z]_, + for (auto c : part) { + // bus names may additionally contain [-] + if (_isBusName && c == '-') + continue; + + if (c < '0' || + (c > '9' && c < 'A') || + (c > 'Z' && c < '_') || + (c > '_' && c < 'a') || + c > 'z') { + COMMONAPI_ERROR( + "Invalid interface name \'", _name, + "\'. Contains illegal character \'", c, + "\'. Only \'[0-9][A-Z][a-z]_\' are allowed."); + return false; + } + } + + start = separatorPos; + separatorPos = _name.find(_separator, separatorPos+1); + } + + // DBus names must not exceed the maximum length + if (_name.length() > DBUS_MAXIMUM_NAME_LENGTH) { + COMMONAPI_ERROR( + "Invalid interface name \'", _name, + "\'. Size exceeds maximum size."); + return false; + } + + return true; } -}// namespace DBus +} // namespace DBus } // namespace CommonAPI |