d38a0c23e605e0e180a21beeb6193abbacf9b29e
[platform/core/security/vasum.git] / server / zone.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Lukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
22  * @brief   Implementation of class for managing one zone
23  */
24
25 #include "config.hpp"
26
27 #include "zone.hpp"
28 #include "base-exception.hpp"
29
30 #include "logger/logger.hpp"
31 #include "utils/paths.hpp"
32 #include "utils/vt.hpp"
33 #include "config/manager.hpp"
34
35 #include <boost/filesystem.hpp>
36
37 #include <string>
38 #include <thread>
39
40 namespace vasum {
41
42 namespace fs = boost::filesystem;
43
44 namespace {
45
46 typedef std::lock_guard<std::recursive_mutex> Lock;
47
48 // TODO: move constants to the config file when default values are implemented there
49 const int RECONNECT_RETRIES = 15;
50 const int RECONNECT_DELAY = 1 * 1000;
51
52 } // namespace
53
54 Zone::Zone(const utils::Worker::Pointer& worker,
55            const std::string& zonesPath,
56            const std::string& zoneConfigPath,
57            const std::string& lxcTemplatePrefix,
58            const std::string& baseRunMountPointPath)
59     : mWorker(worker)
60 {
61     config::loadFromJsonFile(zoneConfigPath, mConfig);
62
63     for (std::string r: mConfig.permittedToSend) {
64         mPermittedToSend.push_back(boost::regex(r));
65     }
66     for (std::string r: mConfig.permittedToRecv) {
67         mPermittedToRecv.push_back(boost::regex(r));
68     }
69
70     if (!mConfig.runMountPoint.empty()) {
71         mRunMountPoint = fs::absolute(mConfig.runMountPoint, baseRunMountPointPath).string();
72     }
73
74     mAdmin.reset(new ZoneAdmin(zonesPath, lxcTemplatePrefix, mConfig));
75     const fs::path zonePath = fs::path(zonesPath) / mAdmin->getId();
76     mProvision.reset(new ZoneProvision(zonePath.string(), mConfig.validLinkPrefixes));
77 }
78
79 Zone::~Zone()
80 {
81     // Make sure all OnNameLostCallbacks get finished and no new will
82     // get called before proceeding further. This guarantees no race
83     // condition on the reconnect thread.
84     {
85         Lock lock(mReconnectMutex);
86         disconnect();
87     }
88     // wait for all tasks to complete
89     mWorker.reset();
90 }
91
92 const std::vector<boost::regex>& Zone::getPermittedToSend() const
93 {
94     return mPermittedToSend;
95 }
96
97 const std::vector<boost::regex>& Zone::getPermittedToRecv() const
98 {
99     return mPermittedToRecv;
100 }
101
102 const std::string& Zone::getId() const
103 {
104     Lock lock(mReconnectMutex);
105     return mAdmin->getId();
106 }
107
108 int Zone::getPrivilege() const
109 {
110     return mConfig.privilege;
111 }
112
113 void Zone::start()
114 {
115     Lock lock(mReconnectMutex);
116     mProvision->start();
117     if (mConfig.enableDbusIntegration) {
118         mConnectionTransport.reset(new ZoneConnectionTransport(mRunMountPoint));
119     }
120     mAdmin->start();
121     if (mConfig.enableDbusIntegration) {
122         connect();
123     }
124
125     // Send to the background only after we're connected, otherwise it'd take ages.
126     LOGD(getId() << ": sending to the background");
127     goBackground();
128 }
129
130 void Zone::startAsync(const StartAsyncResultCallback& callback)
131 {
132     auto startWrapper = [this, callback]() {
133         bool succeeded = false;
134
135         try {
136             start();
137             succeeded = true;
138         } catch(std::exception& e) {
139             LOGE(getId() << ": failed to start: " << e.what());
140         }
141
142         if (callback) {
143             callback(succeeded);
144         }
145     };
146
147     mWorker->addTask(startWrapper);
148 }
149
150 void Zone::stop()
151 {
152     Lock lock(mReconnectMutex);
153     disconnect();
154     mAdmin->stop();
155     mConnectionTransport.reset();
156     mProvision->stop();
157 }
158
159 void Zone::connect()
160 {
161     // assume called under reconnect lock
162     mDbusAddress = mConnectionTransport->acquireAddress();
163     mConnection.reset(new ZoneConnection(mDbusAddress,
164                                               std::bind(&Zone::onNameLostCallback, this)));
165     if (mNotifyCallback) {
166         mConnection->setNotifyActiveZoneCallback(mNotifyCallback);
167     }
168     if (mDisplayOffCallback) {
169         mConnection->setDisplayOffCallback(mDisplayOffCallback);
170     }
171     if (mFileMoveCallback) {
172         mConnection->setFileMoveRequestCallback(mFileMoveCallback);
173     }
174     if (mProxyCallCallback) {
175         mConnection->setProxyCallCallback(mProxyCallCallback);
176     }
177     if (mDbusStateChangedCallback) {
178         mDbusStateChangedCallback(mDbusAddress);
179     }
180 }
181
182 void Zone::disconnect()
183 {
184     // assume called under reconnect lock
185     if (mConnection) {
186         mConnection.reset();
187         mDbusAddress.clear();
188         if (mDbusStateChangedCallback) {
189             // notify about invalid dbusAddress for this zone
190             mDbusStateChangedCallback(std::string());
191         }
192     }
193 }
194
195 std::string Zone::getDbusAddress() const
196 {
197     Lock lock(mReconnectMutex);
198     return mDbusAddress;
199 }
200
201 int Zone::getVT() const
202 {
203     return mConfig.vt;
204 }
205
206 std::string Zone::getRootPath() const
207 {
208     return mProvision->getRootPath();
209 }
210
211
212 bool Zone::activateVT()
213 {
214     Lock lock(mReconnectMutex);
215
216     if (mConfig.vt >= 0) {
217         return utils::activateVT(mConfig.vt);
218     }
219
220     return true;
221 }
222
223 void Zone::goForeground()
224 {
225     Lock lock(mReconnectMutex);
226     mAdmin->setSchedulerLevel(SchedulerLevel::FOREGROUND);
227 }
228
229 void Zone::goBackground()
230 {
231     Lock lock(mReconnectMutex);
232     mAdmin->setSchedulerLevel(SchedulerLevel::BACKGROUND);
233 }
234
235 void Zone::setDetachOnExit()
236 {
237     Lock lock(mReconnectMutex);
238     mAdmin->setDetachOnExit();
239     if (mConnectionTransport) {
240         mConnectionTransport->setDetachOnExit();
241     }
242 }
243
244 void Zone::setDestroyOnExit()
245 {
246     Lock lock(mReconnectMutex);
247     mAdmin->setDestroyOnExit();
248 }
249
250 bool Zone::isRunning()
251 {
252     Lock lock(mReconnectMutex);
253     return mAdmin->isRunning();
254 }
255
256 bool Zone::isStopped()
257 {
258     Lock lock(mReconnectMutex);
259     return mAdmin->isStopped();
260 }
261
262 void Zone::suspend()
263 {
264     Lock lock(mReconnectMutex);
265     mAdmin->suspend();
266 }
267
268 void Zone::resume()
269 {
270     Lock lock(mReconnectMutex);
271     mAdmin->resume();
272 }
273
274 bool Zone::isPaused()
275 {
276     Lock lock(mReconnectMutex);
277     return mAdmin->isPaused();
278 }
279
280 bool Zone::isSwitchToDefaultAfterTimeoutAllowed() const
281 {
282     return mConfig.switchToDefaultAfterTimeout;
283 }
284
285 void Zone::onNameLostCallback()
286 {
287     LOGI(getId() << ": A connection to the DBUS server has been lost, reconnecting...");
288
289     mWorker->addTask(std::bind(&Zone::reconnectHandler, this));
290 }
291
292 void Zone::reconnectHandler()
293 {
294     {
295         Lock lock(mReconnectMutex);
296         disconnect();
297     }
298
299     for (int i = 0; i < RECONNECT_RETRIES; ++i) {
300         // This sleeps even before the first try to give DBUS some time to come back up
301         std::this_thread::sleep_for(std::chrono::milliseconds(RECONNECT_DELAY));
302
303         Lock lock(mReconnectMutex);
304         if (isStopped()) {
305             LOGI(getId() << ": Has stopped, nothing to reconnect to, bailing out");
306             return;
307         }
308
309         try {
310             LOGT(getId() << ": Reconnect try " << i + 1);
311             connect();
312             LOGI(getId() << ": Reconnected");
313             return;
314         } catch (VasumException&) {
315             LOGT(getId() << ": Reconnect try " << i + 1 << " has been unsuccessful");
316         }
317     }
318
319     LOGE(getId() << ": Reconnecting to the DBUS has failed, stopping the zone");
320     stop();
321 }
322
323 void Zone::setNotifyActiveZoneCallback(const NotifyActiveZoneCallback& callback)
324 {
325     Lock lock(mReconnectMutex);
326     mNotifyCallback = callback;
327     if (mConnection) {
328         mConnection->setNotifyActiveZoneCallback(mNotifyCallback);
329     }
330 }
331
332 void Zone::sendNotification(const std::string& zone,
333                                  const std::string& application,
334                                  const std::string& message)
335 {
336     Lock lock(mReconnectMutex);
337     if (mConnection) {
338         mConnection->sendNotification(zone, application, message);
339     } else {
340         LOGE(getId() << ": Can't send notification, no connection to DBUS");
341     }
342 }
343
344 void Zone::setDisplayOffCallback(const DisplayOffCallback& callback)
345 {
346     Lock lock(mReconnectMutex);
347
348     mDisplayOffCallback = callback;
349     if (mConnection) {
350         mConnection->setDisplayOffCallback(callback);
351     }
352 }
353
354 void Zone::setFileMoveRequestCallback(const FileMoveRequestCallback& callback)
355 {
356     Lock lock(mReconnectMutex);
357
358     mFileMoveCallback = callback;
359     if (mConnection) {
360         mConnection->setFileMoveRequestCallback(callback);
361     }
362 }
363
364 void Zone::setProxyCallCallback(const ProxyCallCallback& callback)
365 {
366     Lock lock(mReconnectMutex);
367
368     mProxyCallCallback = callback;
369     if (mConnection) {
370         mConnection->setProxyCallCallback(callback);
371     }
372 }
373
374 void Zone::setDbusStateChangedCallback(const DbusStateChangedCallback& callback)
375 {
376     mDbusStateChangedCallback = callback;
377 }
378
379 void Zone::proxyCallAsync(const std::string& busName,
380                                const std::string& objectPath,
381                                const std::string& interface,
382                                const std::string& method,
383                                GVariant* parameters,
384                                const dbus::DbusConnection::AsyncMethodCallCallback& callback)
385 {
386     Lock lock(mReconnectMutex);
387     if (mConnection) {
388         mConnection->proxyCallAsync(busName,
389                                     objectPath,
390                                     interface,
391                                     method,
392                                     parameters,
393                                     callback);
394     } else {
395         LOGE(getId() << ": Can't do a proxy call, no connection to DBUS");
396     }
397 }
398
399 void Zone::declareFile(const int32_t& type,
400                        const std::string& path,
401                        const int32_t& flags,
402                        const int32_t& mode)
403 {
404     mProvision->declareFile(type, path, flags, mode);
405 }
406
407 void Zone::declareMount(const std::string& source,
408                         const std::string& target,
409                         const std::string& type,
410                         const int64_t& flags,
411                         const std::string& data)
412 {
413     mProvision->declareMount(source, target, type, flags, data);
414 }
415
416 void Zone::declareLink(const std::string& source,
417                        const std::string& target)
418 {
419     mProvision->declareLink(source, target);
420 }
421
422 } // namespace vasum