*/
/*
* @file dbus_access.cpp
- * @author Zbigniew Jasinski <z.jasinski@samsung.com>
- * @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
- * @version 1.1
- * @brief Implementation of SystemD control class over dbus API
+ * @author Zbigniew Jasinski (z.jasinski@samsung.com)
+ * @version 1.0
+ * @brief Functios used in security-tests package for restarting Security Server through
+ * SystemD DBuS interface.
*/
-#include <dpl/log/log.h>
-#include <tests_common.h>
+#include <dbus_access.h>
+#include <dbus_access_impl.h>
-#include <cstring>
-#include <sstream>
-#include <unistd.h>
+namespace {
+const char* const RESTART = "Restart";
+const char* const STOP = "Stop";
+const char* const START = "Start";
+const char* const RESET_FAILED = "ResetFailed";
-#include "dbus_access.h"
+const char* const MODE_FAIL = "fail";
-DBusAccess::DBusAccess(const char *service_name)
- : m_conn(nullptr)
- , m_msg(nullptr)
- , m_pending(nullptr)
- , m_dbus_client_name("tests.dbus.client")
- , m_service_name(service_name)
- , m_dbus_systemd_destination("org.freedesktop.systemd1")
- , m_dbus_systemd_path("/org/freedesktop/systemd1")
- , m_dbus_systemd_manager_interface("org.freedesktop.systemd1.Manager")
- , m_dbus_systemd_properties_interface("org.freedesktop.DBus.Properties")
- , m_dbus_systemd_service_interface("org.freedesktop.systemd1.Service")
- , m_reloadingToken("Reloading")
-{
- dbus_error_init(&m_err);
- connectToDBus();
-}
-
-void DBusAccess::connect() {
- m_conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &m_err);
- RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
- "Error in dbus_bus_get: " << m_err.message);
- dbus_connection_set_exit_on_disconnect(m_conn, FALSE);
-}
-
-void DBusAccess::addBusMatch(const char *member) {
- std::ostringstream rule;
- rule << "type='signal',"
- << "sender='" << m_dbus_systemd_destination << "',"
- << "interface='" << m_dbus_systemd_manager_interface << "',"
- << "member='" << member << "',"
- << "path='" << m_dbus_systemd_path << "'";
-
- dbus_bus_add_match(m_conn, rule.str().c_str(), &m_err);
- RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
- "Error in dbus_bus_add_match: " << m_err.message);
-}
-
-void DBusAccess::subscribeSignals() {
- newMethodCall("Subscribe");
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
-}
-
-void DBusAccess::reloadDbusManager() {
- newMethodCall("Reload");
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
- m_runningJobs.insert(m_reloadingToken);
-}
-
-void DBusAccess::requestName() {
- dbus_bus_request_name(m_conn, m_dbus_client_name.c_str(),
- DBUS_NAME_FLAG_REPLACE_EXISTING , &m_err);
- RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
- "Error in dbus_bus_request_name: " << m_err.message);
-}
-
-void DBusAccess::getUnitPath() {
- newMethodCall("GetUnit");
- appendToMsg(m_service_name.c_str());
- sendMsgWithReply();
- getMsgReply();
- m_unitPath = handleObjectPathMsgReply();
-}
-
-void DBusAccess::newMethodCall(const char *method) {
- m_msg = dbus_message_new_method_call(m_dbus_systemd_destination.c_str(),
- m_dbus_systemd_path.c_str(),
- m_dbus_systemd_manager_interface.c_str(),
- method);
- RUNNER_ASSERT_MSG(nullptr != m_msg,
- "Error in dbus_message_new_method_call");
-}
-
-void DBusAccess::appendToMsg(const char *argument) {
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(m_msg, &iter);
- int ret = dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
- &argument);
- RUNNER_ASSERT_MSG(ret != 0,
- "Error in dbus_message_iter_append_basic");
-}
-
-void DBusAccess::appendToMsg(const char *const *argument) {
- DBusMessageIter iter;
- DBusMessageIter subIter;
- int ret;
-
- dbus_message_iter_init_append(m_msg, &iter);
- ret = dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING,
- &subIter);
- RUNNER_ASSERT_MSG(ret != 0,
- "Error in dbus_message_iter_open_container");
- for (auto str = argument; *str; str++) {
- int ret = dbus_message_iter_append_basic(&subIter, DBUS_TYPE_STRING, str);
- RUNNER_ASSERT_MSG(ret != 0,
- "Error in dbus_message_iter_append_basic");
- }
- ret = dbus_message_iter_close_container(&iter, &subIter);
- RUNNER_ASSERT_MSG(ret != 0,
- "Error in dbus_message_iter_close_container");
-}
-
-void DBusAccess::appendToMsg(bool argument) {
- DBusMessageIter iter;
-
- dbus_message_iter_init_append(m_msg, &iter);
- int b = argument ? 1 : 0;
- int ret = dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN,
- &b);
- RUNNER_ASSERT_MSG(ret != 0,
- "Error in dbus_message_iter_append_basic");
-}
-
-void DBusAccess::sendMsgWithReply() {
- int ret = dbus_connection_send_with_reply(m_conn, m_msg, &m_pending, -1);
- RUNNER_ASSERT_MSG(ret == 1,
- "Error in dbus_connection_send_with_reply");
-
- RUNNER_ASSERT_MSG(nullptr != m_pending, "Pending call null");
-
- dbus_connection_flush(m_conn);
- dbus_pending_call_block(m_pending);
-
- dbus_message_unref(m_msg);
- m_msg = nullptr;
-}
-
-void DBusAccess::getMsgReply() {
- m_msg = dbus_pending_call_steal_reply(m_pending);
- RUNNER_ASSERT_MSG(nullptr != m_msg,
- "Error in dbus_pending_call_steal_reply");
-}
-
-std::string DBusAccess::handleObjectPathMsgReply() {
- DBusMessageIter iter;
-
- RUNNER_ASSERT_MSG(dbus_message_iter_init(m_msg, &iter) != 0,
- "Message has no arguments");
- if (DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("Object path type expected");
- }
- char *tmp;
- dbus_message_iter_get_basic(&iter, &tmp);
- std::string ret(tmp);
-
- finalizeMsgReply();
- return ret;
-}
-
-uint32_t DBusAccess::handleVariantUIntMsgReply() {
- DBusMessageIter iter, iter2;
-
- RUNNER_ASSERT_MSG(dbus_message_iter_init(m_msg, &iter) != 0,
- "Message has no arguments");
- if (DBUS_TYPE_VARIANT != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("Variant type expected");
- }
-
- dbus_message_iter_recurse(&iter, &iter2);
- if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&iter2)) {
- RUNNER_FAIL_MSG("uint32 type expected");
- }
+} // anonymous namespace
- uint32_t ret;
- dbus_message_iter_get_basic(&iter2, &ret);
-
- finalizeMsgReply();
- return ret;
-}
-
-void DBusAccess::finalizeMsgReply() {
- dbus_message_unref(m_msg);
- dbus_pending_call_unref(m_pending);
- m_msg = nullptr;
- m_pending = nullptr;
-}
-
-void DBusAccess::connectToDBus() {
- connect();
- addBusMatch("JobRemoved");
- addBusMatch("JobNew");
- addBusMatch("Reloading");
- dbus_connection_flush(m_conn);
- dbus_connection_add_filter(m_conn,
- messageHandler,
- reinterpret_cast<void*>(this),
- [](void*)->void {});
- subscribeSignals();
- requestName();
- getUnitPath();
-}
-
-void DBusAccess::sendToService(const char *method) {
- newMethodCall(method);
- appendToMsg(m_service_name.c_str());
- appendToMsg("fail");
- sendMsgWithReply();
- getMsgReply();
- m_runningJobs.insert(handleObjectPathMsgReply());
-}
-
-void DBusAccess::sendMaskToService() {
- const char *mask[] = {m_service_name.c_str(), nullptr};
- newMethodCall("MaskUnitFiles");
- appendToMsg(mask);
- appendToMsg(true);
- appendToMsg(true);
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
-}
-
-void DBusAccess::sendUnmaskToService() {
- const char *mask[] = {m_service_name.c_str(), nullptr};
- newMethodCall("UnmaskUnitFiles");
- appendToMsg(mask);
- appendToMsg(true);
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
-}
-
-uint32_t DBusAccess::getUIntProperty(const char *interface, const char *property)
+DBusAccess::DBusAccess(const char* const object)
{
- m_msg = dbus_message_new_method_call(m_dbus_systemd_destination.c_str(),
- m_unitPath.c_str(),
- m_dbus_systemd_properties_interface.c_str(),
- "Get");
-
- appendToMsg(interface);
- appendToMsg(property);
- sendMsgWithReply();
- getMsgReply();
- return handleVariantUIntMsgReply();
-}
-
-void DBusAccess::sendResetFailedToService() {
- newMethodCall("ResetFailedUnit");
- appendToMsg(m_service_name.c_str());
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
-}
-
-DBusHandlerResult DBusAccess::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t) {
- (void) conn;
- DBusAccess* self = reinterpret_cast<DBusAccess*>(t);
-
- if (self->isSignal(msg, "JobRemoved"))
- self->signalJobRemovedHandler(msg);
- else if (self->isSignal(msg, "JobNew"))
- self->signalJobNewHandler(msg);
- else if (self->isSignal(msg, "Reloading"))
- self->signalReloadingHandler(msg);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ m_impl.reset(new DBusAccess::Impl(object));
}
-bool DBusAccess::isSignal(DBusMessage *msg, const char *signal) {
- return dbus_message_is_signal(msg, m_dbus_systemd_manager_interface.c_str(), signal);
-}
-
-void DBusAccess::signalJobRemovedHandler(DBusMessage *msg) {
- DBusMessageIter iter;
- RUNNER_ASSERT_MSG(dbus_message_iter_init(msg, &iter) != 0,
- "Message has no arguments");
-
- if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("uint32 type expected");
- }
- uint32_t id;
- dbus_message_iter_get_basic(&iter, &id);
-
- dbus_message_iter_next (&iter);
- if (DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("Object path type expected");
- }
- char *path;
- dbus_message_iter_get_basic(&iter, &path);
-
- dbus_message_iter_next (&iter);
- if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("String type expected");
- }
- char *unit;
- dbus_message_iter_get_basic(&iter, &unit);
-
- dbus_message_iter_next (&iter);
- if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("String type expected");
- }
- char *result;
- dbus_message_iter_get_basic(&iter, &result);
-
- if(m_service_name == unit) {
- RUNNER_ASSERT_MSG(strcmp(result, "done") == 0 || strcmp(result, "canceled") == 0,
- "RemoveJob signal delivered bad news. Job wasn't completed successfully: "
- << "expected job results = {done, canceled}, "
- << "received job result = " << result << ", "
- << "for job with id = " << id << ", "
- << "and path = " << path);
- m_runningJobs.erase(path);
- }
-}
-
-void DBusAccess::signalJobNewHandler(DBusMessage *msg) {
- DBusMessageIter iter;
- RUNNER_ASSERT_MSG(dbus_message_iter_init(msg, &iter) != 0,
- "Message has no arguments");
-
- if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("uint32 type expected");
- }
- uint32_t id;
- dbus_message_iter_get_basic(&iter, &id);
-
- dbus_message_iter_next (&iter);
- if (DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("Object path type expected");
- }
- char *path;
- dbus_message_iter_get_basic(&iter, &path);
-
- dbus_message_iter_next (&iter);
- if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("String type expected");
- }
- char *unit;
- dbus_message_iter_get_basic(&iter, &unit);
-
- if(m_service_name == unit)
- m_runningJobs.insert(path);
+DBusAccess::~DBusAccess()
+{
}
-void DBusAccess::signalReloadingHandler(DBusMessage *msg) {
- DBusMessageIter iter;
- RUNNER_ASSERT_MSG(dbus_message_iter_init(msg, &iter) != 0,
- "Message has no arguments");
-
- if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&iter)) {
- RUNNER_FAIL_MSG("boolean type expected");
- }
- bool active;
- dbus_message_iter_get_basic(&iter, &active);
+void DBusAccess::restart() {
+ /*
+ * Example:
+ * dbus-send --system --dest=org.freedesktop.systemd1 --print-reply
+ * /org/freedesktop/systemd1/unit/central_2dkey_2dmanager_2eservice
+ * org.freedesktop.systemd1.Unit.Restart string:fail
+ */
+ m_impl->newMethodCall(RESTART);
+ m_impl->setMode(MODE_FAIL);
+ m_impl->sendCommand();
- if (active)
- m_runningJobs.insert(m_reloadingToken);
- else
- m_runningJobs.erase(m_reloadingToken);
-}
+ m_impl->waitForJobEnd();
-void DBusAccess::waitForRunningJobsFinish() {
- while (!m_runningJobs.empty())
- dbus_connection_read_write_dispatch(m_conn, -1);
+ sendResetFailed();
}
-void DBusAccess::startService() {
- sendToService("StartUnit");
- waitForRunningJobsFinish();
- sendResetFailedToService();
-}
+void DBusAccess::start() {
+ m_impl->newMethodCall(START);
+ m_impl->setMode(MODE_FAIL);
+ m_impl->sendCommand();
-void DBusAccess::stopService() {
- sendToService("StopUnit");
- waitForRunningJobsFinish();
- sendResetFailedToService();
-}
+ m_impl->waitForJobEnd();
-void DBusAccess::restartService() {
- sendToService("RestartUnit");
- waitForRunningJobsFinish();
- sendResetFailedToService();
+ sendResetFailed();
}
-pid_t DBusAccess::getServicePid() {
- return static_cast<pid_t>(getUIntProperty(m_dbus_systemd_service_interface.c_str(), "MainPID"));
-}
+void DBusAccess::stop() {
+ m_impl->newMethodCall(STOP);
+ m_impl->setMode(MODE_FAIL);
+ m_impl->sendCommand();
-void DBusAccess::maskService() {
- sendMaskToService();
- reloadDbusManager();
- waitForRunningJobsFinish();
- sendResetFailedToService();
-}
+ m_impl->waitForJobEnd();
-void DBusAccess::unmaskService() {
- sendUnmaskToService();
- reloadDbusManager();
- waitForRunningJobsFinish();
- sendResetFailedToService();
+ sendResetFailed();
}
-DBusAccess::~DBusAccess() {
- dbus_connection_close(m_conn);
- if (m_conn)
- dbus_connection_unref(m_conn);
- dbus_error_free(&m_err);
- if (m_msg)
- dbus_message_unref(m_msg);
- if (m_pending)
- dbus_pending_call_unref(m_pending);
+void DBusAccess::sendResetFailed() {
+ m_impl->newMethodCall(RESET_FAILED);
+ m_impl->sendCommand(false);
}
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd 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
+ */
+/*
+ * @file dbus_access_impl.cpp
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ */
+
+#include <dbus_access_impl.h>
+
+#include <tests_common.h>
+
+DBusAccess::Impl::Impl(const char* object)
+ : m_conn(NULL)
+ , m_msg(NULL)
+ , m_pending(NULL)
+ , m_handled(false)
+{
+ dbus_error_init(&m_err);
+
+ m_signal_type = "signal";
+ m_signal_interface = "org.freedesktop.systemd1.Manager";
+ m_signal_path = "/org/freedesktop/systemd1";
+ m_dbus_client_name = "tests.dbus.client";
+ m_signal_member = "JobRemoved";
+ m_dbus_systemd_object = object;
+
+ m_conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &m_err);
+ RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
+ "Error in dbus_bus_get: " << m_err.message);
+ dbus_connection_set_exit_on_disconnect(m_conn, FALSE);
+
+ dbus_bus_request_name(m_conn, m_dbus_client_name.c_str(),
+ DBUS_NAME_FLAG_REPLACE_EXISTING , &m_err);
+ RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
+ "Error in dbus_bus_request_name: " << m_err.message);
+}
+
+DBusAccess::Impl::~Impl() {
+ dbus_connection_close(m_conn);
+ if (m_conn)
+ dbus_connection_unref(m_conn);
+ dbus_error_free(&m_err);
+ if (m_msg)
+ dbus_message_unref(m_msg);
+ if (m_pending)
+ dbus_pending_call_unref(m_pending);
+}
+
+void DBusAccess::Impl::newMethodCall(const char* method) {
+ const std::string dbus_systemd_name = "org.freedesktop.systemd1";
+ const std::string dbus_systemd_interface = "org.freedesktop.systemd1.Unit";
+
+ m_msg = dbus_message_new_method_call(dbus_systemd_name.c_str(),
+ m_dbus_systemd_object.c_str(),
+ dbus_systemd_interface.c_str(),
+ method);
+ RUNNER_ASSERT_MSG(NULL != m_msg,
+ "Error in dbus_message_new_method_call");
+}
+
+void DBusAccess::Impl::setMode(const char* mode) {
+ DBusMessageIter iter;
+ const char *dbus_systemd_srv_unit_mode = mode;
+
+ dbus_message_iter_init_append(m_msg, &iter);
+ int ret = dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+ &dbus_systemd_srv_unit_mode);
+ RUNNER_ASSERT_MSG(ret != 0,
+ "Error in dbus_message_iter_append_basic");
+}
+
+void DBusAccess::Impl::sendMsgWithReply() {
+ int ret = dbus_connection_send_with_reply(m_conn, m_msg, &m_pending, -1);
+ RUNNER_ASSERT_MSG(ret == 1,
+ "Error in dbus_connection_send_with_reply");
+
+ RUNNER_ASSERT_MSG(NULL != m_pending, "Pending call null");
+
+ dbus_connection_flush(m_conn);
+ dbus_pending_call_block(m_pending);
+ dbus_message_unref(m_msg);
+ m_msg = NULL;
+}
+
+void DBusAccess::Impl::getMsgReply() {
+ m_msg = dbus_pending_call_steal_reply(m_pending);
+ RUNNER_ASSERT_MSG(NULL != m_msg,
+ "Error in dbus_pending_call_steal_reply");
+}
+
+void DBusAccess::Impl::handleMsgReply() {
+ char *object_path = NULL;
+ DBusMessageIter iter;
+
+ RUNNER_ASSERT_MSG(dbus_message_iter_init(m_msg, &iter) != 0,
+ "Message has no arguments");
+ if (DBUS_TYPE_OBJECT_PATH == dbus_message_iter_get_arg_type(&iter)) {
+ dbus_message_iter_get_basic(&iter, &object_path);
+ m_jobID = std::strrchr(object_path, '/') + 1;
+ } else {
+ RUNNER_ASSERT_MSG(false, "No job path in msg");
+ }
+ dbus_message_unref(m_msg);
+ dbus_pending_call_unref(m_pending);
+ m_msg = NULL;
+ m_pending = NULL;
+}
+
+DBusHandlerResult DBusAccess::Impl::signalFilter(DBusConnection *, DBusMessage *message, void *This) {
+ DBusMessageIter iter;
+ dbus_uint32_t id;
+ DBusAccess::Impl *a = reinterpret_cast<DBusAccess::Impl *>(This);
+
+ if (dbus_message_is_signal(message, a->m_signal_interface.c_str(), a->m_signal_member.c_str()))
+ {
+ RUNNER_ASSERT_MSG(dbus_message_iter_init(message, &iter) != 0,
+ "No messages in reply");
+
+ RUNNER_ASSERT_MSG(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32,
+ "Argument is not integer");
+
+ dbus_message_iter_get_basic(&iter, &id);
+
+ if (id == (unsigned int)std::stoi(a->m_jobID)) {
+ while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) {
+ if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
+ char *str = NULL;
+ dbus_message_iter_get_basic(&iter, &str);
+ if (!strncmp(str, "done", strlen("done")))
+ a->m_handled = true;
+ }
+ dbus_message_iter_next(&iter);
+ }
+ }
+ }
+ return (a->m_handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+}
+
+void DBusAccess::Impl::waitForJobEnd() {
+ std::string signal_match = "type='" + m_signal_type + "',interface='" + m_signal_interface +
+ "',member='" + m_signal_member + "',path='" + m_signal_path + "'";
+
+ dbus_bus_add_match(m_conn, signal_match.c_str(), &m_err);
+ RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
+ "Error in dbus_bus_add_match: " << m_err.message);
+
+ dbus_connection_add_filter(m_conn, signalFilter, reinterpret_cast<void *>(this), NULL);
+
+ while(dbus_connection_read_write_dispatch(m_conn, 1000)) {
+ if(m_handled)
+ break;
+ }
+ m_handled = false;
+}
+
+void DBusAccess::Impl::sendCommand(bool handleReply) {
+ sendMsgWithReply();
+ getMsgReply();
+ if (handleReply)
+ handleMsgReply();
+}