* @file service_manager.cpp
* @author Zbigniew Jasinski <z.jasinski@samsung.com>
* @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
+ * @author Marcin Niesluchowski <m.niesluchow@samsung.com>
* @version 1.1
- * @brief Implementation of systemd control class over dbus API
+ * @brief Definition of service control class using dbus interface to communicate with systemd
*/
-#include <dpl/log/log.h>
-#include <tests_common.h>
+#include <service_manager.h>
+
+#include <dpl/test/test_runner.h>
-#include <cstring>
#include <sstream>
#include <unistd.h>
+#include <vector>
-#include <service_manager.h>
+namespace {
+
+const std::string DBUS_CLIENT_NAME("tests.dbus.client");
+const std::string DBUS_PROPERTIES_INTERFACE("org.freedesktop.DBus.Properties");
+const std::string SYSTEMD_DESTINATION("org.freedesktop.systemd1");
+const std::string SYSTEMD_PATH("/org/freedesktop/systemd1");
+const std::string SYSTEMD_MANAGER_INTERFACE("org.freedesktop.systemd1.Manager");
+const std::string SYSTEMD_SERVICE_INTERFACE("org.freedesktop.systemd1.Service");
+
+const std::string MATCH_JOB_REMOVED("JobRemoved");
+const std::string MATCH_JOB_NEW("JobNew");
+const std::string MATCH_RELOADING("Reloading");
-ServiceManager::ServiceManager(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 ServiceManager::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);
+ServiceManager::ServiceManager(const std::string &serviceName)
+ : m_connection(DBUS_BUS_SYSTEM, true)
+ , m_serviceName(serviceName)
+{
+ addBusMatch(MATCH_JOB_REMOVED);
+ addBusMatch(MATCH_JOB_NEW);
+ addBusMatch(MATCH_RELOADING);
+ m_connection.flush();
+ m_connection.addFilter(messageHandler,
+ reinterpret_cast<void*>(this));
+ subscribeSignals();
+ m_connection.requestName(DBUS_CLIENT_NAME);
+ getUnitPath();
}
-void ServiceManager::addBusMatch(const char *member) {
+void ServiceManager::addBusMatch(const std::string &member)
+{
std::ostringstream rule;
rule << "type='signal',"
- << "sender='" << m_dbus_systemd_destination << "',"
- << "interface='" << m_dbus_systemd_manager_interface << "',"
+ << "sender='" << SYSTEMD_DESTINATION << "',"
+ << "interface='" << 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 ServiceManager::subscribeSignals() {
- newMethodCall("Subscribe");
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
-}
-
-void ServiceManager::reloadDbusManager() {
- newMethodCall("Reload");
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
- m_runningJobs.insert(m_reloadingToken);
-}
-
-void ServiceManager::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 ServiceManager::getUnitPath() {
- newMethodCall("GetUnit");
- appendToMsg(m_service_name.c_str());
- sendMsgWithReply();
- getMsgReply();
- m_unitPath = handleObjectPathMsgReply();
-}
-
-void ServiceManager::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 ServiceManager::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 ServiceManager::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 ServiceManager::appendToMsg(bool argument) {
- DBusMessageIter iter;
+ << "path='" << SYSTEMD_PATH << "'";
- 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");
+ m_connection.addMatch(rule.str());
}
-void ServiceManager::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 ServiceManager::subscribeSignals()
+{
+ DBus::MessageOut messageOut = newMethodCall("Subscribe");
+ m_connection.sendWithReplyAndBlock(messageOut);
}
-void ServiceManager::getMsgReply() {
- m_msg = dbus_pending_call_steal_reply(m_pending);
- RUNNER_ASSERT_MSG(nullptr != m_msg,
- "Error in dbus_pending_call_steal_reply");
+void ServiceManager::reloadDbusManager()
+{
+ DBus::MessageOut messageOut = newMethodCall("Reload");
+ m_connection.sendWithReplyAndBlock(messageOut);
+ m_runningJobs.insert(MATCH_RELOADING);
}
-std::string ServiceManager::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;
+void ServiceManager::getUnitPath()
+{
+ DBus::MessageOut messageOut = newMethodCall("GetUnit");
+ messageOut.append(m_serviceName);
+ DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
+ m_unitPath = handleObjectPathMsgReply(messageIn);
}
-uint32_t ServiceManager::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");
- }
-
- uint32_t ret;
- dbus_message_iter_get_basic(&iter2, &ret);
-
- finalizeMsgReply();
- return ret;
+DBus::MessageOut ServiceManager::newMethodCall(const std::string &method)
+{
+ return DBus::MessageOut(SYSTEMD_DESTINATION.c_str(),
+ SYSTEMD_PATH.c_str(),
+ SYSTEMD_MANAGER_INTERFACE.c_str(),
+ method.c_str());
}
-void ServiceManager::finalizeMsgReply() {
- dbus_message_unref(m_msg);
- dbus_pending_call_unref(m_pending);
- m_msg = nullptr;
- m_pending = nullptr;
+std::string ServiceManager::handleObjectPathMsgReply(DBus::MessageIn &messageIn)
+{
+ DBus::MessageIn::Iterator iterator = messageIn.iterInit();
+ iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
+ return iterator.getArgString();
}
-void ServiceManager::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();
+uint32_t ServiceManager::handleVariantUIntMsgReply(DBus::MessageIn &messageIn)
+{
+ DBus::MessageIn::Iterator iterator = messageIn.iterInit();
+ iterator.expectArgType(DBUS_TYPE_VARIANT);
+ DBus::MessageIn::Iterator iteratorSub = iterator.recurse();
+ iteratorSub.expectArgType(DBUS_TYPE_UINT32);
+ return iteratorSub.getArgUint32();
}
-void ServiceManager::sendToService(const char *method) {
- newMethodCall(method);
- appendToMsg(m_service_name.c_str());
- appendToMsg("fail");
- sendMsgWithReply();
- getMsgReply();
- m_runningJobs.insert(handleObjectPathMsgReply());
+void ServiceManager::sendToService(const std::string &method)
+{
+ DBus::MessageOut messageOut = newMethodCall(method);
+ messageOut.append(m_serviceName);
+ messageOut.append("fail");
+ DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
+ m_runningJobs.insert(handleObjectPathMsgReply(messageIn));
}
-void ServiceManager::sendMaskToService() {
- const char *mask[] = {m_service_name.c_str(), nullptr};
- newMethodCall("MaskUnitFiles");
- appendToMsg(mask);
- appendToMsg(true);
- appendToMsg(true);
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
+void ServiceManager::sendMaskToService()
+{
+ const std::vector<std::string> mask(1, m_serviceName);
+ DBus::MessageOut messageOut = newMethodCall("MaskUnitFiles");
+ messageOut.append(mask);
+ messageOut.append(true);
+ messageOut.append(true);
+ m_connection.sendWithReplyAndBlock(messageOut);
}
-void ServiceManager::sendUnmaskToService() {
- const char *mask[] = {m_service_name.c_str(), nullptr};
- newMethodCall("UnmaskUnitFiles");
- appendToMsg(mask);
- appendToMsg(true);
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
+void ServiceManager::sendUnmaskToService()
+{
+ const std::vector<std::string> mask(1, m_serviceName);
+ DBus::MessageOut messageOut = newMethodCall("UnmaskUnitFiles");
+ messageOut.append(mask);
+ messageOut.append(true);
+ m_connection.sendWithReplyAndBlock(messageOut);
}
-uint32_t ServiceManager::getUIntProperty(const char *interface, const char *property)
+uint32_t ServiceManager::getUIntProperty(const std::string &interface, const std::string &property)
{
- 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();
+ DBus::MessageOut messageOut(SYSTEMD_DESTINATION.c_str(),
+ SYSTEMD_PATH.c_str(),
+ DBUS_PROPERTIES_INTERFACE.c_str(),
+ "Get");
+ messageOut.append(interface);
+ messageOut.append(property);
+ DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
+ return handleVariantUIntMsgReply(messageIn);
}
-void ServiceManager::sendResetFailedToService() {
- newMethodCall("ResetFailedUnit");
- appendToMsg(m_service_name.c_str());
- sendMsgWithReply();
- getMsgReply();
- finalizeMsgReply();
+void ServiceManager::sendResetFailedToService()
+{
+ DBus::MessageOut messageOut = newMethodCall("ResetFailedUnit");
+ messageOut.append(m_serviceName);
+ m_connection.sendWithReplyAndBlock(messageOut);
}
-DBusHandlerResult ServiceManager::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t) {
+DBusHandlerResult ServiceManager::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t)
+{
(void) conn;
ServiceManager* self = reinterpret_cast<ServiceManager*>(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);
+ DBus::MessageIn messageIn(msg, true);
+ if (messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_REMOVED))
+ self->signalJobRemovedHandler(messageIn);
+ else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_NEW))
+ self->signalJobNewHandler(messageIn);
+ else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_RELOADING))
+ self->signalReloadingHandler(messageIn);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
-bool ServiceManager::isSignal(DBusMessage *msg, const char *signal) {
- return dbus_message_is_signal(msg, m_dbus_systemd_manager_interface.c_str(), signal);
-}
-
-void ServiceManager::signalJobRemovedHandler(DBusMessage *msg) {
- DBusMessageIter iter;
- RUNNER_ASSERT_MSG(dbus_message_iter_init(msg, &iter) != 0,
- "Message has no arguments");
+void ServiceManager::signalJobRemovedHandler(DBus::MessageIn &messageIn)
+{
+ DBus::MessageIn::Iterator iterator = messageIn.iterInit();
- 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);
+ iterator.expectArgType(DBUS_TYPE_UINT32);
+ uint32_t id = iterator.getArgUint32();
+ iterator.expectNext();
- 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);
+ iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
+ std::string path = iterator.getArgString();
+ iterator.expectNext();
- 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);
+ iterator.expectArgType(DBUS_TYPE_STRING);
+ std::string unit = iterator.getArgString();
+ iterator.expectNext();
- 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);
+ iterator.expectArgType(DBUS_TYPE_STRING);
+ std::string result = iterator.getArgString();
- if(m_service_name == unit) {
- RUNNER_ASSERT_MSG(strcmp(result, "done") == 0 || strcmp(result, "canceled") == 0,
+ if(m_serviceName == unit) {
+ RUNNER_ASSERT_MSG(result == "done" || result == "canceled",
"RemoveJob signal delivered bad news. Job wasn't completed successfully: "
<< "expected job results = {done, canceled}, "
<< "received job result = " << result << ", "
}
}
-void ServiceManager::signalJobNewHandler(DBusMessage *msg) {
- DBusMessageIter iter;
- RUNNER_ASSERT_MSG(dbus_message_iter_init(msg, &iter) != 0,
- "Message has no arguments");
+void ServiceManager::signalJobNewHandler(DBus::MessageIn &messageIn)
+{
+ DBus::MessageIn::Iterator iterator = messageIn.iterInit();
- 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);
+ iterator.expectArgTypeValid();
+ iterator.expectNext();
- 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);
+ iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
+ std::string path = iterator.getArgString();
+ iterator.expectNext();
- 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);
+ iterator.expectArgType(DBUS_TYPE_STRING);
+ std::string unit = iterator.getArgString();
- if(m_service_name == unit)
+ if(m_serviceName == unit)
m_runningJobs.insert(path);
}
-void ServiceManager::signalReloadingHandler(DBusMessage *msg) {
- DBusMessageIter iter;
- RUNNER_ASSERT_MSG(dbus_message_iter_init(msg, &iter) != 0,
- "Message has no arguments");
+void ServiceManager::signalReloadingHandler(DBus::MessageIn &messageIn)
+{
+ DBus::MessageIn::Iterator iterator = messageIn.iterInit();
- 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);
+ iterator.expectArgType(DBUS_TYPE_BOOLEAN);
+ bool active = iterator.getArgBool();
if (active)
- m_runningJobs.insert(m_reloadingToken);
+ m_runningJobs.insert(MATCH_RELOADING);
else
- m_runningJobs.erase(m_reloadingToken);
+ m_runningJobs.erase(MATCH_RELOADING);
}
-void ServiceManager::waitForRunningJobsFinish() {
+void ServiceManager::waitForRunningJobsFinish()
+{
while (!m_runningJobs.empty())
- dbus_connection_read_write_dispatch(m_conn, -1);
+ m_connection.readWriteDispatch();
}
-void ServiceManager::startService() {
+void ServiceManager::startService()
+{
sendToService("StartUnit");
waitForRunningJobsFinish();
sendResetFailedToService();
}
-void ServiceManager::stopService() {
+void ServiceManager::stopService()
+{
sendToService("StopUnit");
waitForRunningJobsFinish();
sendResetFailedToService();
}
-void ServiceManager::restartService() {
+void ServiceManager::restartService()
+{
sendToService("RestartUnit");
waitForRunningJobsFinish();
sendResetFailedToService();
}
-pid_t ServiceManager::getServicePid() {
- return static_cast<pid_t>(getUIntProperty(m_dbus_systemd_service_interface.c_str(), "MainPID"));
+pid_t ServiceManager::getServicePid()
+{
+ return static_cast<pid_t>(getUIntProperty(SYSTEMD_SERVICE_INTERFACE, "MainPID"));
}
-void ServiceManager::maskService() {
+void ServiceManager::maskService()
+{
sendMaskToService();
reloadDbusManager();
waitForRunningJobsFinish();
sendResetFailedToService();
}
-void ServiceManager::unmaskService() {
+void ServiceManager::unmaskService()
+{
sendUnmaskToService();
reloadDbusManager();
waitForRunningJobsFinish();
sendResetFailedToService();
}
-
-ServiceManager::~ServiceManager() {
- 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);
-}