summaryrefslogtreecommitdiff
path: root/src/CommonAPI/DBus/DBusAddressTranslator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/CommonAPI/DBus/DBusAddressTranslator.cpp')
-rw-r--r--src/CommonAPI/DBus/DBusAddressTranslator.cpp370
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