5349171f18a9b989740de18f6e4985236f16e14a
[platform/core/test/security-tests.git] / src / common / service_manager.cpp
1 /*
2  * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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
15  */
16 /*
17  * @file        service_manager.cpp
18  * @author      Zbigniew Jasinski <z.jasinski@samsung.com>
19  * @author      Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
20  * @author      Marcin Niesluchowski <m.niesluchow@samsung.com>
21  * @version     1.1
22  * @brief       Definition of service control class using dbus interface to communicate with systemd
23  */
24
25 #include <service_manager.h>
26
27 #include <dpl/test/test_runner.h>
28
29 #include <sstream>
30 #include <unistd.h>
31 #include <vector>
32
33 namespace {
34
35 const std::string DBUS_CLIENT_NAME("tests.dbus.client");
36 const std::string DBUS_PROPERTIES_INTERFACE("org.freedesktop.DBus.Properties");
37 const std::string SYSTEMD_DESTINATION("org.freedesktop.systemd1");
38 const std::string SYSTEMD_PATH("/org/freedesktop/systemd1");
39 const std::string SYSTEMD_MANAGER_INTERFACE("org.freedesktop.systemd1.Manager");
40 const std::string SYSTEMD_SERVICE_INTERFACE("org.freedesktop.systemd1.Service");
41
42 const std::string MATCH_JOB_REMOVED("JobRemoved");
43 const std::string MATCH_JOB_NEW("JobNew");
44 const std::string MATCH_RELOADING("Reloading");
45
46 }
47
48 ServiceManager::ServiceManager(const std::string &serviceName)
49     : m_connection(DBUS_BUS_SYSTEM, true)
50     , m_serviceName(serviceName)
51 {
52     addBusMatch(MATCH_JOB_REMOVED);
53     addBusMatch(MATCH_JOB_NEW);
54     addBusMatch(MATCH_RELOADING);
55     m_connection.flush();
56     m_connection.addFilter(messageHandler,
57                            static_cast<void*>(this));
58     subscribeSignals();
59     m_connection.requestName(DBUS_CLIENT_NAME);
60     getUnitPath();
61 }
62
63 void ServiceManager::addBusMatch(const std::string &member)
64 {
65     std::ostringstream rule;
66     rule << "type='signal',"
67          << "sender='" << SYSTEMD_DESTINATION << "',"
68          << "interface='" << SYSTEMD_MANAGER_INTERFACE << "',"
69          << "member='" << member << "',"
70          << "path='" << SYSTEMD_PATH << "'";
71
72     m_connection.addMatch(rule.str());
73 }
74
75 void ServiceManager::subscribeSignals()
76 {
77     DBus::MessageOut messageOut = newMethodCall("Subscribe");
78     m_connection.sendWithReplyAndBlock(messageOut);
79 }
80
81 void ServiceManager::reloadDbusManager()
82 {
83     DBus::MessageOut messageOut = newMethodCall("Reload");
84     m_connection.sendWithReplyAndBlock(messageOut);
85     m_runningJobs.insert(MATCH_RELOADING);
86 }
87
88 void ServiceManager::getUnitPath()
89 {
90     DBus::MessageOut messageOut = newMethodCall("GetUnit");
91     messageOut.append(m_serviceName);
92     DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
93     m_unitPath = handleObjectPathMsgReply(messageIn);
94 }
95
96 DBus::MessageOut ServiceManager::newMethodCall(const std::string &method)
97 {
98     return DBus::MessageOut(SYSTEMD_DESTINATION.c_str(),
99                       SYSTEMD_PATH.c_str(),
100                       SYSTEMD_MANAGER_INTERFACE.c_str(),
101                       method.c_str());
102 }
103
104 std::string ServiceManager::handleObjectPathMsgReply(DBus::MessageIn &messageIn)
105 {
106     DBus::MessageIn::Iterator iterator = messageIn.iterInit();
107     iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
108     return iterator.getArgString();
109 }
110
111 uint32_t ServiceManager::handleVariantUIntMsgReply(DBus::MessageIn &messageIn)
112 {
113     DBus::MessageIn::Iterator iterator = messageIn.iterInit();
114     iterator.expectArgType(DBUS_TYPE_VARIANT);
115     DBus::MessageIn::Iterator iteratorSub = iterator.recurse();
116     iteratorSub.expectArgType(DBUS_TYPE_UINT32);
117     return iteratorSub.getArgUint32();
118 }
119
120 uint64_t ServiceManager::handleVariantUInt64MsgReply(DBus::MessageIn &messageIn)
121 {
122     DBus::MessageIn::Iterator iterator = messageIn.iterInit();
123     iterator.expectArgType(DBUS_TYPE_VARIANT);
124     DBus::MessageIn::Iterator iteratorSub = iterator.recurse();
125     iteratorSub.expectArgType(DBUS_TYPE_UINT64);
126     return iteratorSub.getArgUint64();
127 }
128
129 void ServiceManager::sendToService(const std::string &method)
130 {
131     DBus::MessageOut messageOut = newMethodCall(method);
132     messageOut.append(m_serviceName);
133     messageOut.append("fail");
134     DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
135     m_runningJobs.insert(handleObjectPathMsgReply(messageIn));
136 }
137
138 void ServiceManager::sendMaskToService()
139 {
140     const std::vector<std::string> mask(1, m_serviceName);
141     DBus::MessageOut messageOut = newMethodCall("MaskUnitFiles");
142     messageOut.append(mask);
143     messageOut.append(true);
144     messageOut.append(true);
145     m_connection.sendWithReplyAndBlock(messageOut);
146 }
147
148 void ServiceManager::sendUnmaskToService()
149 {
150     const std::vector<std::string> mask(1, m_serviceName);
151     DBus::MessageOut messageOut = newMethodCall("UnmaskUnitFiles");
152     messageOut.append(mask);
153     messageOut.append(true);
154     m_connection.sendWithReplyAndBlock(messageOut);
155 }
156
157 DBus::MessageIn ServiceManager::sendPropertyGetMsg(const std::string &interface,
158                                                    const std::string &property)
159 {
160     DBus::MessageOut messageOut(SYSTEMD_DESTINATION,
161                                 m_unitPath,
162                                 DBUS_PROPERTIES_INTERFACE,
163                                 "Get");
164     messageOut.append(interface);
165     messageOut.append(property);
166     return m_connection.sendWithReplyAndBlock(messageOut);
167 }
168
169 uint32_t ServiceManager::getUIntProperty(const std::string &interface,
170                                          const std::string &property)
171 {
172     DBus::MessageIn messageIn = sendPropertyGetMsg(interface, property);
173     return handleVariantUIntMsgReply(messageIn);
174 }
175
176 uint64_t ServiceManager::getUInt64Property(const std::string &interface,
177                                            const std::string &property)
178 {
179     DBus::MessageIn messageIn = sendPropertyGetMsg(interface, property);
180     return handleVariantUInt64MsgReply(messageIn);
181 }
182
183 void ServiceManager::sendResetFailedToService()
184 {
185     DBus::MessageOut messageOut = newMethodCall("ResetFailedUnit");
186     messageOut.append(m_serviceName);
187     m_connection.sendWithReplyAndBlock(messageOut);
188 }
189
190 DBusHandlerResult ServiceManager::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t)
191 {
192     (void) conn;
193     ServiceManager* self = static_cast<ServiceManager*>(t);
194
195     DBus::MessageIn messageIn(msg, true);
196     if (messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_REMOVED))
197         self->signalJobRemovedHandler(messageIn);
198     else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_NEW))
199         self->signalJobNewHandler(messageIn);
200     else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_RELOADING))
201         self->signalReloadingHandler(messageIn);
202
203     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
204 }
205
206 void ServiceManager::signalJobRemovedHandler(DBus::MessageIn &messageIn)
207 {
208     DBus::MessageIn::Iterator iterator = messageIn.iterInit();
209
210     iterator.expectArgType(DBUS_TYPE_UINT32);
211     uint32_t id = iterator.getArgUint32();
212     iterator.expectNext();
213
214     iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
215     std::string path = iterator.getArgString();
216     iterator.expectNext();
217
218     iterator.expectArgType(DBUS_TYPE_STRING);
219     std::string unit = iterator.getArgString();
220     iterator.expectNext();
221
222     iterator.expectArgType(DBUS_TYPE_STRING);
223     std::string result = iterator.getArgString();
224
225     if(m_serviceName == unit) {
226         RUNNER_ASSERT_MSG(result == "done" || result == "canceled",
227                           "RemoveJob signal delivered bad news. Job wasn't completed successfully: "
228                               << "expected job results = {done, canceled}, "
229                               << "received job result = " << result << ", "
230                               << "for job with id = " << id << ", "
231                               << "and path = " << path);
232         m_runningJobs.erase(path);
233     }
234 }
235
236 void ServiceManager::signalJobNewHandler(DBus::MessageIn &messageIn)
237 {
238     DBus::MessageIn::Iterator iterator = messageIn.iterInit();
239
240     iterator.expectArgTypeValid();
241     iterator.expectNext();
242
243     iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
244     std::string path = iterator.getArgString();
245     iterator.expectNext();
246
247     iterator.expectArgType(DBUS_TYPE_STRING);
248     std::string unit = iterator.getArgString();
249
250     if(m_serviceName == unit)
251         m_runningJobs.insert(path);
252 }
253
254 void ServiceManager::signalReloadingHandler(DBus::MessageIn &messageIn)
255 {
256     DBus::MessageIn::Iterator iterator = messageIn.iterInit();
257
258     iterator.expectArgType(DBUS_TYPE_BOOLEAN);
259     bool active = iterator.getArgBool();
260
261     if (active)
262         m_runningJobs.insert(MATCH_RELOADING);
263     else
264         m_runningJobs.erase(MATCH_RELOADING);
265 }
266
267 void ServiceManager::waitForRunningJobsFinish()
268 {
269     while (!m_runningJobs.empty())
270         m_connection.readWriteDispatch();
271 }
272
273 void ServiceManager::startService()
274 {
275     sendToService("StartUnit");
276     waitForRunningJobsFinish();
277     sendResetFailedToService();
278 }
279
280 void ServiceManager::stopService()
281 {
282     sendToService("StopUnit");
283     waitForRunningJobsFinish();
284     sendResetFailedToService();
285 }
286
287 void ServiceManager::restartService()
288 {
289     sendToService("RestartUnit");
290     waitForRunningJobsFinish();
291     sendResetFailedToService();
292 }
293
294 pid_t ServiceManager::getServicePid()
295 {
296     return static_cast<pid_t>(getUIntProperty(SYSTEMD_SERVICE_INTERFACE, "MainPID"));
297 }
298
299 timeval ServiceManager::getServiceStartTimestamp() {
300     uint64_t timestamp = getUInt64Property(SYSTEMD_SERVICE_INTERFACE,
301                                            "ExecMainStartTimestamp");
302     return {static_cast<long>(timestamp / 1000000), static_cast<long>(timestamp % 1000000)};
303 }
304
305 void ServiceManager::maskService()
306 {
307     sendMaskToService();
308     reloadDbusManager();
309     waitForRunningJobsFinish();
310     sendResetFailedToService();
311 }
312
313 void ServiceManager::unmaskService()
314 {
315     sendUnmaskToService();
316     reloadDbusManager();
317     waitForRunningJobsFinish();
318     sendResetFailedToService();
319 }