2 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
17 * @file dbus_access_impl.cpp
18 * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
22 #include <dbus_access_impl.h>
24 #include <tests_common.h>
27 void popArgument(DBusMessageIter *iter, int expected, void *value = NULL) {
28 int type = dbus_message_iter_get_arg_type(iter);
29 RUNNER_ASSERT_MSG(type == expected,
30 "Argument type is: " << type << ". Expected: " << expected);
33 dbus_message_iter_get_basic(iter, value);
34 dbus_message_iter_next (iter);
36 } // namespace anonymous
38 DBusAccess::Impl::Impl(const char* object)
44 dbus_error_init(&m_err);
46 m_signal_type = "signal";
47 m_signal_interface = "org.freedesktop.systemd1.Manager";
48 m_signal_path = "/org/freedesktop/systemd1";
49 m_dbus_client_name = "tests.dbus.client";
50 m_signal_member = "JobRemoved";
51 m_dbus_systemd_object = object;
53 m_conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &m_err);
54 RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
55 "Error in dbus_bus_get: " << m_err.message);
56 dbus_connection_set_exit_on_disconnect(m_conn, FALSE);
58 dbus_bus_request_name(m_conn, m_dbus_client_name.c_str(),
59 DBUS_NAME_FLAG_REPLACE_EXISTING , &m_err);
60 RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
61 "Error in dbus_bus_request_name: " << m_err.message);
64 DBusAccess::Impl::~Impl() {
65 dbus_connection_close(m_conn);
67 dbus_connection_unref(m_conn);
68 dbus_error_free(&m_err);
70 dbus_message_unref(m_msg);
72 dbus_pending_call_unref(m_pending);
75 void DBusAccess::Impl::newMethodCall(const char* method) {
76 const std::string dbus_systemd_name = "org.freedesktop.systemd1";
77 const std::string dbus_systemd_interface = "org.freedesktop.systemd1.Unit";
79 m_msg = dbus_message_new_method_call(dbus_systemd_name.c_str(),
80 m_dbus_systemd_object.c_str(),
81 dbus_systemd_interface.c_str(),
83 RUNNER_ASSERT_MSG(NULL != m_msg,
84 "Error in dbus_message_new_method_call");
87 void DBusAccess::Impl::setMode(const char* mode) {
89 const char *dbus_systemd_srv_unit_mode = mode;
91 dbus_message_iter_init_append(m_msg, &iter);
92 int ret = dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
93 &dbus_systemd_srv_unit_mode);
94 RUNNER_ASSERT_MSG(ret != 0,
95 "Error in dbus_message_iter_append_basic");
98 void DBusAccess::Impl::sendMsgWithReply() {
99 int ret = dbus_connection_send_with_reply(m_conn, m_msg, &m_pending, -1);
100 RUNNER_ASSERT_MSG(ret == 1,
101 "Error in dbus_connection_send_with_reply");
103 RUNNER_ASSERT_MSG(NULL != m_pending, "Pending call null");
105 dbus_connection_flush(m_conn);
106 dbus_pending_call_block(m_pending);
107 dbus_message_unref(m_msg);
111 void DBusAccess::Impl::getMsgReply() {
112 m_msg = dbus_pending_call_steal_reply(m_pending);
113 RUNNER_ASSERT_MSG(NULL != m_msg,
114 "Error in dbus_pending_call_steal_reply");
117 void DBusAccess::Impl::handleMsgReply() {
118 char *object_path = NULL;
119 DBusMessageIter iter;
121 RUNNER_ASSERT_MSG(dbus_message_iter_init(m_msg, &iter) != 0,
122 "Message has no arguments");
123 popArgument(&iter, DBUS_TYPE_OBJECT_PATH, &object_path);
124 m_jobID = std::strrchr(object_path, '/') + 1;
125 dbus_message_unref(m_msg);
126 dbus_pending_call_unref(m_pending);
131 DBusHandlerResult DBusAccess::Impl::signalFilter(DBusConnection *, DBusMessage *message, void *This) {
132 DBusAccess::Impl *a = reinterpret_cast<DBusAccess::Impl *>(This);
134 if (dbus_message_is_signal(message, a->m_signal_interface.c_str(), a->m_signal_member.c_str()))
136 DBusMessageIter iter;
140 dbus_message_iter_init(message, &iter);
142 popArgument(&iter, DBUS_TYPE_UINT32, &id);
143 popArgument(&iter, DBUS_TYPE_OBJECT_PATH);
144 popArgument(&iter, DBUS_TYPE_STRING);
145 popArgument(&iter, DBUS_TYPE_STRING, &result);
147 if (id == (unsigned int)std::stoi(a->m_jobID)) {
148 RUNNER_ASSERT_MSG(strcmp(result, "done") == 0 || strcmp(result, "canceled") == 0,
149 "Unexpected result: " << result);
153 return (a->m_handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
156 void DBusAccess::Impl::addFilter() {
157 std::string signal_match = "type='" + m_signal_type + "',interface='" + m_signal_interface +
158 "',member='" + m_signal_member + "',path='" + m_signal_path + "'";
160 dbus_bus_add_match(m_conn, signal_match.c_str(), &m_err);
161 RUNNER_ASSERT_MSG(dbus_error_is_set(&m_err) != 1,
162 "Error in dbus_bus_add_match: " << m_err.message);
164 // TODO refactor whole class to allow multiple requests and proper filters management
165 dbus_bool_t ret = dbus_connection_add_filter(m_conn, signalFilter, reinterpret_cast<void *>(this), NULL);
166 RUNNER_ASSERT_MSG( TRUE == ret, "dbus_connection_add_filter failed");
171 void DBusAccess::Impl::sendCommand(bool handleReply) {
178 void DBusAccess::Impl::waitForJobEnd() {
179 // TODO add custom timeout
180 while(dbus_connection_read_write_dispatch(m_conn, 1000)) {