From d8fedce7b248e5d57038882889354c617a08ab85 Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Tue, 9 Dec 2014 17:08:00 +0100
Subject: [PATCH 01/16] Fix doxy comments and some other warnings
[Bug/Feature] N/A
[Cause] N/A
[Solution] N/A
[Verification] Build
Change-Id: I5cff5b198d533ec256d551d9e8280a5c117e06d4
---
CMakeLists.txt | 1 -
cli/main.cpp | 4 ++++
client/utils.cpp | 4 ++--
client/vasum-client-impl.cpp | 2 +-
client/vasum-client.h | 4 ++--
common/ipc/client.hpp | 6 +++---
common/ipc/internals/event-queue.hpp | 8 ++++----
common/ipc/internals/processor.cpp | 2 --
common/ipc/service.hpp | 4 ++--
common/utils/initctl.cpp | 2 +-
server/zones-manager.cpp | 6 +++---
tests/unit_tests/client/ut-client.cpp | 8 ++++----
tests/unit_tests/server/ut-zones-manager.cpp | 2 +-
13 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 34573cc..cd999d7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -77,7 +77,6 @@ ADD_DEFINITIONS(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}")
IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# Warn about documentation problems
ADD_DEFINITIONS("-Wdocumentation")
- ADD_DEFINITIONS("-Wno-error=documentation")
IF(ALL_WARNINGS)
# turn on every -W flags except a few explicitly mentioned
diff --git a/cli/main.cpp b/cli/main.cpp
index e837d86..448d32d 100644
--- a/cli/main.cpp
+++ b/cli/main.cpp
@@ -32,6 +32,8 @@
using namespace vasum::cli;
+namespace {
+
std::map commands = {
{
"set_active_zone", {
@@ -93,6 +95,8 @@ void printUsage(std::ostream& out, const std::string& name)
}
}
+} // namespace
+
int main(const int argc, const char** argv)
{
if (argc < 2) {
diff --git a/client/utils.cpp b/client/utils.cpp
index a5ff48e..305b848 100644
--- a/client/utils.cpp
+++ b/client/utils.cpp
@@ -87,8 +87,8 @@ void unescape(std::string& value)
if (c == '-') {
value[outPos++] = '/';
} else if (c == '\\' && value[inPos] == 'x') {
- const char a = unhex(value[inPos+1]);
- const char b = unhex(value[inPos+2]);
+ const int a = unhex(value[inPos+1]);
+ const int b = unhex(value[inPos+2]);
value[outPos++] = (char) ((a << 4) | b);
inPos += 3;
} else {
diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp
index c16c9d2..41898c7 100644
--- a/client/vasum-client-impl.cpp
+++ b/client/vasum-client-impl.cpp
@@ -113,7 +113,7 @@ VsmZoneState getZoneState(const char* state)
} else if (strcmp(state, "ACTIVATING") == 0) {
return ACTIVATING;
}
- assert(!"UNKNOWN STATE");
+ assert(0 && "UNKNOWN STATE");
return (VsmZoneState)-1;
}
diff --git a/client/vasum-client.h b/client/vasum-client.h
index 3e1f66d..eb4cbba 100644
--- a/client/vasum-client.h
+++ b/client/vasum-client.h
@@ -390,7 +390,7 @@ VsmStatus vsm_create_zone(VsmClient client, const char* id, const char* tname);
* @param[in] force if 0 data will be kept, otherwise data will be lost
* @return status of this function call
*/
-VsmStatus vsm_destroy_zone(VsmClient clent, const char* id, int force);
+VsmStatus vsm_destroy_zone(VsmClient client, const char* id, int force);
/**
* Shutdown zone
@@ -624,7 +624,7 @@ VsmStatus vsm_declare_file(VsmClient client,
* @param[in] target mount point (path in zone)
* @param[in] type filesystem type
* @param[in] flags mount flags as in mount function
- * @patam[in] data additional data as in mount function
+ * @param[in] data additional data as in mount function
* @return status of this function call
*/
VsmStatus vsm_declare_mount(VsmClient client,
diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp
index 5233e29..5751812 100644
--- a/common/ipc/client.hpp
+++ b/common/ipc/client.hpp
@@ -89,7 +89,7 @@ public:
* the data will be parsed and passed to this callback.
*
* @param methodID API dependent id of the method
- * @param methodCallback method handling implementation
+ * @param method method handling implementation
*/
template
void addMethodHandler(const MethodID methodID,
@@ -101,7 +101,7 @@ public:
* the data will be parsed and passed to this callback.
*
* @param methodID API dependent id of the method
- * @param SignalHandler signal handling implementation
+ * @param signal signal handling implementation
* @tparam ReceivedDataType data type to serialize
*/
template
@@ -134,7 +134,7 @@ public:
*
*
* @param methodID API dependent id of the method
- * @param sendCallback callback for data serialization
+ * @param data data to send
* @param resultCallback callback for result serialization and handling
*/
template
diff --git a/common/ipc/internals/event-queue.hpp b/common/ipc/internals/event-queue.hpp
index 74a4923..2c591f7 100644
--- a/common/ipc/internals/event-queue.hpp
+++ b/common/ipc/internals/event-queue.hpp
@@ -57,14 +57,14 @@ public:
int getFD() const;
/**
- * Send an event of a given value
+ * Send an event
*
- * @param value size of the buffer
+ * @param message mesage to send
*/
- void send(const MessageType& mess);
+ void send(const MessageType& message);
/**
- * Receives the signal.
+ * Receives the event.
* Blocks if there is no event.
*
* @return event's value
diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp
index aa21675..be1060d 100644
--- a/common/ipc/internals/processor.cpp
+++ b/common/ipc/internals/processor.cpp
@@ -340,8 +340,6 @@ bool Processor::handleInput(const Socket& socket)
}
}
}
-
- return false;
}
std::shared_ptr Processor::onNewSignals(const FileDescriptor peerFD,
diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp
index 5038398..1f9aee3 100644
--- a/common/ipc/service.hpp
+++ b/common/ipc/service.hpp
@@ -94,7 +94,7 @@ public:
* the data will be parsed and passed to this callback.
*
* @param methodID API dependent id of the method
- * @param methodCallback method handling implementation
+ * @param method method handling implementation
*/
template
void addMethodHandler(const MethodID methodID,
@@ -139,7 +139,7 @@ public:
*
*
* @param methodID API dependent id of the method
- * @param sendCallback callback for data serialization
+ * @param data data to send
* @param resultCallback callback for result serialization and handling
*/
template
diff --git a/common/utils/initctl.cpp b/common/utils/initctl.cpp
index f4a778b..5986799 100644
--- a/common/utils/initctl.cpp
+++ b/common/utils/initctl.cpp
@@ -54,7 +54,7 @@ namespace {
}
return false;
}
- size -= r;
+ size -= static_cast(r);
data = reinterpret_cast(data) + r;
}
return true;
diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp
index 6744c30..981556b 100644
--- a/server/zones-manager.cpp
+++ b/server/zones-manager.cpp
@@ -593,7 +593,7 @@ void ZonesManager::handleDeclareFileCall(const std::string& zone,
try {
mZones.at(zone)->declareFile(type, path, flags, mode);
result->setVoid();
- } catch (const std::out_of_range& ex) {
+ } catch (const std::out_of_range&) {
LOGE("No zone with id=" << zone);
result->setError(api::ERROR_INVALID_ID, "No such zone id");
} catch (const config::ConfigException& ex) {
@@ -614,7 +614,7 @@ void ZonesManager::handleDeclareMountCall(const std::string& source,
try {
mZones.at(zone)->declareMount(source, target, type, flags, data);
result->setVoid();
- } catch (const std::out_of_range& ex) {
+ } catch (const std::out_of_range&) {
LOGE("No zone with id=" << zone);
result->setError(api::ERROR_INVALID_ID, "No such zone id");
} catch (const config::ConfigException& ex) {
@@ -632,7 +632,7 @@ void ZonesManager::handleDeclareLinkCall(const std::string& source,
try {
mZones.at(zone)->declareLink(source, target);
result->setVoid();
- } catch (const std::out_of_range& ex) {
+ } catch (const std::out_of_range&) {
LOGE("No zone with id=" << zone);
result->setError(api::ERROR_INVALID_ID, "No such zone id");
} catch (const config::ConfigException& ex) {
diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp
index e8060be..1e23e81 100644
--- a/tests/unit_tests/client/ut-client.cpp
+++ b/tests/unit_tests/client/ut-client.cpp
@@ -145,9 +145,9 @@ BOOST_AUTO_TEST_CASE(GetZoneDbusesTest)
status = vsm_get_zone_dbuses(client, &keys, &values);
BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
- BOOST_CHECK_EQUAL(getArrayStringLength(keys, EXPECTED_DBUSES_STARTED.size() + 1),
+ BOOST_CHECK_EQUAL(getArrayStringLength(keys, EXPECTED_DBUSES_STARTED.size() + 1u),
EXPECTED_DBUSES_STARTED.size());
- BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1),
+ BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1u),
EXPECTED_DBUSES_STARTED.size());
std::map zones;
@@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(GetZoneIdsTest)
VsmArrayString values;
status = vsm_get_zone_ids(client, &values);
BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
- BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1),
+ BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1u),
EXPECTED_DBUSES_STARTED.size());
std::set zones;
@@ -291,7 +291,7 @@ BOOST_AUTO_TEST_CASE(NotificationTest)
BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
}
- BOOST_CHECK(callbackData.signalReceivedLatch.waitForN(clients.size() - 1, EVENT_TIMEOUT));
+ BOOST_CHECK(callbackData.signalReceivedLatch.waitForN(clients.size() - 1u, EVENT_TIMEOUT));
BOOST_CHECK(callbackData.signalReceivedLatch.empty());
for (const auto& msg : callbackData.receivedSignalMsg) {
diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp
index 33d7c50..07c03dd 100644
--- a/tests/unit_tests/server/ut-zones-manager.cpp
+++ b/tests/unit_tests/server/ut-zones-manager.cpp
@@ -620,7 +620,7 @@ BOOST_AUTO_TEST_CASE(NotifyActiveZoneTest)
dbus.second->callMethodNotify();
}
- BOOST_CHECK(signalReceivedLatch.waitForN(dbuses.size() - 1, EVENT_TIMEOUT));
+ BOOST_CHECK(signalReceivedLatch.waitForN(dbuses.size() - 1u, EVENT_TIMEOUT));
BOOST_CHECK(signalReceivedLatch.empty());
//check if there are no signals that was received more than once
--
2.7.4
From 683b44bd6dc9cce82d8bba32e2988225ce52ddbe Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Wed, 10 Dec 2014 18:24:32 +0100
Subject: [PATCH 02/16] Support for boost version less then 1.54 -- disbale
move in config union
[Bug/Feature] Boost < 1.54 doesn't support rvalues in boost::any, better rvalues tests
[Cause] ConfigUnionTest doesn't pass if compiled with boost 1.51
[Solution] Changes in libConfig; Disable moving in union
[Verification] Build, install, run tests
Change-Id: I3bb6af655fa9393bfab66d535705fa252ecf6174
---
tests/unit_tests/config/ut-configuration.cpp | 44 ++++++++++++++++++++++++++--
1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp
index 8aab028..e46bfd8 100644
--- a/tests/unit_tests/config/ut-configuration.cpp
+++ b/tests/unit_tests/config/ut-configuration.cpp
@@ -44,11 +44,31 @@ struct TestConfig {
struct SubSubConfig {
int intVal;
+ bool moved;
CONFIG_REGISTER
(
intVal
)
+ SubSubConfig() : moved(false) {}
+ SubSubConfig(const SubSubConfig& config) : intVal(config.intVal), moved(false) {}
+ SubSubConfig(SubSubConfig&& config) : intVal(std::move(config.intVal)), moved(false) {
+ config.moved = true;
+ }
+ SubSubConfig& operator=(const SubSubConfig& config) {
+ intVal = config.intVal;
+ moved = false;
+ return *this;
+ }
+ SubSubConfig& operator=(SubSubConfig&& config) {
+ intVal = std::move(config.intVal);
+ moved = false;
+ config.moved = true;
+ return *this;
+ }
+ bool isMoved() const {
+ return moved;
+ }
};
int intVal;
@@ -368,7 +388,7 @@ BOOST_AUTO_TEST_CASE(FromToFDTest)
fs::remove(fifoPath);
}
-BOOST_AUTO_TEST_CASE(ConfigUnion)
+BOOST_AUTO_TEST_CASE(ConfigUnionTest)
{
TestConfig testConfig;
BOOST_REQUIRE_NO_THROW(loadFromString(jsonTestString, testConfig));
@@ -385,11 +405,29 @@ BOOST_AUTO_TEST_CASE(ConfigUnion)
std::string out = saveToString(testConfig);
BOOST_CHECK_EQUAL(out, jsonTestString);
- //Check move and copy
+ //Check copy
+
std::vector unions(2);
unions[0].set(2);
+ //set from const lvalue reference (copy)
+ unions[1].set(testConfig.unions[1].as());
+ BOOST_CHECK(!testConfig.unions[1].as().subSubObj.isMoved());
+ //set from lvalue reference (copy)
+ unions[1].set(testConfig.unions[1].as());
+ BOOST_CHECK(!testConfig.unions[1].as().subSubObj.isMoved());
+ //set from const rvalue reference (copy)
+ unions[1].set(std::move(testConfig.unions[1].as()));
+ BOOST_CHECK(!testConfig.unions[1].as().subSubObj.isMoved());
+ //set rvalue reference (copy -- move is disabled)
unions[1].set(std::move(testConfig.unions[1].as()));
- BOOST_CHECK(testConfig.unions[1].as().intVector.empty());
+ BOOST_CHECK(!testConfig.unions[1].as().subSubObj.isMoved());
+ //assign lvalue reference (copy)
+ testConfig.unions[1] = unions[1];
+ BOOST_CHECK(!unions[1].as().subSubObj.isMoved());
+ //assign rvalue reference (copy -- move is disabled)
+ testConfig.unions[1] = std::move(unions[1]);
+ BOOST_CHECK(!unions[1].as().subSubObj.isMoved());
+
testConfig.unions.clear();
testConfig.unions = unions;
out = saveToString(testConfig);
--
2.7.4
From 7a5a6303f9d660195ef58f730b303eab23617f24 Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Mon, 15 Dec 2014 15:20:26 +0100
Subject: [PATCH 03/16] Fix build error ('out' may be used uninitialized)
[Bug/Feature] build error
[Cause] uninitialized variable
[Solution] initialize variable
[Verification] build
Change-Id: I15fa8909d96a5f61998fb774efbc698cb21744f8
Signed-off-by: Dariusz Michaluk
---
client/vasum-client-impl.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp
index 41898c7..3c9448b 100644
--- a/client/vasum-client-impl.cpp
+++ b/client/vasum-client-impl.cpp
@@ -364,7 +364,7 @@ VsmStatus Client::vsm_get_active_zone_id(VsmString* id) noexcept
{
assert(id);
- GVariant* out;
+ GVariant* out = NULL;
VsmStatus ret = callMethod(HOST_INTERFACE,
api::host::METHOD_GET_ACTIVE_ZONE_ID,
NULL,
@@ -409,7 +409,7 @@ VsmStatus Client::vsm_lookup_zone_by_id(const char* id, VsmZone* zone) noexcept
assert(id);
assert(zone);
- GVariant* out;
+ GVariant* out = NULL;
GVariant* args_in = g_variant_new("(s)", id);
VsmStatus ret = callMethod(HOST_INTERFACE,
api::host::METHOD_GET_ZONE_INFO,
@@ -636,7 +636,7 @@ VsmStatus Client::vsm_file_move_request(const char* destZone, const char* path)
assert(destZone);
assert(path);
- GVariant* out;
+ GVariant* out = NULL;
GVariant* args_in = g_variant_new("(ss)", destZone, path);
VsmStatus ret = callMethod(ZONE_INTERFACE,
api::zone::METHOD_FILE_MOVE_REQUEST,
--
2.7.4
From 1ea2e87dd7c56e65f918466cdb20ef5fd2baa434 Mon Sep 17 00:00:00 2001
From: Jan Olszak
Date: Mon, 8 Dec 2014 16:48:21 +0100
Subject: [PATCH 04/16] IPC: Support for the external polling loop in Service
[Bug/Feature] Using GMainLoop is possible
[Cause] N/A
[Solution] For glib > v.2.36
[Verification] Build, install, run tests
Change-Id: Ic6d74688c322dd79b29195d94658a4f2ffe0aa83
---
common/ipc/internals/acceptor.cpp | 44 +++++++---
common/ipc/internals/acceptor.hpp | 25 ++++++
common/ipc/internals/processor.cpp | 84 +++++++++++-------
common/ipc/internals/processor.hpp | 79 ++++++++++-------
common/ipc/internals/utils.cpp | 4 +-
common/ipc/ipc-gsource.cpp | 174 +++++++++++++++++++++++++++++++++++++
common/ipc/ipc-gsource.hpp | 150 ++++++++++++++++++++++++++++++++
common/ipc/service.cpp | 35 ++++++++
common/ipc/service.hpp | 17 ++++
common/ipc/types.cpp | 2 +
tests/unit_tests/ipc/ut-ipc.cpp | 71 ++++++++++++---
11 files changed, 599 insertions(+), 86 deletions(-)
create mode 100644 common/ipc/ipc-gsource.cpp
create mode 100644 common/ipc/ipc-gsource.hpp
diff --git a/common/ipc/internals/acceptor.cpp b/common/ipc/internals/acceptor.cpp
index 3a6c4cd..1eab1c2 100644
--- a/common/ipc/internals/acceptor.cpp
+++ b/common/ipc/internals/acceptor.cpp
@@ -25,21 +25,20 @@
#include "config.hpp"
#include "ipc/exception.hpp"
-#include "ipc/internals/utils.hpp"
#include "ipc/internals/acceptor.hpp"
#include "logger/logger.hpp"
#include
#include
#include
-#include
#include
namespace vasum {
namespace ipc {
Acceptor::Acceptor(const std::string& socketPath, const NewConnectionCallback& newConnectionCallback)
- : mNewConnectionCallback(newConnectionCallback),
+ : mIsRunning(false),
+ mNewConnectionCallback(newConnectionCallback),
mSocket(Socket::createSocket(socketPath))
{
LOGT("Creating Acceptor for socket " << socketPath);
@@ -88,9 +87,8 @@ void Acceptor::run()
fds[1].fd = mSocket.getFD();
fds[1].events = POLLIN;
- // Main loop
- bool isRunning = true;
- while (isRunning) {
+ mIsRunning = true;
+ while (mIsRunning) {
LOGT("Waiting for new connections...");
int ret = ::poll(fds.data(), fds.size(), -1 /*blocking call*/);
@@ -108,23 +106,41 @@ void Acceptor::run()
// Check for incoming connections
if (fds[1].revents & POLLIN) {
fds[1].revents = 0;
- std::shared_ptr tmpSocket = mSocket.accept();
- mNewConnectionCallback(tmpSocket);
+ handleConnection();
}
// Check for incoming events
if (fds[0].revents & POLLIN) {
fds[0].revents = 0;
-
- if (mEventQueue.receive() == Event::FINISH) {
- LOGD("Event FINISH");
- isRunning = false;
- break;
- }
+ handleEvent();
}
}
LOGT("Exiting run");
}
+void Acceptor::handleConnection()
+{
+ std::shared_ptr tmpSocket = mSocket.accept();
+ mNewConnectionCallback(tmpSocket);
+}
+
+void Acceptor::handleEvent()
+{
+ if (mEventQueue.receive() == Event::FINISH) {
+ LOGD("Event FINISH");
+ mIsRunning = false;
+ }
+}
+
+FileDescriptor Acceptor::getEventFD()
+{
+ return mEventQueue.getFD();
+}
+
+FileDescriptor Acceptor::getConnectionFD()
+{
+ return mSocket.getFD();
+}
+
} // namespace ipc
} // namespace vasum
diff --git a/common/ipc/internals/acceptor.hpp b/common/ipc/internals/acceptor.hpp
index 702a161..f87a0bb 100644
--- a/common/ipc/internals/acceptor.hpp
+++ b/common/ipc/internals/acceptor.hpp
@@ -29,6 +29,7 @@
#include "ipc/internals/socket.hpp"
#include "ipc/internals/event-queue.hpp"
+#include "ipc/types.hpp"
#include
#include
@@ -67,11 +68,35 @@ public:
*/
void stop();
+ /**
+ * Handle one incoming connection.
+ * Used with external polling
+ */
+ void handleConnection();
+
+ /**
+ * Handle one event from the internal event's queue
+ * Used with external polling
+ */
+ void handleEvent();
+
+ /**
+ * @return file descriptor of internal event's queue
+ */
+ FileDescriptor getEventFD();
+
+ /**
+ * @return file descriptor for the connection socket
+ */
+ FileDescriptor getConnectionFD();
+
private:
enum class Event : int {
FINISH // Shutdown request
};
+ bool mIsRunning;
+
NewConnectionCallback mNewConnectionCallback;
Socket mSocket;
diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp
index be1060d..72a1788 100644
--- a/common/ipc/internals/processor.cpp
+++ b/common/ipc/internals/processor.cpp
@@ -112,6 +112,11 @@ void Processor::setRemovedPeerCallback(const PeerCallback& removedPeerCallback)
mRemovedPeerCallback = removedPeerCallback;
}
+FileDescriptor Processor::getEventFD()
+{
+ return mEventQueue.getFD();
+}
+
void Processor::removeMethod(const MethodID methodID)
{
LOGT("Removing method " << methodID);
@@ -128,9 +133,9 @@ FileDescriptor Processor::addPeer(const std::shared_ptr& socketPtr)
peerFD = socketPtr->getFD();
SocketInfo socketInfo(peerFD, std::move(socketPtr));
mNewSockets.push(std::move(socketInfo));
+ mEventQueue.send(Event::ADD_PEER);
}
LOGI("New peer added. Id: " << peerFD);
- mEventQueue.send(Event::ADD_PEER);
return peerFD;
}
@@ -143,9 +148,9 @@ void Processor::removePeer(const FileDescriptor peerFD)
Lock lock(mSocketsMutex);
RemovePeerRequest request(peerFD, conditionPtr);
mPeersToDelete.push(std::move(request));
+ mEventQueue.send(Event::REMOVE_PEER);
}
- mEventQueue.send(Event::REMOVE_PEER);
auto isPeerDeleted = [&peerFD, this]()->bool {
Lock lock(mSocketsMutex);
@@ -204,6 +209,10 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, Status status)
void Processor::resetPolling()
{
+ if (!isStarted()) {
+ return;
+ }
+
LOGI("Resetting polling");
// Setup polling on eventfd and sockets
Lock lock(mSocketsMutex);
@@ -251,20 +260,22 @@ void Processor::run()
}
// Check for incoming events
- if (handleEvent()) {
- // mFDs changed
- continue;
+ if (mFDs[0].revents & POLLIN) {
+ mFDs[0].revents &= ~(POLLIN);
+ if (handleEvent()) {
+ // mFDs changed
+ continue;
+ }
}
+
}
cleanCommunication();
}
-
bool Processor::handleLostConnections()
{
std::vector peersToRemove;
-
{
Lock lock(mSocketsMutex);
for (unsigned int i = 1; i < mFDs.size(); ++i) {
@@ -283,39 +294,61 @@ bool Processor::handleLostConnections()
return !peersToRemove.empty();
}
+bool Processor::handleLostConnection(const FileDescriptor peerFD)
+{
+ removePeerInternal(peerFD, Status::PEER_DISCONNECTED);
+ return true;
+}
+
bool Processor::handleInputs()
{
- std::vector> socketsWithInput;
+ std::vector peersWithInput;
{
Lock lock(mSocketsMutex);
for (unsigned int i = 1; i < mFDs.size(); ++i) {
if (mFDs[i].revents & POLLIN) {
mFDs[i].revents &= ~(POLLIN);
- socketsWithInput.push_back(mSockets[mFDs[i].fd]);
+ peersWithInput.push_back(mFDs[i].fd);
}
}
}
bool pollChanged = false;
// Handle input outside the critical section
- for (const auto& socketPtr : socketsWithInput) {
- pollChanged = pollChanged || handleInput(*socketPtr);
+ for (const FileDescriptor peerFD : peersWithInput) {
+ pollChanged = pollChanged || handleInput(peerFD);
}
return pollChanged;
}
-bool Processor::handleInput(const Socket& socket)
+bool Processor::handleInput(const FileDescriptor peerFD)
{
LOGT("Handle incoming data");
+
+ std::shared_ptr socketPtr;
+ try {
+ socketPtr = mSockets.at(peerFD);
+ } catch (const std::out_of_range&) {
+ LOGE("No such peer: " << peerFD);
+ return false;
+ }
+
MethodID methodID;
MessageID messageID;
{
- Socket::Guard guard = socket.getGuard();
- socket.read(&methodID, sizeof(methodID));
- socket.read(&messageID, sizeof(messageID));
+ Socket::Guard guard = socketPtr->getGuard();
+ try {
+ socketPtr->read(&methodID, sizeof(methodID));
+ socketPtr->read(&messageID, sizeof(messageID));
+
+ } catch (const IPCException& e) {
+ LOGE("Error during reading the socket");
+ removePeerInternal(socketPtr->getFD(), Status::NAUGHTY_PEER);
+ return true;
+ }
if (methodID == RETURN_METHOD_ID) {
- return onReturnValue(socket, messageID);
+ return onReturnValue(*socketPtr, messageID);
} else {
Lock lock(mCallsMutex);
@@ -323,19 +356,19 @@ bool Processor::handleInput(const Socket& socket)
// Method
std::shared_ptr methodCallbacks = mMethodsCallbacks.at(methodID);
lock.unlock();
- return onRemoteCall(socket, methodID, messageID, methodCallbacks);
+ return onRemoteCall(*socketPtr, methodID, messageID, methodCallbacks);
} else if (mSignalsCallbacks.count(methodID)) {
// Signal
std::shared_ptr signalCallbacks = mSignalsCallbacks.at(methodID);
lock.unlock();
- return onRemoteSignal(socket, methodID, messageID, signalCallbacks);
+ return onRemoteSignal(*socketPtr, methodID, messageID, signalCallbacks);
} else {
// Nothing
lock.unlock();
LOGW("No method or signal callback for methodID: " << methodID);
- removePeerInternal(socket.getFD(), Status::NAUGHTY_PEER);
+ removePeerInternal(socketPtr->getFD(), Status::NAUGHTY_PEER);
return true;
}
}
@@ -461,13 +494,6 @@ bool Processor::onRemoteCall(const Socket& socket,
bool Processor::handleEvent()
{
- if (!(mFDs[0].revents & POLLIN)) {
- // No event to serve
- return false;
- }
-
- mFDs[0].revents &= ~(POLLIN);
-
switch (mEventQueue.receive()) {
case Event::FINISH: {
LOGD("Event FINISH");
@@ -518,11 +544,11 @@ bool Processor::onNewPeer()
// Broadcast the new signal to peers
LOGW("Sending handled signals");
- std::list peersIDs;
+ std::list peersFDs;
{
Lock lock(mSocketsMutex);
for (const auto kv : mSockets) {
- peersIDs.push_back(kv.first);
+ peersFDs.push_back(kv.first);
}
}
@@ -535,7 +561,7 @@ bool Processor::onNewPeer()
}
auto data = std::make_shared(ids);
- for (const FileDescriptor peerFD : peersIDs) {
+ for (const FileDescriptor peerFD : peersFDs) {
callInternal(REGISTER_SIGNAL_METHOD_ID,
peerFD,
data,
diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp
index 6ce2688..d33d12b 100644
--- a/common/ipc/internals/processor.hpp
+++ b/common/ipc/internals/processor.hpp
@@ -75,6 +75,7 @@ const unsigned int DEFAULT_METHOD_TIMEOUT = 1000;
* - new way to generate UIDs
* - callbacks for serialization/parsing
* - store Sockets in a vector, maybe SocketStore?
+* - fix valgrind tests
*
*
*/
@@ -240,6 +241,35 @@ public:
void signal(const MethodID methodID,
const std::shared_ptr& data);
+ /**
+ * Removes one peer.
+ * Handler used in external polling.
+ *
+ * @param peerFD file description identifying the peer
+ * @return should the polling structure be rebuild
+ */
+ bool handleLostConnection(const FileDescriptor peerFD);
+
+ /**
+ * Handles input from one peer.
+ * Handler used in external polling.
+ *
+ * @param peerFD file description identifying the peer
+ * @return should the polling structure be rebuild
+ */
+ bool handleInput(const FileDescriptor peerFD);
+
+ /**
+ * Handle one event from the internal event's queue
+ *
+ * @return should the polling structure be rebuild
+ */
+ bool handleEvent();
+
+ /**
+ * @return file descriptor for the internal event's queue
+ */
+ FileDescriptor getEventFD();
private:
typedef std::function& data)> SerializeCallback;
@@ -383,13 +413,12 @@ private:
static void discardResultHandler(Status, std::shared_ptr&) {}
void run();
- bool handleEvent();
bool onCall();
bool onNewPeer();
bool onRemovePeer();
bool handleLostConnections();
bool handleInputs();
- bool handleInput(const Socket& socket);
+
bool onReturnValue(const Socket& socket,
const MessageID messageID);
bool onRemoteCall(const Socket& socket,
@@ -494,26 +523,24 @@ void Processor::addSignalHandler(const MethodID methodID,
mSignalsCallbacks[methodID] = std::make_shared(std::move(signalCall));
}
- if (isStarted()) {
- // Broadcast the new signal to peers
- std::vector ids {methodID};
- auto data = std::make_shared(ids);
+ std::vector ids {methodID};
+ auto data = std::make_shared(ids);
- std::list peersIDs;
- {
- Lock lock(mSocketsMutex);
- for (const auto kv : mSockets) {
- peersIDs.push_back(kv.first);
- }
+ std::list peersFDs;
+ {
+ Lock lock(mSocketsMutex);
+ for (const auto kv : mSockets) {
+ peersFDs.push_back(kv.first);
}
+ }
- for (const FileDescriptor peerFD : peersIDs) {
- callSync(REGISTER_SIGNAL_METHOD_ID,
- peerFD,
- data,
- DEFAULT_METHOD_TIMEOUT);
- }
+ for (const FileDescriptor peerFD : peersFDs) {
+ callSync(REGISTER_SIGNAL_METHOD_ID,
+ peerFD,
+ data,
+ DEFAULT_METHOD_TIMEOUT);
}
+
}
template
@@ -535,11 +562,6 @@ MessageID Processor::callAsync(const MethodID methodID,
const std::shared_ptr& data,
const typename ResultHandler::type& process)
{
- if (!isStarted()) {
- LOGE("The Processor thread is not started. Can't send any data.");
- throw IPCException("The Processor thread is not started. Can't send any data.");
- }
-
return callInternal(methodID, peerFD, data, process);
}
@@ -600,18 +622,13 @@ template
void Processor::signal(const MethodID methodID,
const std::shared_ptr& data)
{
- if (!isStarted()) {
- LOGE("The Processor thread is not started. Can't send any data.");
- throw IPCException("The Processor thread is not started. Can't send any data.");
- }
-
- std::list peersIDs;
+ std::list peersFDs;
{
Lock lock(mSocketsMutex);
- peersIDs = mSignalsPeers[methodID];
+ peersFDs = mSignalsPeers[methodID];
}
- for (const FileDescriptor peerFD : peersIDs) {
+ for (const FileDescriptor peerFD : peersFDs) {
Lock lock(mCallsMutex);
mCalls.push(methodID, peerFD, data);
mEventQueue.send(Event::CALL);
diff --git a/common/ipc/internals/utils.cpp b/common/ipc/internals/utils.cpp
index 88f8fc0..bd98c1b 100644
--- a/common/ipc/internals/utils.cpp
+++ b/common/ipc/internals/utils.cpp
@@ -122,8 +122,8 @@ void write(int fd, const void* bufferPtr, const size_t size, int timeoutMS)
// Neglected errors
LOGD("Retrying write");
} else {
- LOGE("Error during reading: " + std::string(strerror(errno)));
- throw IPCException("Error during reading: " + std::string(strerror(errno)));
+ LOGE("Error during writing: " + std::string(strerror(errno)));
+ throw IPCException("Error during writing: " + std::string(strerror(errno)));
}
if (nTotal >= size) {
diff --git a/common/ipc/ipc-gsource.cpp b/common/ipc/ipc-gsource.cpp
new file mode 100644
index 0000000..f5cdbb5
--- /dev/null
+++ b/common/ipc/ipc-gsource.cpp
@@ -0,0 +1,174 @@
+/*
+* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Contact: Jan Olszak
+*
+* 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
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief Class for creating a dedicated GSource
+ */
+
+
+#include "config.hpp"
+
+#include "ipc/ipc-gsource.hpp"
+
+#if GLIB_CHECK_VERSION(2,36,0)
+
+#include "logger/logger.hpp"
+#include
+
+namespace vasum {
+namespace ipc {
+
+namespace {
+
+
+GIOCondition conditions = static_cast(G_IO_IN |
+ G_IO_ERR |
+ G_IO_HUP);
+}
+
+
+IPCGSource::IPCGSource(const std::vector fds,
+ const HandlerCallback& handlerCallback)
+ : mHandlerCallback(handlerCallback)
+{
+ LOGD("Constructing IPCGSource");
+ for (const FileDescriptor fd : fds) {
+ addFD(fd);
+ }
+}
+
+IPCGSource::~IPCGSource()
+{
+ LOGD("Destroying IPCGSource");
+ g_source_destroy(&mGSource);
+
+}
+
+IPCGSource* IPCGSource::create(const std::vector& fds,
+ const HandlerCallback& handlerCallback)
+{
+ LOGD("Creating IPCGSource");
+
+ static GSourceFuncs funcs = { &IPCGSource::prepare,
+ &IPCGSource::check,
+ &IPCGSource::dispatch,
+ &IPCGSource::finalize,
+ nullptr,
+ nullptr
+ };
+
+ // New GSource
+ GSource* gSource = g_source_new(&funcs, sizeof(IPCGSource));
+ g_source_set_priority(gSource, G_PRIORITY_HIGH);
+
+ // Fill additional data
+ IPCGSource* source = reinterpret_cast(gSource);
+ return new(source) IPCGSource(fds, handlerCallback);
+}
+
+
+void IPCGSource::addFD(const FileDescriptor fd)
+{
+ if (!&mGSource) {
+ // In case it's called as a callback but the IPCGSource is destroyed
+ return;
+ }
+
+ LOGD("Adding fd to glib");
+ gpointer tag = g_source_add_unix_fd(&mGSource,
+ fd,
+ conditions);
+ FDInfo fdInfo(tag, fd);
+ mFDInfos.push_back(std::move(fdInfo));
+}
+
+void IPCGSource::removeFD(const FileDescriptor fd)
+{
+ if (!&mGSource) {
+ // In case it's called as a callback but the IPCGSource is destroyed
+ return;
+ }
+
+ LOGD("Removing fd from glib");
+ auto it = std::find(mFDInfos.begin(), mFDInfos.end(), fd);
+ if (it == mFDInfos.end()) {
+ LOGE("No such fd");
+ return;
+ }
+ g_source_remove_unix_fd(&mGSource, it->tag);
+ mFDInfos.erase(it);
+}
+
+guint IPCGSource::attach(GMainContext* context)
+{
+ LOGD("Attaching to GMainContext");
+ return g_source_attach(&mGSource, context);
+}
+
+gboolean IPCGSource::prepare(GSource* gSource, gint* timeout)
+{
+ if (!gSource) {
+ return FALSE;
+ }
+
+ *timeout = -1;
+
+ // TODO: Implement hasEvents() method in Client and Service and use it here as a callback:
+ // return source->hasEvents();
+ return FALSE;
+}
+
+gboolean IPCGSource::check(GSource* gSource)
+{
+ if (!gSource) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean IPCGSource::dispatch(GSource* gSource,
+ GSourceFunc /*callback*/,
+ gpointer /*userData*/)
+{
+ IPCGSource* source = reinterpret_cast(gSource);
+
+ for (const FDInfo fdInfo : source->mFDInfos) {
+ GIOCondition cond = g_source_query_unix_fd(gSource, fdInfo.tag);
+ if (conditions & cond) {
+ source->mHandlerCallback(fdInfo.fd, cond);
+ }
+ }
+
+ return TRUE; // Don't remove the GSource from the GMainContext
+}
+
+void IPCGSource::finalize(GSource* gSource)
+{
+ if (gSource) {
+ IPCGSource* source = reinterpret_cast(gSource);
+ source->~IPCGSource();
+ }
+}
+
+} // namespace ipc
+} // namespace vasum
+
+#endif // GLIB_CHECK_VERSION
diff --git a/common/ipc/ipc-gsource.hpp b/common/ipc/ipc-gsource.hpp
new file mode 100644
index 0000000..96e0a1a
--- /dev/null
+++ b/common/ipc/ipc-gsource.hpp
@@ -0,0 +1,150 @@
+/*
+* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Contact: Jan Olszak
+*
+* 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
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief Class for creating a dedicated GSource
+ */
+
+#ifndef COMMON_IPC_IPC_GSOURCE_HPP
+#define COMMON_IPC_IPC_GSOURCE_HPP
+
+#include
+#if GLIB_CHECK_VERSION(2,36,0)
+
+#include "ipc/service.hpp"
+#include "ipc/types.hpp"
+#include "utils/callback-wrapper.hpp"
+#include
+
+
+namespace vasum {
+namespace ipc {
+
+/**
+ * Class for connecting to the glib's loop.
+ * Creates a dedicated GSource.
+ *
+ * It's supposed to be constructed ONLY with the static create method
+ * and destructed in a glib callback.
+ */
+struct IPCGSource {
+public:
+ typedef std::function HandlerCallback;
+
+ IPCGSource() = delete;
+ IPCGSource(const IPCGSource&) = delete;
+ IPCGSource& operator=(const IPCGSource&) = delete;
+
+ /**
+ * New file descriptor to listen on.
+ *
+ * @param peerFD file descriptor
+ */
+ void addFD(const FileDescriptor peerFD);
+
+ /**
+ * Removes the file descriptor from the GSource
+ *
+ * @param peerFD file descriptor
+ */
+ void removeFD(const FileDescriptor peerFD);
+
+ /**
+ * Attach to the glib's GMainContext
+ *
+ * @param context where to connect
+ * @return result of the g_source_attach call
+ */
+ guint attach(GMainContext* context = nullptr);
+
+ /**
+ * Creates the IPCGSource class in the memory allocated by glib.
+ * Calls IPCGSource's constructor
+ *
+ * @param fds initial set of file descriptors
+ * @param handlerCallback event handling callback
+ *
+ * @return pointer to the IPCGSource
+ */
+ static IPCGSource* create(const std::vector& fds,
+ const HandlerCallback& handlerCallback);
+
+private:
+
+ /**
+ * GSourceFuncs' callback
+ */
+ static gboolean prepare(GSource* source, gint* timeout);
+
+ /**
+ * GSourceFuncs' callback
+ */
+ static gboolean check(GSource* source);
+
+ /**
+ * GSourceFuncs' callback
+ */
+ static gboolean dispatch(GSource* source,
+ GSourceFunc callbacks,
+ gpointer userData);
+
+ /**
+ * GSourceFuncs' callback
+ */
+ static void finalize(GSource* source);
+
+
+
+ // Called only from IPCGSource::create
+ IPCGSource(const std::vector fds,
+ const HandlerCallback& handlerCallback);
+
+ // Called only from IPCGSource::finalize
+ ~IPCGSource();
+
+ struct FDInfo {
+ FDInfo(gpointer tag, FileDescriptor fd)
+ : tag(tag), fd(fd) {}
+
+ bool operator==(const gpointer t)
+ {
+ return t == tag;
+ }
+
+ bool operator==(const FileDescriptor f)
+ {
+ return f == fd;
+ }
+
+ gpointer tag;
+ FileDescriptor fd;
+ };
+
+ GSource mGSource;
+ HandlerCallback mHandlerCallback;
+ std::vector mFDInfos;
+};
+
+} // namespace ipc
+} // namespace vasum
+
+#endif // GLIB_CHECK_VERSION
+
+#endif // COMMON_IPC_IPC_GSOURCE_HPP
diff --git a/common/ipc/service.cpp b/common/ipc/service.cpp
index 5ee5fbd..be95cee 100644
--- a/common/ipc/service.cpp
+++ b/common/ipc/service.cpp
@@ -79,6 +79,41 @@ void Service::stop()
LOGD("Stopped");
}
+std::vector Service::getFDs()
+{
+ std::vector fds;
+ fds.push_back(mAcceptor.getEventFD());
+ fds.push_back(mAcceptor.getConnectionFD());
+ fds.push_back(mProcessor.getEventFD());
+
+ return fds;
+}
+
+void Service::handle(const FileDescriptor fd, const short pollEvent)
+{
+ if (fd == mProcessor.getEventFD() && pollEvent & POLLIN) {
+ mProcessor.handleEvent();
+ return;
+
+ } else if (fd == mAcceptor.getConnectionFD() && pollEvent & POLLIN) {
+ mAcceptor.handleConnection();
+ return;
+
+ } else if (fd == mAcceptor.getEventFD() && pollEvent & POLLIN) {
+ mAcceptor.handleEvent();
+ return;
+
+ } else if (pollEvent & POLLIN) {
+ mProcessor.handleInput(fd);
+ return;
+
+ } else if (pollEvent & POLLHUP) {
+ mProcessor.handleLostConnection(fd);
+ return;
+ }
+}
+
+
void Service::setNewPeerCallback(const PeerCallback& newPeerCallback)
{
mProcessor.setNewPeerCallback(newPeerCallback);
diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp
index 1f9aee3..ed83606 100644
--- a/common/ipc/service.hpp
+++ b/common/ipc/service.hpp
@@ -75,6 +75,23 @@ public:
void stop();
/**
+ * Used with an external polling loop
+ *
+ * @return vector of internal file descriptors
+ */
+ std::vector getFDs();
+
+ /**
+ * Used with an external polling loop.
+ * Handles one event from the file descriptor.
+ *
+ * @param fd file descriptor
+ * @param pollEvent event on the fd. Defined in poll.h
+ *
+ */
+ void handle(const FileDescriptor fd, const short pollEvent);
+
+ /**
* Set the callback called for each new connection to a peer
*
* @param newPeerCallback the callback
diff --git a/common/ipc/types.cpp b/common/ipc/types.cpp
index 18c769d..fa57648 100644
--- a/common/ipc/types.cpp
+++ b/common/ipc/types.cpp
@@ -22,6 +22,8 @@
* @brief Types definitions and helper functions
*/
+#include "config.hpp"
+
#include "ipc/types.hpp"
#include "logger/logger.hpp"
diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp
index c671db6..9ce131d 100644
--- a/tests/unit_tests/ipc/ut-ipc.cpp
+++ b/tests/unit_tests/ipc/ut-ipc.cpp
@@ -33,7 +33,9 @@
#include "ipc/service.hpp"
#include "ipc/client.hpp"
+#include "ipc/ipc-gsource.hpp"
#include "ipc/types.hpp"
+#include "utils/glib-loop.hpp"
#include "config/fields.hpp"
#include "logger/logger.hpp"
@@ -47,6 +49,8 @@
using namespace vasum;
using namespace vasum::ipc;
+using namespace vasum::utils;
+using namespace std::placeholders;
namespace fs = boost::filesystem;
namespace {
@@ -132,30 +136,48 @@ std::shared_ptr longEchoCallback(const FileDescriptor, std::shared_ptr
return data;
}
-FileDescriptor connect(Service& s, Client& c)
+FileDescriptor connect(Service& s, Client& c, bool serviceUsesGlib = false)
{
// Connects the Client to the Service and returns Clients FileDescriptor
-
std::mutex mutex;
std::condition_variable cv;
FileDescriptor peerFD = 0;
- auto newPeerCallback = [&cv, &peerFD, &mutex](const FileDescriptor newFileDescriptor) {
+ auto newPeerCallback = [&cv, &peerFD, &mutex](const FileDescriptor newFD) {
std::unique_lock lock(mutex);
- peerFD = newFileDescriptor;
- cv.notify_one();
+ peerFD = newFD;
+ cv.notify_all();
};
- s.setNewPeerCallback(newPeerCallback);
- if (!s.isStarted()) {
- s.start();
+ if (!serviceUsesGlib) {
+ s.setNewPeerCallback(newPeerCallback);
+
+ if (!s.isStarted()) {
+ s.start();
+ }
+ } else {
+#if GLIB_CHECK_VERSION(2,36,0)
+
+ IPCGSource* serviceGSourcePtr = IPCGSource::create(s.getFDs(), std::bind(&Service::handle, &s, _1, _2));
+
+ auto agregateCallback = [&newPeerCallback, &serviceGSourcePtr](const FileDescriptor newFD) {
+ serviceGSourcePtr->addFD(newFD);
+ newPeerCallback(newFD);
+ };
+
+ s.setNewPeerCallback(agregateCallback);
+ s.setRemovedPeerCallback(std::bind(&IPCGSource::removeFD, serviceGSourcePtr, _1));
+
+ serviceGSourcePtr->attach();
+#endif // GLIB_CHECK_VERSION
+
}
c.start();
std::unique_lock lock(mutex);
- BOOST_CHECK(cv.wait_for(lock, std::chrono::milliseconds(1000), [&peerFD]() {
+ BOOST_CHECK(cv.wait_for(lock, std::chrono::milliseconds(2000), [&peerFD]() {
return peerFD != 0;
}));
@@ -165,7 +187,7 @@ FileDescriptor connect(Service& s, Client& c)
void testEcho(Client& c, const MethodID methodID)
{
std::shared_ptr sentData(new SendData(34));
- std::shared_ptr recvData = c.callSync(methodID, sentData);
+ std::shared_ptr recvData = c.callSync(methodID, sentData, 1000);
BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
}
@@ -554,6 +576,35 @@ BOOST_AUTO_TEST_CASE(AddSignalOffline)
}
+#if GLIB_CHECK_VERSION(2,36,0)
+
+BOOST_AUTO_TEST_CASE(ServiceGSource)
+{
+ ScopedGlibLoop loop;
+
+ std::atomic_bool isSignalCalled(false);
+ auto signalHandler = [&isSignalCalled](const FileDescriptor, std::shared_ptr&) {
+ isSignalCalled = true;
+ };
+
+ Service s(socketPath);
+ s.addMethodHandler(1, echoCallback);
+
+ Client c(socketPath);
+ s.addSignalHandler(2, signalHandler);
+ connect(s, c, true);
+
+ testEcho(c, 1);
+
+ auto data = std::make_shared(1);
+ c.signal(2, data);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100)); //TODO wait_for
+ BOOST_CHECK(isSignalCalled);
+}
+
+#endif // GLIB_CHECK_VERSION
+
// BOOST_AUTO_TEST_CASE(ConnectionLimitTest)
// {
// unsigned oldLimit = ipc::getMaxFDNumber();
--
2.7.4
From 637f643f63b8c7de143a2eec4891d7b78f396264 Mon Sep 17 00:00:00 2001
From: Lukasz Kostyra
Date: Mon, 15 Dec 2014 13:25:23 +0100
Subject: [PATCH 05/16] Add "enabled" file
[Feature] File indicating that zones are running in the system.
[Cause] Other external services (eg. security-manager) must know when
zones are active in the system.
[Solution] Provide "enabled" file, which will appear when zones are
launched. The file will appear when first zone will be created,
and file will disappear when last zone will be destroyed.
[Verification] Build, install, run tests.
Change-Id: I634e424e28c7d449276bbe1c2c80f3cb0e35bcb7
---
common/utils/fs.cpp | 13 +++++++++++++
common/utils/fs.hpp | 5 +++++
server/zones-manager.cpp | 15 +++++++++++++++
tests/unit_tests/utils/ut-fs.cpp | 7 +++++++
4 files changed, 40 insertions(+)
diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp
index 9254f0a..3330cbf 100644
--- a/common/utils/fs.cpp
+++ b/common/utils/fs.cpp
@@ -98,6 +98,19 @@ bool saveFileContent(const std::string& path, const std::string& content)
return true;
}
+bool removeFile(const std::string& path)
+{
+ LOGD(path << ": exists, removing.");
+ if (::remove(path.c_str())) {
+ if (errno != ENOENT) {
+ LOGE(path << ": failed to delete: " << ::strerror(errno));
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool isCharDevice(const std::string& path)
{
struct stat s;
diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp
index 91ea62a..35000c6 100644
--- a/common/utils/fs.hpp
+++ b/common/utils/fs.hpp
@@ -50,6 +50,11 @@ bool readFileContent(const std::string& path, std::string& content);
bool saveFileContent(const std::string& path, const std::string& content);
/**
+ * Remove file
+ */
+bool removeFile(const std::string& path);
+
+/**
* Checks if a char device exists
*/
bool isCharDevice(const std::string& path);
diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp
index 981556b..402fc7f 100644
--- a/server/zones-manager.cpp
+++ b/server/zones-manager.cpp
@@ -65,6 +65,7 @@ bool regexMatchVector(const std::string& str, const std::vector& v
const std::string HOST_ID = "host";
const std::string ZONE_TEMPLATE_CONFIG_PATH = "template.conf";
+const std::string ENABLED_FILE_NAME = "enabled";
const boost::regex ZONE_NAME_REGEX("~NAME~");
const boost::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~");
@@ -193,6 +194,14 @@ void ZonesManager::createZone(const std::string& zoneConfig)
this, id, _1));
mZones.insert(ZoneMap::value_type(id, std::move(c)));
+
+ // after zone is created successfully, put a file informing that zones are enabled
+ if (mZones.size() == 1) {
+ if (!utils::saveFileContent(
+ utils::createFilePath(mConfig.zonesPath, "/", ENABLED_FILE_NAME), "")) {
+ throw ZoneOperationException(ENABLED_FILE_NAME + ": cannot create.");
+ }
+ }
}
void ZonesManager::destroyZone(const std::string& zoneId)
@@ -207,6 +216,12 @@ void ZonesManager::destroyZone(const std::string& zoneId)
// TODO give back the focus
it->second->setDestroyOnExit();
mZones.erase(it);
+
+ if (mZones.size() == 0) {
+ if (!utils::removeFile(utils::createFilePath(mConfig.zonesPath, "/", ENABLED_FILE_NAME))) {
+ LOGE("Failed to remove enabled file.");
+ }
+ }
}
void ZonesManager::focus(const std::string& zoneId)
diff --git a/tests/unit_tests/utils/ut-fs.cpp b/tests/unit_tests/utils/ut-fs.cpp
index 5557e46..63b4f63 100644
--- a/tests/unit_tests/utils/ut-fs.cpp
+++ b/tests/unit_tests/utils/ut-fs.cpp
@@ -88,6 +88,13 @@ BOOST_AUTO_TEST_CASE(SaveFileContentTest)
boost::filesystem::remove(FILE_PATH_RANDOM, ec);
}
+BOOST_AUTO_TEST_CASE(RemoveFileTest)
+{
+ BOOST_REQUIRE(saveFileContent(FILE_PATH_RANDOM, FILE_CONTENT));
+ BOOST_REQUIRE(removeFile(FILE_PATH_RANDOM));
+ BOOST_REQUIRE(!boost::filesystem::exists(FILE_PATH_RANDOM));
+}
+
BOOST_AUTO_TEST_CASE(MountPointTest)
{
bool result;
--
2.7.4
From 8f92cd9ec0ab3c34ac8add4c9b6e8f2a31227cb5 Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Thu, 11 Dec 2014 17:54:13 +0100
Subject: [PATCH 06/16] Worker thread utility class
[Bug/Feature] A utility class that wraps a queue of tasks executed in a
dedicated thread.
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I32788fd6321c2877cf4dafe7213c1a140c1d3fd2
---
common/utils/counting-map.hpp | 88 ++++++++++++++
common/utils/worker.cpp | 186 +++++++++++++++++++++++++++++
common/utils/worker.hpp | 74 ++++++++++++
server/zone.cpp | 37 ++----
server/zone.hpp | 13 +-
server/zones-manager.cpp | 39 +++---
server/zones-manager.hpp | 2 +
tests/unit_tests/server/ut-zone.cpp | 9 +-
tests/unit_tests/utils/ut-counting-map.cpp | 81 +++++++++++++
tests/unit_tests/utils/ut-worker.cpp | 182 ++++++++++++++++++++++++++++
10 files changed, 656 insertions(+), 55 deletions(-)
create mode 100644 common/utils/counting-map.hpp
create mode 100644 common/utils/worker.cpp
create mode 100644 common/utils/worker.hpp
create mode 100644 tests/unit_tests/utils/ut-counting-map.cpp
create mode 100644 tests/unit_tests/utils/ut-worker.cpp
diff --git a/common/utils/counting-map.hpp b/common/utils/counting-map.hpp
new file mode 100644
index 0000000..da5f4c7
--- /dev/null
+++ b/common/utils/counting-map.hpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Counting map
+ */
+
+#ifndef COMMON_UTILS_COUNTING_MAP_HPP
+#define COMMON_UTILS_COUNTING_MAP_HPP
+
+#include
+
+namespace vasum {
+namespace utils {
+
+
+/**
+ * Structure used to count elements.
+ * It's like multiset + count but is more efficient.
+ */
+template
+class CountingMap {
+public:
+ size_t increment(const Key& key)
+ {
+ auto res = mMap.insert(typename Map::value_type(key, 1));
+ if (!res.second) {
+ ++res.first->second;
+ }
+ return res.first->second;
+ }
+
+ size_t decrement(const Key& key)
+ {
+ auto it = mMap.find(key);
+ if (it == mMap.end()) {
+ return 0;
+ }
+ if (--it->second == 0) {
+ mMap.erase(it);
+ return 0;
+ }
+ return it->second;
+ }
+
+ void clear()
+ {
+ mMap.clear();
+ }
+
+ size_t get(const Key& key) const
+ {
+ auto it = mMap.find(key);
+ return it == mMap.end() ? 0 : it->second;
+ }
+
+ bool empty() const
+ {
+ return mMap.empty();
+ }
+private:
+ typedef std::unordered_map Map;
+ Map mMap;
+};
+
+
+} // namespace utils
+} // namespace vasum
+
+
+#endif // COMMON_UTILS_COUNTING_MAP_HPP
diff --git a/common/utils/worker.cpp b/common/utils/worker.cpp
new file mode 100644
index 0000000..2cb3284
--- /dev/null
+++ b/common/utils/worker.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief A worker thread that executes tasks
+ */
+
+#include "config.hpp"
+#include "utils/worker.hpp"
+#include "utils/counting-map.hpp"
+#include "logger/logger.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+namespace vasum {
+namespace utils {
+
+
+class Worker::WorkerQueue {
+public:
+ WorkerQueue()
+ : mLastGroupID(0), mEnding(false)
+ {
+ LOGT("Worker queue created");
+ }
+
+ ~WorkerQueue()
+ {
+ {
+ Lock lock(mMutex);
+ assert(mTaskQueue.empty());
+ assert(mGroupCounter.empty());
+ mEnding = true;
+ }
+ if (mThread.joinable()) {
+ mAddedCondition.notify_all();
+ mThread.join();
+ }
+ LOGT("Worker queue destroyed");
+ }
+
+ GroupID getNextGroupID()
+ {
+ return ++mLastGroupID;
+ }
+
+ void addTask(const Worker::Task& task, GroupID groupID)
+ {
+ assert(task);
+
+ Lock lock(mMutex);
+ LOGT("Adding task to subgroup " << groupID);
+ mTaskQueue.push_back(TaskInfo{task, groupID});
+ mGroupCounter.increment(groupID);
+ mAddedCondition.notify_one();
+ if (!mThread.joinable()) {
+ mThread = std::thread(&WorkerQueue::workerProc, this);
+ }
+ }
+
+ void waitForGroupEmpty(GroupID groupID)
+ {
+ Lock lock(mMutex);
+ size_t count = mGroupCounter.get(groupID);
+ if (count > 0) {
+ LOGD("Waiting for " << count << " task in group " << groupID);
+ }
+ mEmptyGroupCondition.wait(lock, [this, groupID] {
+ return mGroupCounter.get(groupID) == 0;
+ });
+ }
+private:
+ typedef std::unique_lock Lock;
+
+ struct TaskInfo {
+ Worker::Task task;
+ GroupID groupID;
+ };
+
+ std::atomic mLastGroupID;
+ std::condition_variable mAddedCondition;
+ std::condition_variable mEmptyGroupCondition;
+ std::thread mThread;
+
+ std::mutex mMutex; // protects below member variables:
+ bool mEnding;
+ std::deque mTaskQueue;
+ CountingMap mGroupCounter;
+
+ void workerProc()
+ {
+ LOGT("Worker thread started");
+ for (;;) {
+ // wait for a task
+ GroupID groupID;
+ {
+ Lock lock(mMutex);
+ mAddedCondition.wait(lock, [this] {
+ return !mTaskQueue.empty() || mEnding;
+ });
+ if (mTaskQueue.empty()) {
+ break;
+ }
+ TaskInfo taskInfo = std::move(mTaskQueue.front());
+ mTaskQueue.pop_front();
+
+ lock.unlock();
+
+ // execute
+ execute(taskInfo);
+ groupID = taskInfo.groupID;
+ }
+ // remove from queue
+ {
+ Lock lock(mMutex);
+ if (mGroupCounter.decrement(groupID) == 0) {
+ mEmptyGroupCondition.notify_all();
+ }
+ }
+ }
+ LOGT("Worker thread exited");
+ }
+
+ void execute(const TaskInfo& taskInfo)
+ {
+ try {
+ LOGT("Executing task from subgroup " << taskInfo.groupID);
+ taskInfo.task();
+ } catch (const std::exception& e) {
+ LOGE("Unexpected exception while executing task: " << e.what());
+ }
+ }
+};
+
+
+Worker::Pointer Worker::create()
+{
+ return Pointer(new Worker(std::make_shared()));
+}
+
+Worker::Worker(const std::shared_ptr& workerQueue)
+ : mWorkerQueue(workerQueue), mGroupID(workerQueue->getNextGroupID())
+{
+}
+
+Worker::~Worker()
+{
+ mWorkerQueue->waitForGroupEmpty(mGroupID);
+}
+
+Worker::Pointer Worker::createSubWorker()
+{
+ return Pointer(new Worker(mWorkerQueue));
+}
+
+void Worker::addTask(const Task& task)
+{
+ mWorkerQueue->addTask(task, mGroupID);
+}
+
+
+} // namespace utils
+} // namespace vasum
diff --git a/common/utils/worker.hpp b/common/utils/worker.hpp
new file mode 100644
index 0000000..0d951fb
--- /dev/null
+++ b/common/utils/worker.hpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief A worker thread that executes tasks
+ */
+
+#ifndef COMMON_UTILS_WORKER_HPP
+#define COMMON_UTILS_WORKER_HPP
+
+#include
+#include
+
+namespace vasum {
+namespace utils {
+
+/**
+ * A queue with tasks executed in a dedicated thread.
+ * Current implementation creates a thread on the first use.
+ */
+class Worker {
+public:
+ typedef std::shared_ptr Pointer;
+ typedef std::function Task;
+
+ ~Worker();
+
+ /**
+ * Creates a worker with its own thread
+ */
+ static Pointer create();
+
+ /**
+ * Creates a worker that share a thread with its parent
+ */
+ Pointer createSubWorker();
+
+ /**
+ * Adds a task to the queue.
+ */
+ void addTask(const Task& task);
+
+private:
+ typedef unsigned int GroupID;
+ class WorkerQueue;
+
+ const std::shared_ptr mWorkerQueue;
+ const GroupID mGroupID;
+
+ Worker(const std::shared_ptr& workerQueue);
+};
+
+} // namespace utils
+} // namespace vasum
+
+
+#endif // COMMON_UTILS_WORKER_HPP
diff --git a/server/zone.cpp b/server/zone.cpp
index 2e4573c..5f6dce0 100644
--- a/server/zone.cpp
+++ b/server/zone.cpp
@@ -65,10 +65,12 @@ void declareUnit(const std::string& file, ZoneProvisioning::Unit&& unit)
} // namespace
-Zone::Zone(const std::string& zonesPath,
- const std::string& zoneConfigPath,
- const std::string& lxcTemplatePrefix,
- const std::string& baseRunMountPointPath)
+Zone::Zone(const utils::Worker::Pointer& worker,
+ const std::string& zonesPath,
+ const std::string& zoneConfigPath,
+ const std::string& lxcTemplatePrefix,
+ const std::string& baseRunMountPointPath)
+ : mWorker(worker)
{
config::loadFromFile(zoneConfigPath, mConfig);
@@ -92,19 +94,9 @@ Zone::~Zone()
{
// Make sure all OnNameLostCallbacks get finished and no new will
// get called before proceeding further. This guarantees no race
- // condition on the mReconnectThread.
- {
- Lock lock(mReconnectMutex);
- disconnect();
- }
-
- if (mReconnectThread.joinable()) {
- mReconnectThread.join();
- }
-
- if (mStartThread.joinable()) {
- mStartThread.join();
- }
+ // condition on the reconnect thread.
+ Lock lock(mReconnectMutex);
+ disconnect();
}
const std::vector& Zone::getPermittedToSend() const
@@ -146,10 +138,6 @@ void Zone::start()
void Zone::startAsync(const StartAsyncResultCallback& callback)
{
- if (mStartThread.joinable()) {
- mStartThread.join();
- }
-
auto startWrapper = [this, callback]() {
bool succeeded = false;
@@ -165,7 +153,7 @@ void Zone::startAsync(const StartAsyncResultCallback& callback)
}
};
- mStartThread = std::thread(startWrapper);
+ mWorker->addTask(startWrapper);
}
void Zone::stop()
@@ -300,10 +288,7 @@ void Zone::onNameLostCallback()
{
LOGI(getId() << ": A connection to the DBUS server has been lost, reconnecting...");
- if (mReconnectThread.joinable()) {
- mReconnectThread.join();
- }
- mReconnectThread = std::thread(std::bind(&Zone::reconnectHandler, this));
+ mWorker->addTask(std::bind(&Zone::reconnectHandler, this));
}
void Zone::reconnectHandler()
diff --git a/server/zone.hpp b/server/zone.hpp
index 5ee95af..1fdc588 100644
--- a/server/zone.hpp
+++ b/server/zone.hpp
@@ -30,6 +30,7 @@
#include "zone-admin.hpp"
#include "zone-connection.hpp"
#include "zone-connection-transport.hpp"
+#include "utils/worker.hpp"
#include
#include
@@ -50,10 +51,11 @@ public:
* @param lxcTemplatePrefix directory where templates are stored
* @param baseRunMountPointPath base directory for run mount point
*/
- Zone(const std::string& zonesPath,
- const std::string& zoneConfigPath,
- const std::string& lxcTemplatePrefix,
- const std::string& baseRunMountPointPath);
+ Zone(const utils::Worker::Pointer& worker,
+ const std::string& zonesPath,
+ const std::string& zoneConfigPath,
+ const std::string& lxcTemplatePrefix,
+ const std::string& baseRunMountPointPath);
Zone(Zone&&) = default;
virtual ~Zone();
@@ -253,14 +255,13 @@ public:
const std::string& target);
private:
+ utils::Worker::Pointer mWorker;
ZoneConfig mConfig;
std::vector mPermittedToSend;
std::vector mPermittedToRecv;
std::unique_ptr mConnectionTransport;
std::unique_ptr mAdmin;
std::unique_ptr mConnection;
- std::thread mReconnectThread;
- std::thread mStartThread;
mutable std::recursive_mutex mReconnectMutex;
NotifyActiveZoneCallback mNotifyCallback;
DisplayOffCallback mDisplayOffCallback;
diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp
index 402fc7f..2ce03d7 100644
--- a/server/zones-manager.cpp
+++ b/server/zones-manager.cpp
@@ -74,7 +74,8 @@ const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100;
} // namespace
-ZonesManager::ZonesManager(const std::string& managerConfigPath): mDetachOnExit(false)
+ZonesManager::ZonesManager(const std::string& managerConfigPath)
+ : mWorker(utils::Worker::create()), mDetachOnExit(false)
{
LOGD("Instantiating ZonesManager object...");
@@ -168,32 +169,33 @@ void ZonesManager::createZone(const std::string& zoneConfig)
std::string zoneConfigPath = utils::getAbsolutePath(zoneConfig, baseConfigPath);
LOGT("Creating Zone " << zoneConfigPath);
- std::unique_ptr c(new Zone(mConfig.zonesPath,
- zoneConfigPath,
- mConfig.lxcTemplatePrefix,
- mConfig.runMountPointPrefix));
- const std::string id = c->getId();
+ std::unique_ptr zone(new Zone(mWorker->createSubWorker(),
+ mConfig.zonesPath,
+ zoneConfigPath,
+ mConfig.lxcTemplatePrefix,
+ mConfig.runMountPointPrefix));
+ const std::string id = zone->getId();
if (id == HOST_ID) {
throw ZoneOperationException("Cannot use reserved zone ID");
}
using namespace std::placeholders;
- c->setNotifyActiveZoneCallback(bind(&ZonesManager::notifyActiveZoneHandler,
- this, id, _1, _2));
+ zone->setNotifyActiveZoneCallback(bind(&ZonesManager::notifyActiveZoneHandler,
+ this, id, _1, _2));
- c->setDisplayOffCallback(bind(&ZonesManager::displayOffHandler,
- this, id));
+ zone->setDisplayOffCallback(bind(&ZonesManager::displayOffHandler,
+ this, id));
- c->setFileMoveRequestCallback(bind(&ZonesManager::handleZoneMoveFileRequest,
- this, id, _1, _2, _3));
+ zone->setFileMoveRequestCallback(bind(&ZonesManager::handleZoneMoveFileRequest,
+ this, id, _1, _2, _3));
- c->setProxyCallCallback(bind(&ZonesManager::handleProxyCall,
- this, id, _1, _2, _3, _4, _5, _6, _7));
+ zone->setProxyCallCallback(bind(&ZonesManager::handleProxyCall,
+ this, id, _1, _2, _3, _4, _5, _6, _7));
- c->setDbusStateChangedCallback(bind(&ZonesManager::handleDbusStateChanged,
- this, id, _1));
+ zone->setDbusStateChangedCallback(bind(&ZonesManager::handleDbusStateChanged,
+ this, id, _1));
- mZones.insert(ZoneMap::value_type(id, std::move(c)));
+ mZones.insert(ZoneMap::value_type(id, std::move(zone)));
// after zone is created successfully, put a file informing that zones are enabled
if (mZones.size() == 1) {
@@ -836,8 +838,7 @@ void ZonesManager::handleDestroyZoneCall(const std::string& id,
result->setVoid();
};
- std::thread thread(destroyer);
- thread.detach(); //TODO fix it
+ mWorker->addTask(destroyer);
}
void ZonesManager::handleLockZoneCall(const std::string& id,
diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp
index 2fc0305..b58da86 100644
--- a/server/zones-manager.hpp
+++ b/server/zones-manager.hpp
@@ -31,6 +31,7 @@
#include "host-connection.hpp"
#include "input-monitor.hpp"
#include "proxy-call-policy.hpp"
+#include "utils/worker.hpp"
#include
#include
@@ -105,6 +106,7 @@ public:
void setZonesDetachOnExit();
private:
+ utils::Worker::Pointer mWorker;
ZonesManagerConfig mConfig;
std::string mConfigPath;
HostConnection mHostConnection;
diff --git a/tests/unit_tests/server/ut-zone.cpp b/tests/unit_tests/server/ut-zone.cpp
index 7d80d66..80e73da 100644
--- a/tests/unit_tests/server/ut-zone.cpp
+++ b/tests/unit_tests/server/ut-zone.cpp
@@ -63,10 +63,11 @@ struct Fixture {
std::unique_ptr create(const std::string& configPath)
{
- return std::unique_ptr(new Zone(ZONES_PATH,
- configPath,
- LXC_TEMPLATES_PATH,
- ""));
+ return std::unique_ptr(new Zone(utils::Worker::create(),
+ ZONES_PATH,
+ configPath,
+ LXC_TEMPLATES_PATH,
+ ""));
}
void ensureStarted()
diff --git a/tests/unit_tests/utils/ut-counting-map.cpp b/tests/unit_tests/utils/ut-counting-map.cpp
new file mode 100644
index 0000000..702470f
--- /dev/null
+++ b/tests/unit_tests/utils/ut-counting-map.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Unit tests of counting map
+ */
+
+#include "config.hpp"
+#include "ut.hpp"
+
+#include "utils/counting-map.hpp"
+
+BOOST_AUTO_TEST_SUITE(CountingMapSuite)
+
+using namespace vasum::utils;
+
+BOOST_AUTO_TEST_CASE(CountingTest)
+{
+ CountingMap map;
+
+ BOOST_CHECK(map.empty());
+ BOOST_CHECK_EQUAL(0, map.get("ala"));
+
+ BOOST_CHECK_EQUAL(1, map.increment("ala"));
+ BOOST_CHECK_EQUAL(1, map.increment("ma"));
+
+ BOOST_CHECK(!map.empty());
+ BOOST_CHECK_EQUAL(1, map.get("ala"));
+ BOOST_CHECK_EQUAL(1, map.get("ma"));
+ BOOST_CHECK_EQUAL(0, map.get("kota"));
+
+ BOOST_CHECK_EQUAL(2, map.increment("ala"));
+ BOOST_CHECK_EQUAL(2, map.increment("ma"));
+ BOOST_CHECK_EQUAL(3, map.increment("ma"));
+
+ BOOST_CHECK(!map.empty());
+ BOOST_CHECK_EQUAL(2, map.get("ala"));
+ BOOST_CHECK_EQUAL(3, map.get("ma"));
+ BOOST_CHECK_EQUAL(0, map.get("kota"));
+
+ BOOST_CHECK_EQUAL(1, map.decrement("ala"));
+ BOOST_CHECK_EQUAL(0, map.decrement("kota"));
+
+ BOOST_CHECK(!map.empty());
+ BOOST_CHECK_EQUAL(1, map.get("ala"));
+ BOOST_CHECK_EQUAL(3, map.get("ma"));
+ BOOST_CHECK_EQUAL(0, map.get("kota"));
+
+ BOOST_CHECK_EQUAL(0, map.decrement("ala"));
+
+ BOOST_CHECK(!map.empty());
+ BOOST_CHECK_EQUAL(0, map.get("ala"));
+ BOOST_CHECK_EQUAL(3, map.get("ma"));
+ BOOST_CHECK_EQUAL(0, map.get("kota"));
+
+ BOOST_CHECK_EQUAL(2, map.decrement("ma"));
+ BOOST_CHECK_EQUAL(1, map.decrement("ma"));
+ BOOST_CHECK_EQUAL(0, map.decrement("ma"));
+
+ BOOST_CHECK(map.empty());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit_tests/utils/ut-worker.cpp b/tests/unit_tests/utils/ut-worker.cpp
new file mode 100644
index 0000000..280889b
--- /dev/null
+++ b/tests/unit_tests/utils/ut-worker.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz
+ *
+ * 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
+ * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Unit tests of worker thread
+ */
+
+#include "config.hpp"
+#include "ut.hpp"
+
+#include "utils/worker.hpp"
+#include "utils/latch.hpp"
+
+#include
+#include
+#include
+
+BOOST_AUTO_TEST_SUITE(WorkerSuite)
+
+using namespace vasum::utils;
+
+const int unsigned TIMEOUT = 1000;
+
+BOOST_AUTO_TEST_CASE(NoTasksTest)
+{
+ Worker::Pointer worker = Worker::create();
+}
+
+BOOST_AUTO_TEST_CASE(NoTasks2Test)
+{
+ Worker::Pointer worker = Worker::create();
+ Worker::Pointer sub1 = worker->createSubWorker();
+ Worker::Pointer sub2 = worker->createSubWorker();
+ Worker::Pointer sub3 = sub1->createSubWorker();
+
+ sub1.reset();
+ worker.reset();
+}
+
+BOOST_AUTO_TEST_CASE(SimpleTest)
+{
+ Latch done;
+
+ Worker::Pointer worker = Worker::create();
+ worker->addTask([&] {
+ done.set();
+ });
+
+ BOOST_CHECK(done.wait(TIMEOUT));
+}
+
+BOOST_AUTO_TEST_CASE(QueueTest)
+{
+ std::mutex mutex;
+ std::string result;
+
+ Worker::Pointer worker = Worker::create();
+
+ for (int n=0; n<10; ++n) {
+ worker->addTask([&, n]{
+ std::lock_guard lock(mutex);
+ result += std::to_string(n);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ });
+ }
+
+ worker.reset();
+
+ std::lock_guard lock(mutex);
+ BOOST_CHECK_EQUAL("0123456789", result);
+}
+
+BOOST_AUTO_TEST_CASE(ThreadResumeTest)
+{
+ Latch done;
+
+ const auto task = [&] {
+ done.set();
+ };
+
+ Worker::Pointer worker = Worker::create();
+
+ worker->addTask(task);
+
+ BOOST_CHECK(done.wait(TIMEOUT));
+
+ // make sure worker thread is in waiting state
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ worker->addTask(task);
+
+ worker.reset();
+
+ BOOST_CHECK(done.wait(TIMEOUT));
+}
+
+BOOST_AUTO_TEST_CASE(SubWorkerTest)
+{
+ std::mutex mutex;
+ std::string result;
+
+ Worker::Pointer worker = Worker::create();
+ Worker::Pointer sub1 = worker->createSubWorker();
+ Worker::Pointer sub2 = worker->createSubWorker();
+
+ auto addTask = [&](Worker::Pointer w, const std::string& id) {
+ w->addTask([&, id]{
+ std::lock_guard lock(mutex);
+ result += id;
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ });
+ };
+
+ for (int n=0; n<4; ++n) {
+ addTask(worker, "_w" + std::to_string(n));
+ addTask(sub1, "_a" + std::to_string(n));
+ }
+
+ worker.reset();
+ sub1.reset();
+
+ {
+ std::lock_guard lock(mutex);
+ BOOST_CHECK_EQUAL("_w0_a0_w1_a1_w2_a2_w3_a3", result);
+ result.clear();
+ }
+
+ addTask(sub2, "_b0");
+ addTask(sub2, "_b1");
+
+ sub2.reset();
+
+ {
+ std::lock_guard lock(mutex);
+ BOOST_CHECK_EQUAL("_b0_b1", result);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(NoCopyTest)
+{
+ typedef std::atomic_int Counter;
+
+ struct Task {
+ Counter& count;
+
+ Task(Counter& c) : count(c) {};
+ Task(const Task& t) : count(t.count) {++count;}
+ Task(Task&& r) : count(r.count) {}
+ Task& operator=(const Task&) = delete;
+ Task& operator=(Task&&) = delete;
+ void operator() () {}
+
+ };
+
+ Counter copyCount(0);
+
+ Worker::Pointer worker = Worker::create();
+ worker->addTask(Task(copyCount));
+ worker.reset();
+
+ BOOST_CHECK_EQUAL(1, copyCount); // one copy for creating std::function
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--
2.7.4
From 6de4eeceb5f669eb2fe71cf0a3d5d755e2663f8d Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Mon, 15 Dec 2014 12:36:25 +0100
Subject: [PATCH 07/16] Adding support for --vt option in lxc-templates
[Bug/Feature] N/A
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I11049b06922f763e168449d43cf6dd9527ea9324
Signed-off-by: Dariusz Michaluk
---
server/configs/lxc-templates/template.sh | 3 ++-
server/zone-admin.cpp | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/server/configs/lxc-templates/template.sh b/server/configs/lxc-templates/template.sh
index c73bd01..e7d5533 100755
--- a/server/configs/lxc-templates/template.sh
+++ b/server/configs/lxc-templates/template.sh
@@ -2,7 +2,7 @@
echo LXC template, args: $@
-options=$(getopt -o p:n: -l rootfs:,path:,name:,ipv4:,ipv4-gateway: -- "$@")
+options=$(getopt -o p:n: -l path:,rootfs:,name:,vt:,ipv4:,ipv4-gateway: -- "$@")
if [ $? -ne 0 ]; then
exit 1
fi
@@ -14,6 +14,7 @@ do
-p|--path) path=$2; shift 2;;
--rootfs) rootfs=$2; shift 2;;
-n|--name) name=$2; shift 2;;
+ --vt) vt=$2; shift 2;;
--ipv4) ipv4=$2; shift 2;;
--ipv4-gateway) ipv4_gateway=$2; shift 2;;
--) shift 1; break ;;
diff --git a/server/zone-admin.cpp b/server/zone-admin.cpp
index 42c71ea..46c4974 100644
--- a/server/zone-admin.cpp
+++ b/server/zone-admin.cpp
@@ -71,6 +71,11 @@ ZoneAdmin::ZoneAdmin(const std::string& zonesPath,
args.add("--ipv4");
args.add(config.ipv4.c_str());
}
+ const std::string vt = std::to_string(config.vt);
+ if (config.vt > 0) {
+ args.add("--vt");
+ args.add(vt.c_str());
+ }
if (!mZone.create(lxcTemplate, args.c_array())) {
throw ZoneOperationException("Could not create zone");
}
--
2.7.4
From 3bf358a390639906a64f6d9c1487c86be2962ba2 Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Mon, 15 Dec 2014 13:13:52 +0100
Subject: [PATCH 08/16] Change zonesPath and ExecStart command in service
[Bug/Feature] N/A
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: Ie51e3bd436f039f926c93b92ea5343e27e7314c0
Signed-off-by: Dariusz Michaluk
---
CMakeLists.txt | 4 ++++
packaging/vasum.spec | 3 +++
server/configs/CMakeLists.txt | 5 ++++-
server/configs/{daemon.conf => daemon.conf.in} | 4 ++--
server/configs/systemd/vasum.service.in | 2 +-
5 files changed, 14 insertions(+), 4 deletions(-)
rename server/configs/{daemon.conf => daemon.conf.in} (84%)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cd999d7..a12367f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -152,6 +152,10 @@ IF(NOT DEFINED SYSTEMD_UNIT_DIR)
SET(SYSTEMD_UNIT_DIR "${LIB_INSTALL_DIR}/systemd/system")
ENDIF(NOT DEFINED SYSTEMD_UNIT_DIR)
+IF(NOT DEFINED DATA_DIR)
+ SET(DATA_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}")
+ENDIF(NOT DEFINED DATA_DIR)
+
SET(VSM_CONFIG_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/vasum)
SET(VSM_DATA_INSTALL_DIR ${SHARE_INSTALL_PREFIX}/vasum)
diff --git a/packaging/vasum.spec b/packaging/vasum.spec
index 78db5de..887409e 100644
--- a/packaging/vasum.spec
+++ b/packaging/vasum.spec
@@ -51,6 +51,7 @@ between them. A process from inside a zone can request a switch of context
%{_unitdir}/vasum.service
%{_unitdir}/multi-user.target.wants/vasum.service
/etc/dbus-1/system.d/org.tizen.vasum.host.conf
+%dir %{_datadir}/.zones
%prep
%setup -q
@@ -67,6 +68,7 @@ between them. A process from inside a zone can request a switch of context
-DCMAKE_BUILD_TYPE=%{build_type} \
-DSCRIPT_INSTALL_DIR=%{script_dir} \
-DSYSTEMD_UNIT_DIR=%{_unitdir} \
+ -DDATA_DIR=%{_datadir} \
-DPYTHON_SITELIB=%{python_sitelib} \
-DVASUM_USER=%{vsm_user} \
-DINPUT_EVENT_GROUP=%{input_event_group} \
@@ -78,6 +80,7 @@ make -k %{?jobs:-j%jobs}
%make_install
mkdir -p %{buildroot}/%{_unitdir}/multi-user.target.wants
ln -s ../vasum.service %{buildroot}/%{_unitdir}/multi-user.target.wants/vasum.service
+mkdir -p %{buildroot}/%{_datadir}/.zones
%clean
rm -rf %{buildroot}
diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt
index b5c9286..9c0fa4b 100644
--- a/server/configs/CMakeLists.txt
+++ b/server/configs/CMakeLists.txt
@@ -29,7 +29,10 @@ CONFIGURE_FILE(systemd/vasum.service.in
## Install #####################################################################
-INSTALL(FILES daemon.conf
+CONFIGURE_FILE(daemon.conf.in
+ ${CMAKE_BINARY_DIR}/daemon.conf)
+
+INSTALL(FILES ${CMAKE_BINARY_DIR}/daemon.conf
DESTINATION ${VSM_CONFIG_INSTALL_DIR})
# preprocess d-bus configs
diff --git a/server/configs/daemon.conf b/server/configs/daemon.conf.in
similarity index 84%
rename from server/configs/daemon.conf
rename to server/configs/daemon.conf.in
index 714640e..296c1c7 100644
--- a/server/configs/daemon.conf
+++ b/server/configs/daemon.conf.in
@@ -1,7 +1,7 @@
{
"zoneConfigs" : ["zones/private.conf", "zones/business.conf"],
- "zonesPath" : "/opt/usr/zones",
- "zoneImagePath" : "/opt/usr/zones/img/system-data.img",
+ "zonesPath" : "${DATA_DIR}/.zones",
+ "zoneImagePath" : "${DATA_DIR}/.zones/img/system-data.img",
"zoneTemplatePath" : "templates",
"zoneNewConfigPrefix" : "/var/lib/vasum",
"runMountPointPrefix" : "/var/run/zones",
diff --git a/server/configs/systemd/vasum.service.in b/server/configs/systemd/vasum.service.in
index f36622a..8131ed5 100644
--- a/server/configs/systemd/vasum.service.in
+++ b/server/configs/systemd/vasum.service.in
@@ -4,7 +4,7 @@ ConditionVirtualization=no
[Service]
Type=simple
-ExecStart=${CMAKE_INSTALL_PREFIX}/bin/vasum-server
+ExecStart=${CMAKE_INSTALL_PREFIX}/bin/vasum-server -r
Restart=on-failure
ExecReload=/bin/kill -HUP $MAINPID
--
2.7.4
From 112dc09c274e68b577e2c3d76e6ff0fcac3d3289 Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Mon, 15 Dec 2014 12:55:16 +0100
Subject: [PATCH 09/16] Update tizen common (with wayland) lxc template
[Bug/Feature] N/A
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: Ib7621c70a708fea479dc0d2e7d4bbc528728c504
Signed-off-by: Dariusz Michaluk
---
.../configs/lxc-templates/tizen-common-wayland.sh | 23 +++++++++-------------
server/configs/zones/business.conf | 2 +-
server/configs/zones/private.conf | 2 +-
3 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/server/configs/lxc-templates/tizen-common-wayland.sh b/server/configs/lxc-templates/tizen-common-wayland.sh
index ed2df9b..12fb223 100755
--- a/server/configs/lxc-templates/tizen-common-wayland.sh
+++ b/server/configs/lxc-templates/tizen-common-wayland.sh
@@ -23,14 +23,14 @@ usage()
cat <
- [-p|--path=] [-r|--rootfs=] [-v|--vt=]
+ [-p|--path=] [--rootfs=] [--vt=]
[--ipv4=] [--ipv4-gateway=] [-h|--help]
Mandatory args:
-n,--name zone name
Optional args:
- -p,--path path to zone config files, defaults to /var/lib/lxc
- --rootfs path to zone rootfs, defaults to /var/lib/lxc/[NAME]/rootfs
- -v,--vt zone virtual terminal
+ -p,--path path to zone config files
+ --rootfs path to zone rootfs
+ --vt zone virtual terminal
--ipv4 zone IP address
--ipv4-gateway zone gateway
-h,--help print help
@@ -38,7 +38,7 @@ EOF
return 0
}
-options=$(getopt -o hp:v:n: -l help,rootfs:,path:,vt:,name:,ipv4:,ipv4-gateway: -- "$@")
+options=$(getopt -o hp:n: -l help,rootfs:,path:,vt:,name:,ipv4:,ipv4-gateway: -- "$@")
if [ $? -ne 0 ]; then
usage $(basename $0)
exit 1
@@ -51,7 +51,7 @@ do
-h|--help) usage $0 && exit 0;;
--rootfs) rootfs=$2; shift 2;;
-p|--path) path=$2; shift 2;;
- -v|--vt) vt=$2; shift 2;;
+ --vt) vt=$2; shift 2;;
-n|--name) name=$2; shift 2;;
--ipv4) ipv4=$2; shift 2;;
--ipv4-gateway) ipv4_gateway=$2; shift 2;;
@@ -94,14 +94,12 @@ ${rootfs}/opt \
${rootfs}/proc \
${rootfs}/root \
${rootfs}/run \
-${rootfs}/run/dbus \
-${rootfs}/run/memory \
-${rootfs}/run/systemd \
-${rootfs}/run/udev \
${rootfs}/sbin \
${rootfs}/sys \
${rootfs}/tmp \
${rootfs}/usr \
+${rootfs}/var \
+${rootfs}/var/run \
${path}/hooks \
${path}/scripts \
${path}/systemd \
@@ -389,10 +387,7 @@ ${path}/systemd/user etc/systemd/user none ro,bind 0 0
/opt opt none rw,rbind 0 0
devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
devpts dev/pts devpts rw,relatime,gid=5,mode=620,ptmxmode=000 0 0
-/run/dbus run/dbus none rw,bind 0 0
-/run/memory run/memory none rw,bind 0 0
-/run/systemd run/systemd none rw,bind 0 0
-/run/udev run/udev none rw,bind 0 0
/sys/fs/smackfs sys/fs/smackfs none rw,bind 0 0
+/var/run/zones/${name}/run var/run none rw,bind 0 0
#tmpfs run tmpfs rw,nosuid,nodev,mode=755 0 0
EOF
diff --git a/server/configs/zones/business.conf b/server/configs/zones/business.conf
index b211ce3..6a4bc50 100644
--- a/server/configs/zones/business.conf
+++ b/server/configs/zones/business.conf
@@ -1,6 +1,6 @@
{
"name" : "business",
- "lxcTemplate" : "template.sh",
+ "lxcTemplate" : "tizen-common-wayland.sh",
"initWithArgs" : [],
"ipv4Gateway" : "10.0.102.1",
"ipv4" : "10.0.102.2",
diff --git a/server/configs/zones/private.conf b/server/configs/zones/private.conf
index b4fb56a..2a1147f 100644
--- a/server/configs/zones/private.conf
+++ b/server/configs/zones/private.conf
@@ -1,6 +1,6 @@
{
"name" : "private",
- "lxcTemplate" : "template.sh",
+ "lxcTemplate" : "tizen-common-wayland.sh",
"initWithArgs" : [],
"ipv4Gateway" : "10.0.101.1",
"ipv4" : "10.0.101.2",
--
2.7.4
From 21d934cb08890c90816f9f94cbdc096599c548e2 Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Tue, 16 Dec 2014 11:40:03 +0100
Subject: [PATCH 10/16] Some cppcheck fixes
[Bug] Some cppcheck fixes (const, uniused variable)
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run cppcheck
Change-Id: I58fa2e3434c6a7546441ba310bb437b59c7fd6de
---
client/vasum-client-impl.cpp | 4 ++--
client/vasum-client-impl.hpp | 4 ++--
server/input-monitor.cpp | 2 +-
server/input-monitor.hpp | 2 +-
server/proxy-call-policy.cpp | 2 +-
server/proxy-call-policy.hpp | 2 +-
server/zone-connection-transport.cpp | 2 +-
server/zone-connection-transport.hpp | 2 +-
server/zone.cpp | 2 +-
server/zone.hpp | 2 +-
server/zones-manager.cpp | 6 +++---
server/zones-manager.hpp | 6 +++---
tests/unit_tests/config/ut-configuration.cpp | 2 +-
zone-daemon/main.cpp | 2 --
14 files changed, 19 insertions(+), 21 deletions(-)
diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp
index 3c9448b..23270e4 100644
--- a/client/vasum-client-impl.cpp
+++ b/client/vasum-client-impl.cpp
@@ -307,12 +307,12 @@ VsmStatus Client::signalUnsubscribe(VsmSubscriptionId id)
return vsm_get_status();
}
-const char* Client::vsm_get_status_message() noexcept
+const char* Client::vsm_get_status_message() const noexcept
{
return mStatus.mMsg.c_str();
}
-VsmStatus Client::vsm_get_status() noexcept
+VsmStatus Client::vsm_get_status() const noexcept
{
return mStatus.mVsmStatus;
}
diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp
index 18eb726..66ffa82 100644
--- a/client/vasum-client-impl.hpp
+++ b/client/vasum-client-impl.hpp
@@ -96,12 +96,12 @@ public:
/**
* @see ::vsm_get_status_message
*/
- const char* vsm_get_status_message() noexcept;
+ const char* vsm_get_status_message() const noexcept;
/**
* @see ::vsm_get_status
*/
- VsmStatus vsm_get_status() noexcept;
+ VsmStatus vsm_get_status() const noexcept;
/**
* @see ::vsm_get_zone_dbuses
diff --git a/server/input-monitor.cpp b/server/input-monitor.cpp
index 8d641b1..7937840 100644
--- a/server/input-monitor.cpp
+++ b/server/input-monitor.cpp
@@ -148,7 +148,7 @@ bool isDeviceWithName(const boost::regex& deviceNameRegex,
}
} // namespace
-std::string InputMonitor::getDevicePath()
+std::string InputMonitor::getDevicePath() const
{
std::string device = mConfig.device;
if (fs::path(device).is_absolute()
diff --git a/server/input-monitor.hpp b/server/input-monitor.hpp
index 93c2d75..2b0ed45 100644
--- a/server/input-monitor.hpp
+++ b/server/input-monitor.hpp
@@ -56,7 +56,7 @@ private:
std::list mEventTimes;
GIOChannel* mChannelPtr;
- std::string getDevicePath();
+ std::string getDevicePath() const;
void createGIOChannel(const std::string& devicePath);
// Internal callback to be registered at glib g_io_add_watch()
diff --git a/server/proxy-call-policy.cpp b/server/proxy-call-policy.cpp
index 281cb3a..9fed52b 100644
--- a/server/proxy-call-policy.cpp
+++ b/server/proxy-call-policy.cpp
@@ -51,7 +51,7 @@ bool ProxyCallPolicy::isProxyCallAllowed(const std::string& caller,
const std::string& targetBusName,
const std::string& targetObjectPath,
const std::string& targetInterface,
- const std::string& targetMethod)
+ const std::string& targetMethod) const
{
for (const ProxyCallRule& rule : mProxyCallRules) {
if (match(rule.caller, caller)
diff --git a/server/proxy-call-policy.hpp b/server/proxy-call-policy.hpp
index 4176979..d6fbaed 100644
--- a/server/proxy-call-policy.hpp
+++ b/server/proxy-call-policy.hpp
@@ -44,7 +44,7 @@ public:
const std::string& targetBusName,
const std::string& targetObjectPath,
const std::string& targetInterface,
- const std::string& targetMethod);
+ const std::string& targetMethod) const;
private:
std::vector mProxyCallRules;
diff --git a/server/zone-connection-transport.cpp b/server/zone-connection-transport.cpp
index d209705..0757241 100644
--- a/server/zone-connection-transport.cpp
+++ b/server/zone-connection-transport.cpp
@@ -100,7 +100,7 @@ ZoneConnectionTransport::~ZoneConnectionTransport()
}
-std::string ZoneConnectionTransport::acquireAddress()
+std::string ZoneConnectionTransport::acquireAddress() const
{
if (mRunMountPoint.empty()) {
return std::string();
diff --git a/server/zone-connection-transport.hpp b/server/zone-connection-transport.hpp
index 5729389..d651f3c 100644
--- a/server/zone-connection-transport.hpp
+++ b/server/zone-connection-transport.hpp
@@ -44,7 +44,7 @@ public:
/**
* Gets dbus addres. Will block until address is available.
*/
- std::string acquireAddress();
+ std::string acquireAddress() const;
/**
* Set whether object should detach from transport filesystem on exit
diff --git a/server/zone.cpp b/server/zone.cpp
index 5f6dce0..199ecff 100644
--- a/server/zone.cpp
+++ b/server/zone.cpp
@@ -200,7 +200,7 @@ void Zone::disconnect()
}
}
-std::string Zone::getDbusAddress()
+std::string Zone::getDbusAddress() const
{
Lock lock(mReconnectMutex);
return mDbusAddress;
diff --git a/server/zone.hpp b/server/zone.hpp
index 1fdc588..fba9399 100644
--- a/server/zone.hpp
+++ b/server/zone.hpp
@@ -226,7 +226,7 @@ public:
/**
* Get a dbus address
*/
- std::string getDbusAddress();
+ std::string getDbusAddress() const;
/**
* Get id of VT
diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp
index 2ce03d7..a1dcc71 100644
--- a/server/zones-manager.cpp
+++ b/server/zones-manager.cpp
@@ -305,7 +305,7 @@ bool ZonesManager::isRunning(const std::string& zoneId)
return iter->second->isRunning();
}
-std::string ZonesManager::getRunningForegroundZoneId()
+std::string ZonesManager::getRunningForegroundZoneId() const
{
for (auto& zone : mZones) {
if (zone.first == mConfig.foregroundId &&
@@ -523,7 +523,7 @@ void ZonesManager::handleProxyCall(const std::string& caller,
asyncResultCallback);
}
-void ZonesManager::handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result)
+void ZonesManager::handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result) const
{
std::vector entries;
for (auto& zone : mZones) {
@@ -542,7 +542,7 @@ void ZonesManager::handleDbusStateChanged(const std::string& zoneId,
mHostConnection.signalZoneDbusState(zoneId, dbusAddress);
}
-void ZonesManager::handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result)
+void ZonesManager::handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result) const
{
std::vector zoneIds;
for(auto& zone: mZones){
diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp
index b58da86..41a3e7c 100644
--- a/server/zones-manager.hpp
+++ b/server/zones-manager.hpp
@@ -92,7 +92,7 @@ public:
/**
* @return id of the currently focused/foreground zone
*/
- std::string getRunningForegroundZoneId();
+ std::string getRunningForegroundZoneId() const;
/**
* @return id of next to currently focused/foreground zone. If currently focused zone
@@ -138,9 +138,9 @@ private:
const std::string& targetMethod,
GVariant* parameters,
dbus::MethodResultBuilder::Pointer result);
- void handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result);
+ void handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result) const;
void handleDbusStateChanged(const std::string& zoneId, const std::string& dbusAddress);
- void handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result);
+ void handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result) const;
void handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer result);
void handleGetZoneInfoCall(const std::string& id, dbus::MethodResultBuilder::Pointer result);
void handleDeclareFileCall(const std::string& zone,
diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp
index e46bfd8..4e6bedc 100644
--- a/tests/unit_tests/config/ut-configuration.cpp
+++ b/tests/unit_tests/config/ut-configuration.cpp
@@ -50,7 +50,7 @@ struct TestConfig {
(
intVal
)
- SubSubConfig() : moved(false) {}
+ SubSubConfig() : intVal(), moved(false) {}
SubSubConfig(const SubSubConfig& config) : intVal(config.intVal), moved(false) {}
SubSubConfig(SubSubConfig&& config) : intVal(std::move(config.intVal)), moved(false) {
config.moved = true;
diff --git a/zone-daemon/main.cpp b/zone-daemon/main.cpp
index 846f431..f0c00c6 100644
--- a/zone-daemon/main.cpp
+++ b/zone-daemon/main.cpp
@@ -57,8 +57,6 @@ const std::string PROGRAM_NAME_AND_VERSION =
int main(int argc, char* argv[])
{
- std::string configPath ;
-
try {
po::options_description desc("Allowed options");
--
2.7.4
From 9d21e0db847cebff18406f16f5d3234ec0d9e0ec Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Wed, 17 Dec 2014 13:41:13 +0100
Subject: [PATCH 11/16] Fix synchronization issues
[Bug/Feature] Missing mutex
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: Iec7e016b62a0f3a671fd4843957e1bc6a265f84e
---
server/zones-manager.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++-
server/zones-manager.hpp | 4 ++++
2 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp
index a1dcc71..a0cb274 100644
--- a/server/zones-manager.cpp
+++ b/server/zones-manager.cpp
@@ -195,6 +195,8 @@ void ZonesManager::createZone(const std::string& zoneConfig)
zone->setDbusStateChangedCallback(bind(&ZonesManager::handleDbusStateChanged,
this, id, _1));
+ Lock lock(mMutex);
+
mZones.insert(ZoneMap::value_type(id, std::move(zone)));
// after zone is created successfully, put a file informing that zones are enabled
@@ -208,7 +210,8 @@ void ZonesManager::createZone(const std::string& zoneConfig)
void ZonesManager::destroyZone(const std::string& zoneId)
{
- // TODO mutex for mZones access
+ Lock lock(mMutex);
+
auto it = mZones.find(zoneId);
if (it == mZones.end()) {
LOGE("Failed to destroy zone " << zoneId << ": no such zone");
@@ -228,6 +231,8 @@ void ZonesManager::destroyZone(const std::string& zoneId)
void ZonesManager::focus(const std::string& zoneId)
{
+ Lock lock(mMutex);
+
/* try to access the object first to throw immediately if it doesn't exist */
ZoneMap::mapped_type& foregroundZone = mZones.at(zoneId);
@@ -249,6 +254,8 @@ void ZonesManager::startAll()
{
LOGI("Starting all zones");
+ Lock lock(mMutex);
+
bool isForegroundFound = false;
for (auto& zone : mZones) {
@@ -279,6 +286,8 @@ void ZonesManager::stopAll()
{
LOGI("Stopping all zones");
+ Lock lock(mMutex);
+
for (auto& zone : mZones) {
zone.second->stop();
}
@@ -286,6 +295,8 @@ void ZonesManager::stopAll()
bool ZonesManager::isPaused(const std::string& zoneId)
{
+ Lock lock(mMutex);
+
auto iter = mZones.find(zoneId);
if (iter == mZones.end()) {
LOGE("No such zone id: " << zoneId);
@@ -297,6 +308,8 @@ bool ZonesManager::isPaused(const std::string& zoneId)
bool ZonesManager::isRunning(const std::string& zoneId)
{
+ Lock lock(mMutex);
+
auto iter = mZones.find(zoneId);
if (iter == mZones.end()) {
LOGE("No such zone id: " << zoneId);
@@ -307,6 +320,8 @@ bool ZonesManager::isRunning(const std::string& zoneId)
std::string ZonesManager::getRunningForegroundZoneId() const
{
+ Lock lock(mMutex);
+
for (auto& zone : mZones) {
if (zone.first == mConfig.foregroundId &&
zone.second->isRunning()) {
@@ -318,6 +333,8 @@ std::string ZonesManager::getRunningForegroundZoneId() const
std::string ZonesManager::getNextToForegroundZoneId()
{
+ Lock lock(mMutex);
+
// handles case where there is no next zone
if (mZones.size() < 2) {
return std::string();
@@ -349,6 +366,8 @@ void ZonesManager::switchingSequenceMonitorNotify()
void ZonesManager::setZonesDetachOnExit()
{
+ Lock lock(mMutex);
+
mDetachOnExit = true;
for (auto& zone : mZones) {
@@ -362,6 +381,9 @@ void ZonesManager::notifyActiveZoneHandler(const std::string& caller,
{
LOGI("notifyActiveZoneHandler(" << caller << ", " << application << ", " << message
<< ") called");
+
+ Lock lock(mMutex);
+
try {
const std::string activeZone = getRunningForegroundZoneId();
if (!activeZone.empty() && caller != activeZone) {
@@ -375,6 +397,8 @@ void ZonesManager::notifyActiveZoneHandler(const std::string& caller,
void ZonesManager::displayOffHandler(const std::string& /*caller*/)
{
// get config of currently set zone and switch if switchToDefaultAfterTimeout is true
+ Lock lock(mMutex);
+
const std::string activeZoneName = getRunningForegroundZoneId();
const auto& activeZone = mZones.find(activeZoneName);
@@ -414,6 +438,8 @@ void ZonesManager::handleZoneMoveFileRequest(const std::string& srcZoneId,
<< "dst: " << dstZoneId << "\n"
<< "path: " << path);
+ Lock lock(mMutex);
+
ZoneMap::const_iterator srcIter = mZones.find(srcZoneId);
if (srcIter == mZones.end()) {
LOGE("Source zone '" << srcZoneId << "' not found");
@@ -507,6 +533,8 @@ void ZonesManager::handleProxyCall(const std::string& caller,
return;
}
+ Lock lock(mMutex);
+
ZoneMap::const_iterator targetIter = mZones.find(target);
if (targetIter == mZones.end()) {
LOGE("Target zone '" << target << "' not found");
@@ -525,6 +553,8 @@ void ZonesManager::handleProxyCall(const std::string& caller,
void ZonesManager::handleGetZoneDbuses(dbus::MethodResultBuilder::Pointer result) const
{
+ Lock lock(mMutex);
+
std::vector entries;
for (auto& zone : mZones) {
GVariant* zoneId = g_variant_new_string(zone.first.c_str());
@@ -544,6 +574,8 @@ void ZonesManager::handleDbusStateChanged(const std::string& zoneId,
void ZonesManager::handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer result) const
{
+ Lock lock(mMutex);
+
std::vector zoneIds;
for(auto& zone: mZones){
zoneIds.push_back(g_variant_new_string(zone.first.c_str()));
@@ -558,6 +590,9 @@ void ZonesManager::handleGetZoneIdsCall(dbus::MethodResultBuilder::Pointer resul
void ZonesManager::handleGetActiveZoneIdCall(dbus::MethodResultBuilder::Pointer result)
{
LOGI("GetActiveZoneId call");
+
+ Lock lock(mMutex);
+
if (!mConfig.foregroundId.empty() && mZones[mConfig.foregroundId]->isRunning()){
result->set(g_variant_new("(s)", mConfig.foregroundId.c_str()));
} else {
@@ -569,6 +604,9 @@ void ZonesManager::handleGetZoneInfoCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result)
{
LOGI("GetZoneInfo call");
+
+ Lock lock(mMutex);
+
if (mZones.count(id) == 0) {
LOGE("No zone with id=" << id);
result->setError(api::ERROR_INVALID_ID, "No such zone id");
@@ -607,7 +645,10 @@ void ZonesManager::handleDeclareFileCall(const std::string& zone,
dbus::MethodResultBuilder::Pointer result)
{
LOGI("DeclareFile call");
+
try {
+ Lock lock(mMutex);
+
mZones.at(zone)->declareFile(type, path, flags, mode);
result->setVoid();
} catch (const std::out_of_range&) {
@@ -628,7 +669,10 @@ void ZonesManager::handleDeclareMountCall(const std::string& source,
dbus::MethodResultBuilder::Pointer result)
{
LOGI("DeclareMount call");
+
try {
+ Lock lock(mMutex);
+
mZones.at(zone)->declareMount(source, target, type, flags, data);
result->setVoid();
} catch (const std::out_of_range&) {
@@ -647,6 +691,8 @@ void ZonesManager::handleDeclareLinkCall(const std::string& source,
{
LOGI("DeclareLink call");
try {
+ Lock lock(mMutex);
+
mZones.at(zone)->declareLink(source, target);
result->setVoid();
} catch (const std::out_of_range&) {
@@ -662,6 +708,9 @@ void ZonesManager::handleSetActiveZoneCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result)
{
LOGI("SetActiveZone call; Id=" << id );
+
+ Lock lock(mMutex);
+
auto zone = mZones.find(id);
if (zone == mZones.end()){
LOGE("No zone with id=" << id );
@@ -737,6 +786,8 @@ void ZonesManager::handleCreateZoneCall(const std::string& id,
LOGI("Creating zone " << id);
+ Lock lock(mMutex);
+
// TODO: This solution is temporary. It utilizes direct access to config files when creating new
// zones. Update this handler when config database will appear.
namespace fs = boost::filesystem;
@@ -819,6 +870,8 @@ void ZonesManager::handleCreateZoneCall(const std::string& id,
void ZonesManager::handleDestroyZoneCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result)
{
+ Lock lock(mMutex);
+
if (mZones.find(id) == mZones.end()) {
LOGE("Failed to destroy zone - no such zone id: " << id);
result->setError(api::ERROR_INVALID_ID, "No such zone id");
@@ -845,6 +898,9 @@ void ZonesManager::handleLockZoneCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result)
{
LOGI("LockZone call; Id=" << id );
+
+ Lock lock(mMutex);
+
auto iter = mZones.find(id);
if (iter == mZones.end()) {
LOGE("Failed to lock zone - no such zone id: " << id);
@@ -875,6 +931,9 @@ void ZonesManager::handleUnlockZoneCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result)
{
LOGI("UnlockZone call; Id=" << id );
+
+ Lock lock(mMutex);
+
auto iter = mZones.find(id);
if (iter == mZones.end()) {
LOGE("Failed to unlock zone - no such zone id: " << id);
diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp
index 41a3e7c..2ed5312 100644
--- a/server/zones-manager.hpp
+++ b/server/zones-manager.hpp
@@ -106,7 +106,11 @@ public:
void setZonesDetachOnExit();
private:
+ typedef std::recursive_mutex Mutex;
+ typedef std::unique_lock Lock;
+
utils::Worker::Pointer mWorker;
+ mutable Mutex mMutex; // used to protect mZones
ZonesManagerConfig mConfig;
std::string mConfigPath;
HostConnection mHostConnection;
--
2.7.4
From 01d4faf05df4e0be4b5daa7e9468583bc2992c06 Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Wed, 17 Dec 2014 15:46:59 +0100
Subject: [PATCH 12/16] Rearrange create zone process
[Bug/Feature] Remove start functionality, add VT support.
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I67a7eebf6e45bb2cab29e833fbf53c1bdaeb88fb
Signed-off-by: Dariusz Michaluk
---
server/configs/daemon.conf.in | 2 +-
server/configs/templates/template.conf | 4 ++--
server/zones-manager.cpp | 20 +++++++++-----------
tests/unit_tests/server/ut-zones-manager.cpp | 6 +++---
4 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/server/configs/daemon.conf.in b/server/configs/daemon.conf.in
index 296c1c7..648d986 100644
--- a/server/configs/daemon.conf.in
+++ b/server/configs/daemon.conf.in
@@ -1,7 +1,7 @@
{
"zoneConfigs" : ["zones/private.conf", "zones/business.conf"],
"zonesPath" : "${DATA_DIR}/.zones",
- "zoneImagePath" : "${DATA_DIR}/.zones/img/system-data.img",
+ "zoneImagePath" : "",
"zoneTemplatePath" : "templates",
"zoneNewConfigPrefix" : "/var/lib/vasum",
"runMountPointPrefix" : "/var/run/zones",
diff --git a/server/configs/templates/template.conf b/server/configs/templates/template.conf
index 1939d51..fa6ef5c 100644
--- a/server/configs/templates/template.conf
+++ b/server/configs/templates/template.conf
@@ -1,13 +1,13 @@
{
"name" : "~NAME~",
- "lxcTemplate" : "template.sh",
+ "lxcTemplate" : "tizen-common-wayland.sh",
"initWithArgs" : [],
"ipv4Gateway" : "10.0.~IP~.1",
"ipv4" : "10.0.~IP~.2",
"cpuQuotaForeground" : -1,
"cpuQuotaBackground" : 1000,
"privilege" : 10,
- "vt" : -1,
+ "vt" : ~VT~,
"switchToDefaultAfterTimeout" : true,
"enableDbusIntegration" : true,
"runMountPoint" : "~NAME~/run",
diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp
index a0cb274..eafbe4b 100644
--- a/server/zones-manager.cpp
+++ b/server/zones-manager.cpp
@@ -69,8 +69,10 @@ const std::string ENABLED_FILE_NAME = "enabled";
const boost::regex ZONE_NAME_REGEX("~NAME~");
const boost::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~");
+const boost::regex ZONE_VT_REGEX("~VT~");
const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100;
+const unsigned int ZONE_VT_BASE = 1;
} // namespace
@@ -764,6 +766,12 @@ void ZonesManager::generateNewConfig(const std::string& id,
LOGD("IP third octet: " << thirdOctetStr);
resultConfig = boost::regex_replace(resultConfig, ZONE_IP_THIRD_OCTET_REGEX, thirdOctetStr);
+ // generate first free VT number
+ // TODO change algorithm after implementing removeZone
+ std::string freeVT = std::to_string(ZONE_VT_BASE + mZones.size() + 1);
+ LOGD("VT number: " << freeVT);
+ resultConfig = boost::regex_replace(resultConfig, ZONE_VT_REGEX, freeVT);
+
if (!utils::saveFileContent(resultPath, resultConfig)) {
LOGE("Faield to save new config file.");
throw ZoneOperationException("Failed to save new config file.");
@@ -854,17 +862,7 @@ void ZonesManager::handleCreateZoneCall(const std::string& id,
return;
}
- auto resultCallback = [this, id, result](bool succeeded) {
- if (succeeded) {
- focus(id);
- result->setVoid();
- } else {
- LOGE("Failed to start zone.");
- // TODO removeZone
- result->setError(api::ERROR_INTERNAL, "Failed to start zone");
- }
- };
- mZones[id]->startAsync(resultCallback);
+ result->setVoid();
}
void ZonesManager::handleDestroyZoneCall(const std::string& id,
diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp
index 07c03dd..4db9434 100644
--- a/tests/unit_tests/server/ut-zones-manager.cpp
+++ b/tests/unit_tests/server/ut-zones-manager.cpp
@@ -1065,16 +1065,16 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZoneTest)
dbus.callAsyncMethodCreateZone(zone1, resultCallback);
BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
- BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone1);
-
// create zone2
dbus.callAsyncMethodCreateZone(zone2, resultCallback);
BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
- BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone2); //TODO is this valid?
// create zone3
dbus.callAsyncMethodCreateZone(zone3, resultCallback);
BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+
+ cm.startAll();
+
BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), zone3);
// destroy zone2
--
2.7.4
From fa7b65cc7179ef7a037f5d3114fe501147e0e72b Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Tue, 9 Dec 2014 15:56:40 +0100
Subject: [PATCH 13/16] Taking into account the provision configuration
[Feature] Taking into account the provision configuration
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I2b564bb3f9af2514781ff2233cabb7b1ca654e69
---
client/vasum-client-impl.cpp | 4 +-
common/base-exception.cpp | 41 ++++
common/base-exception.hpp | 5 +
common/utils/fs.cpp | 182 ++++++++++++++--
common/utils/fs.hpp | 33 +++
server/CMakeLists.txt | 1 +
server/configs/templates/template.conf | 6 +-
server/configs/zones/business.conf | 6 +-
server/configs/zones/private.conf | 6 +-
server/zone-config.hpp | 8 +-
...ioning-config.hpp => zone-provision-config.hpp} | 0
server/zone-provision.cpp | 214 ++++++++++++++++++
server/zone-provision.hpp | 95 ++++++++
server/zone.cpp | 57 ++---
server/zone.hpp | 8 +-
server/zones-manager.cpp | 5 +-
.../configs/ut-client/zones/console1-dbus.conf.in | 3 +-
.../configs/ut-client/zones/console2-dbus.conf.in | 3 +-
.../configs/ut-client/zones/console3-dbus.conf.in | 3 +-
.../server/configs/ut-server/zones/zone1.conf | 3 +-
.../server/configs/ut-server/zones/zone2.conf | 3 +-
.../server/configs/ut-server/zones/zone3.conf | 3 +-
.../server/configs/ut-zone-admin/zones/buggy.conf | 3 +-
.../configs/ut-zone-admin/zones/missing.conf | 3 +-
.../ut-zone-admin/zones/test-no-shutdown.conf | 3 +-
.../server/configs/ut-zone-admin/zones/test.conf | 3 +-
.../server/configs/ut-zone/zones/buggy.conf | 3 +-
.../server/configs/ut-zone/zones/test-dbus.conf.in | 3 +-
.../server/configs/ut-zone/zones/test.conf | 3 +-
.../ut-zones-manager/templates/template.conf.in | 3 +-
.../ut-zones-manager/zones/console1-dbus.conf.in | 3 +-
.../configs/ut-zones-manager/zones/console1.conf | 3 +-
.../ut-zones-manager/zones/console2-dbus.conf.in | 3 +-
.../configs/ut-zones-manager/zones/console2.conf | 3 +-
.../ut-zones-manager/zones/console3-dbus.conf.in | 3 +-
.../configs/ut-zones-manager/zones/console3.conf | 3 +-
tests/unit_tests/server/ut-zone-provision.cpp | 242 +++++++++++++++++++++
tests/unit_tests/server/ut-zones-manager.cpp | 151 -------------
zone-daemon/CMakeLists.txt | 3 +-
39 files changed, 894 insertions(+), 233 deletions(-)
create mode 100644 common/base-exception.cpp
rename server/{provisioning-config.hpp => zone-provision-config.hpp} (100%)
create mode 100644 server/zone-provision.cpp
create mode 100644 server/zone-provision.hpp
create mode 100644 tests/unit_tests/server/ut-zone-provision.cpp
diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp
index 23270e4..2aa923d 100644
--- a/client/vasum-client-impl.cpp
+++ b/client/vasum-client-impl.cpp
@@ -322,7 +322,7 @@ VsmStatus Client::vsm_get_zone_dbuses(VsmArrayString* keys, VsmArrayString* valu
assert(keys);
assert(values);
- GVariant* out;
+ GVariant* out = NULL;
VsmStatus ret = callMethod(HOST_INTERFACE,
api::host::METHOD_GET_ZONE_DBUSES,
NULL,
@@ -343,7 +343,7 @@ VsmStatus Client::vsm_get_zone_ids(VsmArrayString* array) noexcept
{
assert(array);
- GVariant* out;
+ GVariant* out = NULL;
VsmStatus ret = callMethod(HOST_INTERFACE,
api::host::METHOD_GET_ZONE_ID_LIST,
NULL,
diff --git a/common/base-exception.cpp b/common/base-exception.cpp
new file mode 100644
index 0000000..bcfe600
--- /dev/null
+++ b/common/base-exception.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Mateusz Malicki
+ *
+ * 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
+ * @author Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief Vasum base exception implementation
+ */
+
+#include "base-exception.hpp"
+
+#include
+#include
+#include
+
+namespace vasum {
+
+const int ERROR_MESSAGE_BUFFER_CAPACITY = 256;
+
+std::string getSystemErrorMessage()
+{
+ char buf[ERROR_MESSAGE_BUFFER_CAPACITY];
+ return strerror_r(errno, buf, sizeof(buf));
+}
+
+} // namespace vasum
diff --git a/common/base-exception.hpp b/common/base-exception.hpp
index d501e3d..3969404 100644
--- a/common/base-exception.hpp
+++ b/common/base-exception.hpp
@@ -41,6 +41,11 @@ struct VasumException: public std::runtime_error {
VasumException(const std::string& error = "") : std::runtime_error(error) {}
};
+/**
+ * Return string describing error number
+ * it is wrapper for strerror_r
+ */
+std::string getSystemErrorMessage();
} // namespace vasum
diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp
index 3330cbf..763bdfe 100644
--- a/common/utils/fs.cpp
+++ b/common/utils/fs.cpp
@@ -38,10 +38,13 @@
#include
#include
#include
+#include
#include
+namespace fs = boost::filesystem;
+
namespace vasum {
namespace utils {
@@ -140,6 +143,36 @@ bool mountRun(const std::string& path)
|| utils::mountTmpfs(path, RUN_MOUNT_POINT_FLAGS, RUN_MOUNT_POINT_OPTIONS_NO_SMACK);
}
+bool mount(const std::string& source,
+ const std::string& target,
+ const std::string& filesystemtype,
+ unsigned long mountflags,
+ const std::string& data)
+{
+ int ret = ::mount(source.c_str(),
+ target.c_str(),
+ filesystemtype.c_str(),
+ mountflags,
+ data.c_str());
+ if (ret < 0) {
+ LOGE("Mount operation failure: "
+ << "source path: "
+ << source
+ << ", target path: "
+ << target
+ << ", filesystemtype: "
+ << filesystemtype
+ << ", mountflags: "
+ << mountflags
+ << ", data: "
+ << data
+ << ", msg: "
+ << getSystemErrorMessage());
+ return false;
+ }
+ return true;
+}
+
bool umount(const std::string& path)
{
if (::umount(path.c_str()) != 0) {
@@ -181,7 +214,6 @@ bool moveFile(const std::string& src, const std::string& dst)
{
bool bResult;
- namespace fs = boost::filesystem;
boost::system::error_code error;
// The destination has to be a full path (including a file name)
@@ -218,8 +250,6 @@ namespace {
bool copyDirContentsRec(const boost::filesystem::path& src, const boost::filesystem::path& dst)
{
- namespace fs = boost::filesystem;
-
try {
for (fs::directory_iterator file(src);
file != fs::directory_iterator();
@@ -274,26 +304,34 @@ bool copyDirContentsRec(const boost::filesystem::path& src, const boost::filesys
return true;
}
+boost::filesystem::perms getPerms(const mode_t& mode)
+{
+ return static_cast(mode);
+}
+
+bool copySmackLabel(const std::string& /* src */, const std::string& /* dst */)
+{
+ //TODO: fill copySmackLabel function
+ return true;
+}
+
+
} // namespace
bool copyDirContents(const std::string& src, const std::string& dst)
{
- namespace fs = boost::filesystem;
-
return copyDirContentsRec(fs::path(src), fs::path(dst));
}
bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem::perms mode)
{
- namespace fs = boost::filesystem;
-
fs::path dirPath(path);
- boost::system::error_code ec;
+ boost::system::error_code errorCode;
bool runDirCreated = false;
if (!fs::exists(dirPath)) {
- if (!fs::create_directory(dirPath, ec)) {
+ if (!fs::create_directory(dirPath, errorCode)) {
LOGE("Failed to create directory '" << path << "': "
- << ec.message());
+ << errorCode.message());
return false;
}
runDirCreated = true;
@@ -303,10 +341,10 @@ bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem:
}
// set permissions
- fs::permissions(dirPath, mode, ec);
+ fs::permissions(dirPath, mode, errorCode);
if (fs::status(dirPath).permissions() != mode) {
LOGE("Failed to set permissions to '" << path << "': "
- << ec.message());
+ << errorCode.message());
return false;
}
@@ -323,10 +361,36 @@ bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem:
return true;
}
-bool createEmptyDir(const std::string& path)
+bool createDirs(const std::string& path, mode_t mode)
{
- namespace fs = boost::filesystem;
+ boost::filesystem::perms perms = getPerms(mode);
+ std::vector dirs;
+ fs::path prefix;
+ fs::path dirPath = fs::path(path);
+ for (const auto dir : dirPath) {
+ prefix /= dir;
+ if (!fs::exists(prefix)) {
+ bool created = createDir(prefix.string(), -1, -1, perms);
+ if (created) {
+ dirs.push_back(prefix);
+ } else {
+ LOGE("Failed to create dir");
+ for (auto dir = dirs.rbegin(); dir != dirs.rend(); ++dir) {
+ boost::system::error_code errorCode;
+ fs::remove(*dir, errorCode);
+ if (errorCode) {
+ LOGE("Error during cleaning: dir: " << *dir << ", msg: " << errorCode.message());
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+bool createEmptyDir(const std::string& path)
+{
fs::path dirPath(path);
boost::system::error_code ec;
bool cleanDirCreated = false;
@@ -353,5 +417,95 @@ bool createEmptyDir(const std::string& path)
return true;
}
+bool createFile(const std::string& path, int flags, mode_t mode)
+{
+ // TODO: Check if we really need *flags* in the API
+ int ret = ::open(path.c_str(), flags, mode);
+ if (ret < 0) {
+ LOGE("Failed to create file: path=host:"
+ << path
+ << ", msg: "
+ << getSystemErrorMessage());
+ return false;
+ }
+ close(ret);
+ return true;
+}
+
+bool createFifo(const std::string& path, mode_t mode)
+{
+ int ret = ::mkfifo(path.c_str(), mode);
+ if (ret < 0) {
+ LOGE("Failed to make fifo: path=host:" << path);
+ return false;
+ }
+ return true;
+}
+
+bool copyFile(const std::string& src, const std::string& dest)
+{
+ boost::system::error_code errorCode;
+ fs::copy_file(src, dest, errorCode);
+ if (errorCode) {
+ LOGE("Failed to copy file: msg: "
+ << errorCode.message()
+ << ", path=host:"
+ << src
+ << ", path=host:"
+ << dest);
+ return false;
+ }
+ bool retSmack = copySmackLabel(src, dest);
+ if (!retSmack) {
+ LOGE("Failed to copy file: msg: (can't copy smacklabel) "
+ << ", path=host:"
+ << src
+ << ", path=host:"
+ << dest);
+ fs::remove(src, errorCode);
+ if (errorCode) {
+ LOGE("Failed to clean after copy failure: path=host:"
+ << src
+ << ", msg: "
+ << errorCode.message());
+ }
+ return false;
+ }
+ return true;
+}
+
+bool createLink(const std::string& src, const std::string& dest)
+{
+ int retLink = ::link(src.c_str(), dest.c_str());
+ if (retLink < 0) {
+ LOGE("Failed to hard link: path=host:"
+ << src
+ << ", path=host:"
+ << dest
+ << ", msg:"
+ << getSystemErrorMessage());
+ return false;
+ }
+ bool retSmack = copySmackLabel(src, dest);
+ if (!retSmack) {
+ LOGE("Failed to copy smack label: path=host:"
+ << src
+ << ", path=host:"
+ << dest);
+ boost::system::error_code ec;
+ fs::remove(dest, ec);
+ if (!ec) {
+ LOGE("Failed to clean after hard link creation failure: path=host:"
+ << src
+ << ", to: "
+ << dest
+ << ", msg: "
+ << ec.message());
+ }
+ return false;
+ }
+ return true;
+}
+
} // namespace utils
} // namespace vasum
diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp
index 35000c6..b00f95a 100644
--- a/common/utils/fs.hpp
+++ b/common/utils/fs.hpp
@@ -70,6 +70,15 @@ bool listDir(const std::string& path, std::vector& files);
bool mountRun(const std::string& path);
/**
+ * Creates mount point
+ */
+bool mount(const std::string& source,
+ const std::string& target,
+ const std::string& filesystemtype,
+ unsigned long mountflags,
+ const std::string& data);
+
+/**
* Umounts a filesystem
*/
bool umount(const std::string& path);
@@ -102,12 +111,36 @@ bool copyDirContents(const std::string& src, const std::string& dst);
bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem::perms mode);
/**
+ * Recursively creates a directory with specific permissions set.
+ */
+bool createDirs(const std::string& path, mode_t mode);
+
+/**
* Creates an empty directory, ready to serve as mount point.
* Succeeds either if path did not exist and was created successfully, or if already existing dir
* under the same path is empty and is not a mount point.
*/
bool createEmptyDir(const std::string& path);
+/**
+ * Creates an empty file
+ */
+bool createFile(const std::string& path, int flags, mode_t mode);
+
+/**
+ * Creates an FIFO special file
+ */
+bool createFifo(const std::string& path, mode_t mode);
+
+/**
+ * Copy an file
+ */
+bool copyFile(const std::string& src, const std::string& dest);
+
+/**
+ * Create hard link
+ */
+bool createLink(const std::string& src, const std::string& dest);
} // namespace utils
} // namespace vasum
diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt
index 8c7604a..adfef3e 100644
--- a/server/CMakeLists.txt
+++ b/server/CMakeLists.txt
@@ -34,6 +34,7 @@ PKG_CHECK_MODULES(SERVER_DEPS REQUIRED lxc json gio-2.0 libsystemd-journal libsy
libcap-ng libLogger libSimpleDbus libConfig)
INCLUDE_DIRECTORIES(${COMMON_FOLDER})
+INCLUDE_DIRECTORIES(${CLIENT_FOLDER})
INCLUDE_DIRECTORIES(SYSTEM ${SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(${SERVER_CODENAME} ${SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES})
diff --git a/server/configs/templates/template.conf b/server/configs/templates/template.conf
index fa6ef5c..e011a64 100644
--- a/server/configs/templates/template.conf
+++ b/server/configs/templates/template.conf
@@ -12,5 +12,9 @@
"enableDbusIntegration" : true,
"runMountPoint" : "~NAME~/run",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : [ "/tmp/",
+ "/run/",
+ "/opt/usr/data/",
+ "/opt/usr/dbsapce/" ]
}
diff --git a/server/configs/zones/business.conf b/server/configs/zones/business.conf
index 6a4bc50..74c3bad 100644
--- a/server/configs/zones/business.conf
+++ b/server/configs/zones/business.conf
@@ -12,5 +12,9 @@
"switchToDefaultAfterTimeout" : true,
"runMountPoint" : "business/run",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : [ "/tmp/",
+ "/run/",
+ "/opt/usr/data/",
+ "/opt/usr/dbsapce/" ]
}
diff --git a/server/configs/zones/private.conf b/server/configs/zones/private.conf
index 2a1147f..ffb7e85 100644
--- a/server/configs/zones/private.conf
+++ b/server/configs/zones/private.conf
@@ -12,5 +12,9 @@
"switchToDefaultAfterTimeout" : true,
"runMountPoint" : "private/run",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : [ "/tmp/",
+ "/run/",
+ "/opt/usr/data/",
+ "/opt/usr/dbsapce/" ]
}
diff --git a/server/zone-config.hpp b/server/zone-config.hpp
index b801af8..f92ca8f 100644
--- a/server/zone-config.hpp
+++ b/server/zone-config.hpp
@@ -112,6 +112,11 @@ struct ZoneConfig {
*/
std::vector permittedToRecv;
+ /**
+ * Valid hard link prefixes.
+ */
+ std::vector validLinkPrefixes;
+
CONFIG_REGISTER
(
name,
@@ -127,7 +132,8 @@ struct ZoneConfig {
cpuQuotaBackground,
runMountPoint,
permittedToSend,
- permittedToRecv
+ permittedToRecv,
+ validLinkPrefixes
)
};
diff --git a/server/provisioning-config.hpp b/server/zone-provision-config.hpp
similarity index 100%
rename from server/provisioning-config.hpp
rename to server/zone-provision-config.hpp
diff --git a/server/zone-provision.cpp b/server/zone-provision.cpp
new file mode 100644
index 0000000..3bff4b5
--- /dev/null
+++ b/server/zone-provision.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Mateusz Malicki
+ *
+ * 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
+ * @author Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief Implementation of class for managing zone provsion
+ */
+
+#include "config.hpp"
+
+#include "zone-provision.hpp"
+#include "zone-provision-config.hpp"
+
+#include "logger/logger.hpp"
+#include "utils/fs.hpp"
+#include "utils/exception.hpp"
+#include "config/manager.hpp"
+#include "vasum-client.h"
+
+#include
+
+#include
+#include
+
+namespace fs = boost::filesystem;
+
+namespace vasum {
+
+namespace {
+
+const std::string ZONE_PROVISION_FILE = "provision.conf";
+
+void declareUnit(const std::string& file, ZoneProvisioning::Unit&& unit)
+{
+ // TODO: Add to the dynamic configuration
+ ZoneProvisioning config;
+ if (fs::exists(file)) {
+ config::loadFromFile(file, config);
+ }
+ config.units.push_back(std::move(unit));
+ config::saveToFile(file, config);
+}
+
+} // namespace
+
+ZoneProvision::ZoneProvision(const std::string& zonePath,
+ const std::vector& validLinkPrefixes)
+{
+ mProvisionFile = (fs::path(zonePath) / fs::path(ZONE_PROVISION_FILE)).string();
+ mRootPath = (zonePath / fs::path("rootfs")).string();
+ mValidLinkPrefixes = validLinkPrefixes;
+}
+
+std::string ZoneProvision::getRootPath() const
+{
+ return mRootPath;
+}
+
+
+void ZoneProvision::declareFile(const int32_t& type,
+ const std::string& path,
+ const int32_t& flags,
+ const int32_t& mode)
+{
+ ZoneProvisioning::Unit unit;
+ unit.set(ZoneProvisioning::File({type, path, flags, mode}));
+
+ declareUnit(mProvisionFile, std::move(unit));
+}
+
+void ZoneProvision::declareMount(const std::string& source,
+ const std::string& target,
+ const std::string& type,
+ const int64_t& flags,
+ const std::string& data)
+{
+ ZoneProvisioning::Unit unit;
+ unit.set(ZoneProvisioning::Mount({source, target, type, flags, data}));
+
+ declareUnit(mProvisionFile, std::move(unit));
+}
+
+void ZoneProvision::declareLink(const std::string& source,
+ const std::string& target)
+{
+ ZoneProvisioning::Unit unit;
+ unit.set(ZoneProvisioning::Link({source, target}));
+
+ declareUnit(mProvisionFile, std::move(unit));
+}
+
+void ZoneProvision::start() noexcept
+{
+ if (fs::exists(mProvisionFile)) {
+ config::loadFromFile(mProvisionFile, mProvisioningConfig);
+ for (const auto& unit : mProvisioningConfig.units) {
+ try {
+ if (unit.is()) {
+ file(unit.as());
+ } else if (unit.is()) {
+ mount(unit.as());
+ } else if (unit.is()) {
+ link(unit.as());
+ }
+ } catch (std::exception& ex) {
+ LOGE("Provsion error: " << ex.what());
+ }
+ }
+ }
+}
+
+void ZoneProvision::stop() noexcept
+{
+ for (auto it = mProvisioningConfig.units.rbegin();
+ it != mProvisioningConfig.units.rend();
+ ++it) {
+ if (it->is()) {
+ umount(it->as());
+ }
+ }
+}
+
+void ZoneProvision::file(const ZoneProvisioning::File& config)
+{
+ bool ret = false;
+ const fs::path hostPath = fs::path(mRootPath) / fs::path(config.path);
+ switch (config.type) {
+ case VSMFILE_DIRECTORY:
+ ret = utils::createDirs(hostPath.string(), config.mode);
+ if (!ret) {
+ throw UtilsException("Can't create dir: " + hostPath.string());
+ }
+ break;
+
+ case VSMFILE_FIFO:
+ ret = utils::createFifo(hostPath.string(), config.mode);
+ if (!ret) {
+ throw UtilsException("Failed to make fifo: " + config.path);
+ }
+ break;
+
+ case VSMFILE_REGULAR:
+ if ((config.flags & O_CREAT)) {
+ ret = utils::createFile(hostPath.string(), config.flags, config.mode);
+ if (!ret) {
+ throw UtilsException("Failed to create file: " + config.path);
+ }
+ } else {
+ ret = utils::copyFile(config.path, hostPath.string());
+ if (!ret) {
+ throw UtilsException("Failed to copy file: " + config.path);
+ }
+ }
+ break;
+ }
+}
+
+void ZoneProvision::mount(const ZoneProvisioning::Mount& config)
+{
+ const fs::path hostPath = fs::path(mRootPath) / fs::path(config.target);
+ bool ret = utils::mount(config.source,
+ hostPath.string(),
+ config.type,
+ config.flags,
+ config.data);
+ if (!ret) {
+ throw UtilsException("Mount operation failure - source : " + config.source);
+ }
+}
+
+void ZoneProvision::umount(const ZoneProvisioning::Mount& config)
+{
+ const fs::path hostPath = fs::path(mRootPath) / fs::path(config.target);
+ utils::umount(hostPath.string());
+}
+
+void ZoneProvision::link(const ZoneProvisioning::Link& config)
+{
+ const std::string srcHostPath = fs::path(config.source).normalize().string();
+ for (const std::string& prefix : mValidLinkPrefixes) {
+ if (prefix.length() <= srcHostPath.length()
+ && srcHostPath.compare(0, prefix.length(), prefix) == 0) {
+
+ const fs::path destHostPath = fs::path(mRootPath) / fs::path(config.target);
+ bool ret = utils::createLink(srcHostPath, destHostPath.string());
+ if (!ret) {
+ throw UtilsException("Failed to create hard link: " + config.source);
+ }
+ return;
+ }
+ }
+ LOGE("Failed to create hard link: path=host: "
+ << srcHostPath
+ << ", msg: Path prefix is not valid path");
+ throw UtilsException("Failed to hard link: path prefix is not valid");
+}
+
+} // namespace vasum
diff --git a/server/zone-provision.hpp b/server/zone-provision.hpp
new file mode 100644
index 0000000..d7cc1e4
--- /dev/null
+++ b/server/zone-provision.hpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Mateusz Malicki
+ *
+ * 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
+ * @author Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief Declaration of the class for managing zone provision
+ */
+
+
+#ifndef SERVER_ZONE_PROVISION_HPP
+#define SERVER_ZONE_PROVISION_HPP
+
+#include "zone-provision-config.hpp"
+
+#include
+#include
+
+namespace vasum {
+
+
+/**
+ * Class is responsible for prepare filesystem for zone
+ * It allows to create directories, files, mount points and copying files from host
+ */
+class ZoneProvision {
+
+public:
+ /**
+ * ZoneProvision constructor
+ * @param zonesPath directory where zones are defined (lxc configs, rootfs etc)
+ */
+ ZoneProvision(const std::string& zonePath,
+ const std::vector& validLinkPrefixes);
+
+ /**
+ * Declare file, directory or pipe that will be created while zone startup
+ */
+ void declareFile(const int32_t& type,
+ const std::string& path,
+ const int32_t& flags,
+ const int32_t& mode);
+ /**
+ * Declare mount that will be created while zone startup
+ */
+ void declareMount(const std::string& source,
+ const std::string& target,
+ const std::string& type,
+ const int64_t& flags,
+ const std::string& data);
+ /**
+ * Declare link that will be created while zone startup
+ */
+ void declareLink(const std::string& source,
+ const std::string& target);
+
+ /**
+ * Get zone root path
+ */
+ std::string getRootPath() const;
+
+ void start() noexcept;
+ void stop() noexcept;
+
+private:
+ ZoneProvisioning mProvisioningConfig;
+ std::string mRootPath;
+ std::string mProvisionFile;
+ std::vector mValidLinkPrefixes;
+
+ void mount(const ZoneProvisioning::Mount& config);
+ void umount(const ZoneProvisioning::Mount& config);
+ void file(const ZoneProvisioning::File& config);
+ void link(const ZoneProvisioning::Link& config);
+};
+
+
+} // namespace vasum
+
+#endif // SERVER_ZONE_PROVISION_HPP
diff --git a/server/zone.cpp b/server/zone.cpp
index 199ecff..f6fb188 100644
--- a/server/zone.cpp
+++ b/server/zone.cpp
@@ -26,7 +26,6 @@
#include "zone.hpp"
#include "base-exception.hpp"
-#include "provisioning-config.hpp"
#include "logger/logger.hpp"
#include "utils/paths.hpp"
@@ -38,7 +37,6 @@
#include
#include
-
namespace vasum {
namespace fs = boost::filesystem;
@@ -50,18 +48,6 @@ typedef std::lock_guard Lock;
// TODO: move constants to the config file when default values are implemented there
const int RECONNECT_RETRIES = 15;
const int RECONNECT_DELAY = 1 * 1000;
-const std::string ZONE_PROVISION_FILE = "provision.conf";
-
-void declareUnit(const std::string& file, ZoneProvisioning::Unit&& unit)
-{
- // TODO: Add to the dynamic configuration
- ZoneProvisioning config;
- if (fs::exists(file)) {
- config::loadFromFile(file, config);
- }
- config.units.push_back(std::move(unit));
- config::saveToFile(file, config);
-}
} // namespace
@@ -86,8 +72,8 @@ Zone::Zone(const utils::Worker::Pointer& worker,
}
mAdmin.reset(new ZoneAdmin(zonesPath, lxcTemplatePrefix, mConfig));
- const fs::path baseProvision = fs::path(zonesPath) / mAdmin->getId();
- mProvisionConfig = fs::absolute(ZONE_PROVISION_FILE, baseProvision).string();
+ const fs::path zonePath = fs::path(zonesPath) / mAdmin->getId();
+ mProvision.reset(new ZoneProvision(zonePath.string(), mConfig.validLinkPrefixes));
}
Zone::~Zone()
@@ -123,6 +109,7 @@ int Zone::getPrivilege() const
void Zone::start()
{
Lock lock(mReconnectMutex);
+ mProvision->start();
if (mConfig.enableDbusIntegration) {
mConnectionTransport.reset(new ZoneConnectionTransport(mRunMountPoint));
}
@@ -162,6 +149,7 @@ void Zone::stop()
disconnect();
mAdmin->stop();
mConnectionTransport.reset();
+ mProvision->stop();
}
void Zone::connect()
@@ -211,6 +199,12 @@ int Zone::getVT() const
return mConfig.vt;
}
+std::string Zone::getRootPath() const
+{
+ return mProvision->getRootPath();
+}
+
+
bool Zone::activateVT()
{
Lock lock(mReconnectMutex);
@@ -399,35 +393,26 @@ void Zone::proxyCallAsync(const std::string& busName,
}
void Zone::declareFile(const int32_t& type,
- const std::string& path,
- const int32_t& flags,
- const int32_t& mode)
+ const std::string& path,
+ const int32_t& flags,
+ const int32_t& mode)
{
- ZoneProvisioning::Unit unit;
- unit.set(std::move(ZoneProvisioning::File({type, path, flags, mode})));
-
- declareUnit(mProvisionConfig, std::move(unit));
+ mProvision->declareFile(type, path, flags, mode);
}
void Zone::declareMount(const std::string& source,
- const std::string& target,
- const std::string& type,
- const int64_t& flags,
- const std::string& data)
+ const std::string& target,
+ const std::string& type,
+ const int64_t& flags,
+ const std::string& data)
{
- ZoneProvisioning::Unit unit;
- unit.set(std::move(ZoneProvisioning::Mount({source, target, type, flags, data})));
-
- declareUnit(mProvisionConfig, std::move(unit));
+ mProvision->declareMount(source, target, type, flags, data);
}
void Zone::declareLink(const std::string& source,
- const std::string& target)
+ const std::string& target)
{
- ZoneProvisioning::Unit unit;
- unit.set(std::move(ZoneProvisioning::Link({source, target})));
-
- declareUnit(mProvisionConfig, std::move(unit));
+ mProvision->declareLink(source, target);
}
} // namespace vasum
diff --git a/server/zone.hpp b/server/zone.hpp
index fba9399..dd0daca 100644
--- a/server/zone.hpp
+++ b/server/zone.hpp
@@ -30,6 +30,7 @@
#include "zone-admin.hpp"
#include "zone-connection.hpp"
#include "zone-connection-transport.hpp"
+#include "zone-provision.hpp"
#include "utils/worker.hpp"
#include
@@ -254,6 +255,11 @@ public:
void declareLink(const std::string& source,
const std::string& target);
+ /**
+ * Get zone root path
+ */
+ std::string getRootPath() const;
+
private:
utils::Worker::Pointer mWorker;
ZoneConfig mConfig;
@@ -262,6 +268,7 @@ private:
std::unique_ptr mConnectionTransport;
std::unique_ptr mAdmin;
std::unique_ptr mConnection;
+ std::unique_ptr mProvision;
mutable std::recursive_mutex mReconnectMutex;
NotifyActiveZoneCallback mNotifyCallback;
DisplayOffCallback mDisplayOffCallback;
@@ -270,7 +277,6 @@ private:
DbusStateChangedCallback mDbusStateChangedCallback;
std::string mDbusAddress;
std::string mRunMountPoint;
- std::string mProvisionConfig;
void onNameLostCallback();
void reconnectHandler();
diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp
index eafbe4b..1f9bef0 100644
--- a/server/zones-manager.cpp
+++ b/server/zones-manager.cpp
@@ -628,15 +628,12 @@ void ZonesManager::handleGetZoneInfoCall(const std::string& id,
result->setError(api::ERROR_INTERNAL, "Unrecognized state of zone");
return;
}
- const auto zonePath = boost::filesystem::absolute(id, mConfig.zonesPath);
- const auto rootfsDir = boost::filesystem::path("rootfs");
- const auto rootfsPath = zonePath / rootfsDir;
result->set(g_variant_new("((siss))",
id.c_str(),
zone->getVT(),
state,
- rootfsPath.string().c_str()));
+ zone->getRootPath().c_str()));
}
void ZonesManager::handleDeclareFileCall(const std::string& zone,
diff --git a/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in
index 72fbdbf..46fb716 100644
--- a/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in
+++ b/tests/unit_tests/client/configs/ut-client/zones/console1-dbus.conf.in
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-run/ut-zones-manager-console1-dbus",
"permittedToSend" : [ "/tmp/.*", "/etc/secret2" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in
index 1386878..260d01f 100644
--- a/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in
+++ b/tests/unit_tests/client/configs/ut-client/zones/console2-dbus.conf.in
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-run/ut-zones-manager-console2-dbus",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ]
+ "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in
index f91754f..e20ffe9 100644
--- a/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in
+++ b/tests/unit_tests/client/configs/ut-client/zones/console3-dbus.conf.in
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-run/ut-zones-manager-console3-dbus",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone1.conf b/tests/unit_tests/server/configs/ut-server/zones/zone1.conf
index 898eef2..2c2ccde 100644
--- a/tests/unit_tests/server/configs/ut-server/zones/zone1.conf
+++ b/tests/unit_tests/server/configs/ut-server/zones/zone1.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone2.conf b/tests/unit_tests/server/configs/ut-server/zones/zone2.conf
index 8f4687a..1d500a7 100644
--- a/tests/unit_tests/server/configs/ut-server/zones/zone2.conf
+++ b/tests/unit_tests/server/configs/ut-server/zones/zone2.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-server/zones/zone3.conf b/tests/unit_tests/server/configs/ut-server/zones/zone3.conf
index fdb958f..a9856c7 100644
--- a/tests/unit_tests/server/configs/ut-server/zones/zone3.conf
+++ b/tests/unit_tests/server/configs/ut-server/zones/zone3.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf
index 320dc00..e96dca8 100644
--- a/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf
+++ b/tests/unit_tests/server/configs/ut-zone-admin/zones/buggy.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf
index 9aaf464..9a5ec68 100644
--- a/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf
+++ b/tests/unit_tests/server/configs/ut-zone-admin/zones/missing.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf
index b3b0141..be05697 100644
--- a/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf
+++ b/tests/unit_tests/server/configs/ut-zone-admin/zones/test-no-shutdown.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf b/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf
index ae046e5..45213d7 100644
--- a/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf
+++ b/tests/unit_tests/server/configs/ut-zone-admin/zones/test.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf b/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf
index 55586b4..eaf0811 100644
--- a/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf
+++ b/tests/unit_tests/server/configs/ut-zone/zones/buggy.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in b/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in
index 4f8e6db..e4a18fa 100644
--- a/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in
+++ b/tests/unit_tests/server/configs/ut-zone/zones/test-dbus.conf.in
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-run/ut-zone-test-dbus",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zone/zones/test.conf b/tests/unit_tests/server/configs/ut-zone/zones/test.conf
index a8f9692..4386c8c 100644
--- a/tests/unit_tests/server/configs/ut-zone/zones/test.conf
+++ b/tests/unit_tests/server/configs/ut-zone/zones/test.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [],
- "permittedToRecv" : []
+ "permittedToRecv" : [],
+ "validLinkPrefixes" : [ "/tmp" ]
}
diff --git a/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in
index 15185d6..7c2f5e4 100644
--- a/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in
+++ b/tests/unit_tests/server/configs/ut-zones-manager/templates/template.conf.in
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-run/~NAME~",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in
index 72fbdbf..46fb716 100644
--- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in
+++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1-dbus.conf.in
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-run/ut-zones-manager-console1-dbus",
"permittedToSend" : [ "/tmp/.*", "/etc/secret2" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf
index 3e88c3d..41071ad 100644
--- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf
+++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console1.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in
index 1386878..260d01f 100644
--- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in
+++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2-dbus.conf.in
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-run/ut-zones-manager-console2-dbus",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ]
+ "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf
index 22f7a39..f152092 100644
--- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf
+++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console2.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in
index f91754f..e20ffe9 100644
--- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in
+++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3-dbus.conf.in
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-run/ut-zones-manager-console3-dbus",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf
index 2f99f23..4979dd2 100644
--- a/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf
+++ b/tests/unit_tests/server/configs/ut-zones-manager/zones/console3.conf
@@ -12,5 +12,6 @@
"cpuQuotaBackground" : 1000,
"runMountPoint" : "",
"permittedToSend" : [ "/tmp/.*" ],
- "permittedToRecv" : [ "/tmp/.*" ]
+ "permittedToRecv" : [ "/tmp/.*" ],
+ "validLinkPrefixes" : []
}
diff --git a/tests/unit_tests/server/ut-zone-provision.cpp b/tests/unit_tests/server/ut-zone-provision.cpp
new file mode 100644
index 0000000..6a6e4ef
--- /dev/null
+++ b/tests/unit_tests/server/ut-zone-provision.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Mateusz Malicki
+ *
+ * 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
+ * @author Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief Unit tests of the ZoneProvsion class
+ */
+
+#include "config.hpp"
+#include "ut.hpp"
+
+#include "zone.hpp"
+
+#include "utils/glib-loop.hpp"
+#include "utils/scoped-dir.hpp"
+#include "config/manager.hpp"
+#include "zone-provision-config.hpp"
+#include "vasum-client.h"
+
+#include
+#include
+
+#include
+#include
+#include
+
+using namespace vasum;
+using namespace config;
+
+namespace fs = boost::filesystem;
+
+namespace {
+
+const std::string PROVISON_CONFIG_FILE = "provision.conf";
+const std::string ZONE = "ut-zone-test";
+const fs::path TEST_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone/zones/test.conf";
+const fs::path ZONES_PATH = "/tmp/ut-zones";
+const fs::path LXC_TEMPLATES_PATH = VSM_TEST_LXC_TEMPLATES_INSTALL_DIR;
+const fs::path ZONE_PATH = ZONES_PATH / fs::path(ZONE);
+const fs::path PROVISION_FILE_PATH = ZONE_PATH / fs::path(PROVISON_CONFIG_FILE);
+const fs::path ROOTFS_PATH = ZONE_PATH / fs::path("rootfs");
+
+struct Fixture {
+ utils::ScopedGlibLoop mLoop;
+ utils::ScopedDir mZonesPathGuard;
+ utils::ScopedDir mRunGuard;
+ utils::ScopedDir mRootfsPath;
+
+ Fixture()
+ : mZonesPathGuard(ZONES_PATH.string())
+ , mRunGuard("/tmp/ut-run")
+ , mRootfsPath(ROOTFS_PATH.string())
+ {
+ }
+
+ std::unique_ptr create(const std::string& configPath)
+ {
+ return std::unique_ptr(new Zone(utils::Worker::create(),
+ ZONES_PATH.string(),
+ configPath,
+ LXC_TEMPLATES_PATH.string(),
+ ""));
+ }
+};
+
+} // namespace
+
+
+BOOST_FIXTURE_TEST_SUITE(ZoneProvisionSuite, Fixture)
+
+BOOST_AUTO_TEST_CASE(FileTest)
+{
+ //TODO: Test Fifo
+ const fs::path regularFile = fs::path("/opt/usr/data/ut-regular-file");
+ const fs::path copyFile = PROVISION_FILE_PATH;
+
+ ZoneProvisioning config;
+ ZoneProvisioning::Unit unit;
+ unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY,
+ regularFile.parent_path().string(),
+ 0,
+ 0777}));
+ config.units.push_back(unit);
+
+ unit.set(ZoneProvisioning::File({VSMFILE_REGULAR,
+ regularFile.string(),
+ O_CREAT,
+ 0777}));
+ config.units.push_back(unit);
+
+ unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY,
+ copyFile.parent_path().string(),
+ 0,
+ 0777}));
+ config.units.push_back(unit);
+ unit.set(ZoneProvisioning::File({VSMFILE_REGULAR,
+ copyFile.string(),
+ 0,
+ 0777}));
+ config.units.push_back(unit);
+ config::saveToFile(PROVISION_FILE_PATH.string(), config);
+ auto c = create(TEST_CONFIG_PATH.string());
+ c->start();
+
+ BOOST_CHECK(fs::exists(ROOTFS_PATH / regularFile.parent_path()));
+ BOOST_CHECK(fs::exists(ROOTFS_PATH / regularFile));
+ BOOST_CHECK(fs::exists(ROOTFS_PATH / copyFile.parent_path()));
+ BOOST_CHECK(fs::exists(ROOTFS_PATH / copyFile));
+
+ c->stop();
+}
+
+BOOST_AUTO_TEST_CASE(MountTest)
+{
+ //TODO: Test Fifo
+ const fs::path mountTarget = fs::path("/opt/usr/data/ut-from-host-provision");
+ const fs::path mountSource = fs::path("/tmp/ut-provision");
+ const fs::path sharedFile = fs::path("ut-regular-file");
+
+ utils::ScopedDir provisionfs(mountSource.string());
+
+
+ ZoneProvisioning config;
+ ZoneProvisioning::Unit unit;
+ unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY,
+ mountTarget.string(),
+ 0,
+ 0777}));
+ config.units.push_back(unit);
+ unit.set(ZoneProvisioning::Mount({mountSource.string(),
+ mountTarget.string(),
+ "",
+ MS_BIND,
+ ""}));
+ config.units.push_back(unit);
+ unit.set(ZoneProvisioning::File({VSMFILE_REGULAR,
+ (mountTarget / sharedFile).string(),
+ O_CREAT,
+ 0777}));
+ config.units.push_back(unit);
+
+ config::saveToFile(PROVISION_FILE_PATH.string(), config);
+ auto c = create(TEST_CONFIG_PATH.string());
+ c->start();
+
+ BOOST_CHECK(fs::exists(ROOTFS_PATH / mountTarget));
+ BOOST_CHECK(fs::exists(ROOTFS_PATH / mountTarget / sharedFile));
+ BOOST_CHECK(fs::exists(mountSource / sharedFile));
+
+ c->stop();
+}
+
+BOOST_AUTO_TEST_CASE(LinkTest)
+{
+ const fs::path linkFile = fs::path("/ut-from-host-provision.conf");
+
+ ZoneProvisioning config;
+ ZoneProvisioning::Unit unit;
+
+ unit.set(ZoneProvisioning::Link({PROVISION_FILE_PATH.string(),
+ linkFile.string()}));
+ config.units.push_back(unit);
+ config::saveToFile(PROVISION_FILE_PATH.string(), config);
+ auto c = create(TEST_CONFIG_PATH.string());
+ c->start();
+
+ BOOST_CHECK(fs::exists(ROOTFS_PATH / linkFile));
+
+ c->stop();
+}
+
+BOOST_AUTO_TEST_CASE(DeclareFile)
+{
+ ZoneProvision zoneProvision(ZONE_PATH.string(), {});
+ zoneProvision.declareFile(1, "path", 0747, 0777);
+ zoneProvision.declareFile(2, "path", 0747, 0777);
+
+ ZoneProvisioning config;
+ BOOST_REQUIRE_NO_THROW(loadFromFile(PROVISION_FILE_PATH.string(), config));
+ BOOST_REQUIRE_EQUAL(config.units.size(), 2);
+ BOOST_REQUIRE(config.units[0].is());
+ BOOST_REQUIRE(config.units[1].is());
+ const ZoneProvisioning::File& unit = config.units[0].as();
+ BOOST_CHECK_EQUAL(unit.type, 1);
+ BOOST_CHECK_EQUAL(unit.path, "path");
+ BOOST_CHECK_EQUAL(unit.flags, 0747);
+ BOOST_CHECK_EQUAL(unit.mode, 0777);
+}
+
+BOOST_AUTO_TEST_CASE(DeclareMount)
+{
+ ZoneProvision zoneProvision(ZONE_PATH.string(), {});
+ zoneProvision.declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake");
+ zoneProvision.declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake");
+
+ ZoneProvisioning config;
+ BOOST_REQUIRE_NO_THROW(loadFromFile(PROVISION_FILE_PATH.string(), config));
+ BOOST_REQUIRE_EQUAL(config.units.size(), 2);
+ BOOST_REQUIRE(config.units[0].is());
+ BOOST_REQUIRE(config.units[1].is());
+ const ZoneProvisioning::Mount& unit = config.units[0].as();
+ BOOST_CHECK_EQUAL(unit.source, "/fake/path1");
+ BOOST_CHECK_EQUAL(unit.target, "/fake/path2");
+ BOOST_CHECK_EQUAL(unit.type, "tmpfs");
+ BOOST_CHECK_EQUAL(unit.flags, 077);
+ BOOST_CHECK_EQUAL(unit.data, "fake");
+}
+
+BOOST_AUTO_TEST_CASE(DeclareLink)
+{
+ ZoneProvision zoneProvision(ZONE_PATH.string(), {});
+ zoneProvision.declareLink("/fake/path1", "/fake/path2");
+ zoneProvision.declareLink("/fake/path2", "/fake/path2");
+
+ ZoneProvisioning config;
+ BOOST_REQUIRE_NO_THROW(loadFromFile(PROVISION_FILE_PATH.string(), config));
+ BOOST_REQUIRE_EQUAL(config.units.size(), 2);
+ BOOST_REQUIRE(config.units[0].is());
+ BOOST_REQUIRE(config.units[1].is());
+ const ZoneProvisioning::Link& unit = config.units[0].as();
+ BOOST_CHECK_EQUAL(unit.source, "/fake/path1");
+ BOOST_CHECK_EQUAL(unit.target, "/fake/path2");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp
index 4db9434..3c62478 100644
--- a/tests/unit_tests/server/ut-zones-manager.cpp
+++ b/tests/unit_tests/server/ut-zones-manager.cpp
@@ -27,9 +27,6 @@
#include "ut.hpp"
#include "zones-manager.hpp"
-#include "zones-manager-config.hpp"
-#include "zone-config.hpp"
-#include "provisioning-config.hpp"
#include "zone-dbus-definitions.hpp"
#include "host-dbus-definitions.hpp"
#include "test-dbus-definitions.hpp"
@@ -40,7 +37,6 @@
#include "dbus/connection.hpp"
#include "dbus/exception.hpp"
#include "utils/glib-loop.hpp"
-#include "config/manager.hpp"
#include "config/exception.hpp"
#include "utils/latch.hpp"
#include "utils/fs.hpp"
@@ -82,7 +78,6 @@ const std::string FILE_CONTENT = "File content\n"
"Line 2\n";
const std::string NON_EXISTANT_ZONE_ID = "NON_EXISTANT_ZONE_ID";
const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf
-const std::string PROVISON_CONFIG_FILE = "provision.conf";
class DbusAccessory {
public:
@@ -314,67 +309,6 @@ public:
}
- void callMethodDeclareFile(const std::string& zone,
- const int32_t& type,
- const std::string& path,
- const int32_t& flags,
- const int32_t& mode)
- {
- assert(isHost());
- GVariant* parameters = g_variant_new("(sisii)",
- zone.c_str(),
- type,
- path.c_str(),
- flags,
- mode);
- GVariantPtr result = mClient->callMethod(api::host::BUS_NAME,
- api::host::OBJECT_PATH,
- api::host::INTERFACE,
- api::host::METHOD_DECLARE_FILE,
- parameters,
- "()");
- }
-
- void callMethodDeclareMount(const std::string& source,
- const std::string& zone,
- const std::string& target,
- const std::string& type,
- const uint64_t& flags,
- const std::string& data)
- {
- assert(isHost());
- GVariant* parameters = g_variant_new("(ssssts)",
- source.c_str(),
- zone.c_str(),
- target.c_str(),
- type.c_str(),
- flags,
- data.c_str());
- GVariantPtr result = mClient->callMethod(api::host::BUS_NAME,
- api::host::OBJECT_PATH,
- api::host::INTERFACE,
- api::host::METHOD_DECLARE_MOUNT,
- parameters,
- "()");
- }
-
- void callMethodDeclareLink(const std::string& source,
- const std::string& zone,
- const std::string& target)
- {
- assert(isHost());
- GVariant* parameters = g_variant_new("(sss)",
- source.c_str(),
- zone.c_str(),
- target.c_str());
- GVariantPtr result = mClient->callMethod(api::host::BUS_NAME,
- api::host::OBJECT_PATH,
- api::host::INTERFACE,
- api::host::METHOD_DECLARE_LINK,
- parameters,
- "()");
- }
-
void callAsyncMethodCreateZone(const std::string& id,
const VoidResultCallback& result)
{
@@ -477,26 +411,6 @@ struct Fixture {
{}
};
-std::string getProvisionConfigPath(const std::string& zone)
-{
- namespace fs = boost::filesystem;
- ZonesManagerConfig managerConfig;
- loadFromFile(TEST_CONFIG_PATH, managerConfig);
- for (const auto& zonesPath : managerConfig.zoneConfigs) {
- ZoneConfig zoneConfig;
- const fs::path configConfigPath = fs::absolute(zonesPath,
- fs::path(TEST_CONFIG_PATH).parent_path());
-
- loadFromFile(configConfigPath.string(), zoneConfig);
- if (zoneConfig.name == zone) {
- const fs::path base = fs::path(managerConfig.zonesPath) / fs::path(zone);
- return fs::absolute(PROVISON_CONFIG_FILE, base).string();
- }
- }
- BOOST_FAIL("There is no provision config file for " + zone);
- return std::string();
-}
-
} // namespace
@@ -1093,71 +1007,6 @@ BOOST_AUTO_TEST_CASE(CreateDestroyZoneTest)
BOOST_CHECK_EQUAL(cm.getRunningForegroundZoneId(), "");
}
-BOOST_AUTO_TEST_CASE(DeclareFile)
-{
- const std::string zone = EXPECTED_DBUSES_NO_DBUS.begin()->first;
- const std::string provisionConfigPath = getProvisionConfigPath(zone);
-
- ZonesManager cm(TEST_CONFIG_PATH);
- DbusAccessory dbus(DbusAccessory::HOST_ID);
- dbus.callMethodDeclareFile(zone, 1, "path", 0747, 0777);
- dbus.callMethodDeclareFile(zone, 2, "path", 0747, 0777);
-
- ZoneProvisioning config;
- BOOST_REQUIRE_NO_THROW(loadFromFile(provisionConfigPath, config));
- BOOST_REQUIRE_EQUAL(config.units.size(), 2);
- BOOST_REQUIRE(config.units[0].is());
- BOOST_REQUIRE(config.units[1].is());
- const ZoneProvisioning::File& unit = config.units[0].as();
- BOOST_CHECK_EQUAL(unit.type, 1);
- BOOST_CHECK_EQUAL(unit.path, "path");
- BOOST_CHECK_EQUAL(unit.flags, 0747);
- BOOST_CHECK_EQUAL(unit.mode, 0777);
-}
-
-BOOST_AUTO_TEST_CASE(DeclareMount)
-{
- const std::string zone = EXPECTED_DBUSES_NO_DBUS.begin()->first;
- const std::string provisionConfigPath = getProvisionConfigPath(zone);
-
- ZonesManager cm(TEST_CONFIG_PATH);
- DbusAccessory dbus(DbusAccessory::HOST_ID);
- dbus.callMethodDeclareMount("/fake/path1", zone, "/fake/path2", "tmpfs", 077, "fake");
- dbus.callMethodDeclareMount("/fake/path2", zone, "/fake/path2", "tmpfs", 077, "fake");
-
- ZoneProvisioning config;
- BOOST_REQUIRE_NO_THROW(loadFromFile(provisionConfigPath, config));
- BOOST_REQUIRE_EQUAL(config.units.size(), 2);
- BOOST_REQUIRE(config.units[0].is());
- BOOST_REQUIRE(config.units[1].is());
- const ZoneProvisioning::Mount& unit = config.units[0].as();
- BOOST_CHECK_EQUAL(unit.source, "/fake/path1");
- BOOST_CHECK_EQUAL(unit.target, "/fake/path2");
- BOOST_CHECK_EQUAL(unit.type, "tmpfs");
- BOOST_CHECK_EQUAL(unit.flags, 077);
- BOOST_CHECK_EQUAL(unit.data, "fake");
-}
-
-BOOST_AUTO_TEST_CASE(DeclareLink)
-{
- const std::string zone = EXPECTED_DBUSES_NO_DBUS.begin()->first;
- const std::string provisionConfigPath = getProvisionConfigPath(zone);
-
- ZonesManager cm(TEST_CONFIG_PATH);
- DbusAccessory dbus(DbusAccessory::HOST_ID);
- dbus.callMethodDeclareLink("/fake/path1", zone, "/fake/path2");
- dbus.callMethodDeclareLink("/fake/path2", zone, "/fake/path2");
-
- ZoneProvisioning config;
- BOOST_REQUIRE_NO_THROW(loadFromFile(provisionConfigPath, config));
- BOOST_REQUIRE_EQUAL(config.units.size(), 2);
- BOOST_REQUIRE(config.units[0].is());
- BOOST_REQUIRE(config.units[1].is());
- const ZoneProvisioning::Link& unit = config.units[0].as();
- BOOST_CHECK_EQUAL(unit.source, "/fake/path1");
- BOOST_CHECK_EQUAL(unit.target, "/fake/path2");
-}
-
BOOST_AUTO_TEST_CASE(LockUnlockZoneTest)
{
ZonesManager cm(TEST_DBUS_CONFIG_PATH);
diff --git a/zone-daemon/CMakeLists.txt b/zone-daemon/CMakeLists.txt
index 3fd611f..50bfa1a 100644
--- a/zone-daemon/CMakeLists.txt
+++ b/zone-daemon/CMakeLists.txt
@@ -22,7 +22,8 @@ MESSAGE(STATUS "Generating makefile for the Zone Daemon...")
FILE(GLOB project_SRCS *.cpp *.hpp)
FILE(GLOB common_SRCS ${COMMON_FOLDER}/dbus/*.cpp ${COMMON_FOLDER}/dbus/*.hpp
${COMMON_FOLDER}/log/*.cpp ${COMMON_FOLDER}/log/*.hpp
- ${COMMON_FOLDER}/utils/*.cpp ${COMMON_FOLDER}/utils/*.hpp)
+ ${COMMON_FOLDER}/utils/*.cpp ${COMMON_FOLDER}/utils/*.hpp
+ ${COMMON_FOLDER}/*.cpp)
## Setup target ################################################################
SET(ZONE_DAEMON_CODENAME "${PROJECT_NAME}-zone-daemon")
--
2.7.4
From 719daa453260d4cbcad85d0e6dbfd2434b779625 Mon Sep 17 00:00:00 2001
From: Krzysztof Dynowski
Date: Sat, 6 Dec 2014 13:05:46 +0100
Subject: [PATCH 14/16] config (dynamic): unit tests, test config extracted
[Bug/Feature] test loading config defaults from json
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: Ia9ad29af5e343642d9ca7ae26b126c3efe45beab
---
tests/unit_tests/config/testconfig-example.hpp | 151 +++++++++++++++++++++++++
tests/unit_tests/config/ut-configuration.cpp | 122 +-------------------
tests/unit_tests/config/ut-dynvisit.cpp | 100 ++++++++++++++++
3 files changed, 252 insertions(+), 121 deletions(-)
create mode 100644 tests/unit_tests/config/testconfig-example.hpp
create mode 100644 tests/unit_tests/config/ut-dynvisit.cpp
diff --git a/tests/unit_tests/config/testconfig-example.hpp b/tests/unit_tests/config/testconfig-example.hpp
new file mode 100644
index 0000000..35e846e
--- /dev/null
+++ b/tests/unit_tests/config/testconfig-example.hpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Krzysztof Dynowski (k.dynowski@samsumg.com)
+ *
+ * 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
+ * @author Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief Test configuration struct to be used in unit tests
+ */
+
+#ifndef TESTCONFIG_EXAMPLE_HPP
+#define TESTCONFIG_EXAMPLE_HPP
+
+#include "config/fields.hpp"
+#include "config/fields-union.hpp"
+
+struct TestConfig {
+ // subtree class
+ struct SubConfig {
+
+ struct SubSubConfig {
+ int intVal;
+ bool moved;
+
+ CONFIG_REGISTER
+ (
+ intVal
+ )
+ SubSubConfig() : intVal(), moved(false) {}
+ SubSubConfig(const SubSubConfig& config) : intVal(config.intVal), moved(false) {}
+ SubSubConfig(SubSubConfig&& config) : intVal(std::move(config.intVal)), moved(false) {
+ config.moved = true;
+ }
+ SubSubConfig& operator=(const SubSubConfig& config) {
+ intVal = config.intVal;
+ moved = false;
+ return *this;
+ }
+ SubSubConfig& operator=(SubSubConfig&& config) {
+ intVal = std::move(config.intVal);
+ moved = false;
+ config.moved = true;
+ return *this;
+ }
+ bool isMoved() const {
+ return moved;
+ }
+ };
+
+ int intVal;
+ std::vector intVector;
+ SubSubConfig subSubObj;
+
+ CONFIG_REGISTER
+ (
+ intVal,
+ intVector,
+ subSubObj
+ )
+ };
+
+ struct SubConfigOption {
+ CONFIG_DECLARE_UNION
+ (
+ SubConfig,
+ int
+ )
+ };
+
+ int intVal;
+ std::int64_t int64Val;
+ std::string stringVal;
+ double doubleVal;
+ bool boolVal;
+
+ std::vector emptyIntVector;
+ std::vector intVector;
+ std::vector stringVector;
+ std::vector doubleVector;
+
+ SubConfig subObj;
+ std::vector