From 2a642703696fa9d3390c18ccd58325cae56e62fb Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Tue, 21 Oct 2014 15:32:06 +0200
Subject: [PATCH 01/16] Fix missing package dependency
[Bug/Feature] Test package require python-xml for working.
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests.
Change-Id: I08774f20115dfd4d4ab18a65dd4ac395fb6322ce
---
packaging/security-containers.spec | 1 +
1 file changed, 1 insertion(+)
diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec
index 137f02b..00a05a6 100644
--- a/packaging/security-containers.spec
+++ b/packaging/security-containers.spec
@@ -207,6 +207,7 @@ Group: Development/Libraries
Requires: security-containers = %{version}-%{release}
Requires: security-containers-client = %{version}-%{release}
Requires: python
+Requires: python-xml
Requires: boost-test
%description tests
--
2.7.4
From 0533ba4677d802d3821e04eb6756d76180994843 Mon Sep 17 00:00:00 2001
From: Lukasz Kostyra
Date: Tue, 14 Oct 2014 10:00:49 +0200
Subject: [PATCH 02/16] Fix issue with permissions when copying dir contents
[Bug] Permission denied error when trying to copy read-only directories recursively.
[Cause] boost::filesystem::copy applied permissions immediately, which in some cases caused
error when trying to write something inside processed directory.
[Solution] Instead of using boost::filesystem::copy on directories, split action into three
sub-actions:
* Create new directory with boost::filesystem::create_directory
* Call copyDirContentsRec() to copy contents of processed directory
* Apply source directory permissions and ownership
[Verification] Build, install, run tests.
Change-Id: Ifdec110a595dcecd113abf4065dd1cdc03f2d3cb
---
common/utils/fs.cpp | 52 +++++++++++++++++++++++++++-------------
server/server.cpp | 5 +++-
tests/unit_tests/utils/ut-fs.cpp | 35 ++++++++++++++++++++++++++-
3 files changed, 73 insertions(+), 19 deletions(-)
diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp
index a03c139..8a6441c 100644
--- a/common/utils/fs.cpp
+++ b/common/utils/fs.cpp
@@ -208,38 +208,56 @@ bool copyDirContentsRec(const boost::filesystem::path& src, const boost::filesys
namespace fs = boost::filesystem;
// TODO: Right now this function skips files which produce error when copying. Errors show up
- // when:
- // a) fs::directory_iterator file(src) is created
- // b) fs::copy(...) is called
- // In both cases lack of permissions is the issue.
+ // when fs::directory_iterator file(src) is created - lack of permissions is the issue.
//
- // In a) case we can't do much - SCS won't be able to read the directory and its contents. Such
- // directories are not common in the filesystem, so they *probably* can be skipped.
- //
- // In b) case multiple directories have too strict permissions to be directly copied. This
- // is a problem for some files crucial to container launch (ex. we cannot copy
- // /usr/lib/systemd/systemd because /usr/lib has 555 permissions).
- // To fix b) issue, copying must be done in two steps:
- // 1. Copy file contents without permissions (this probably can be achieved by opening two
- // files in-code with fstream and programatically copying data from one file to another).
- // 2. Apply all available file attributes from source (permissions, owner UID/GID, xattrs...)
+ // To fix lack of permissions, copying must be done as root. The easiest way would be to launch
+ // copyDirContents after fork() and setuid(0).
try {
for (fs::directory_iterator file(src);
file != fs::directory_iterator();
++file) {
fs::path current(file->path());
+ fs::path destination = dst / current.filename();
boost::system::error_code ec;
- fs::copy(current, dst / current.filename(), ec);
- if(ec.value() != boost::system::errc::success) {
+
+ if (!fs::is_symlink(current) && fs::is_directory(current)) {
+ fs::create_directory(destination, ec);
+ } else {
+ fs::copy(current, destination, ec);
+ }
+
+ if (ec.value() != boost::system::errc::success) {
LOGW("Failed to copy " << current << ": " << ec.message());
+ continue;
}
if (!fs::is_symlink(current) && fs::is_directory(current)) {
- if (!copyDirContentsRec(current, dst / current.filename())) {
+ if (!copyDirContentsRec(current, destination)) {
return false;
}
+
+ // apply permissions coming from source file/directory
+ fs::file_status stat = status(current);
+ fs::permissions(destination, stat.permissions(), ec);
+
+ if (ec.value() != boost::system::errc::success) {
+ LOGW("Failed to set permissions for " << destination << ": " << ec.message());
+ }
+ }
+
+ // change owner
+ struct stat info;
+ ::stat(current.string().c_str(), &info);
+ if (fs::is_symlink(destination)) {
+ if (::lchown(destination.string().c_str(), info.st_uid, info.st_gid) < 0) {
+ LOGW("Failed to change owner of symlink " << destination.string() << ": " << strerror(errno));
+ }
+ } else {
+ if (::chown(destination.string().c_str(), info.st_uid, info.st_gid) < 0) {
+ LOGW("Failed to change owner of file " << destination.string() << ": " << strerror(errno));
+ }
}
}
} catch (fs::filesystem_error& e) {
diff --git a/server/server.cpp b/server/server.cpp
index a9ad444..7b03f4c 100644
--- a/server/server.cpp
+++ b/server/server.cpp
@@ -202,9 +202,12 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot)
// is introduced. The capability is needed to allow modify SMACK labels of
// "/var/run/containers//run" mount point.
// CAP_SYS_TTY_CONFIG is needed to activate virtual terminals through ioctl calls
+ // CAP_CHOWN is needed when creating new container from image to set owner/group for each file,
+ // directory or symlink
return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN,
CAP_MAC_OVERRIDE,
- CAP_SYS_TTY_CONFIG}));
+ CAP_SYS_TTY_CONFIG,
+ CAP_CHOWN}));
}
diff --git a/tests/unit_tests/utils/ut-fs.cpp b/tests/unit_tests/utils/ut-fs.cpp
index 43be58a..a1eea40 100644
--- a/tests/unit_tests/utils/ut-fs.cpp
+++ b/tests/unit_tests/utils/ut-fs.cpp
@@ -64,6 +64,8 @@ const std::string FILE_DIR_RANDOM_2 =
boost::filesystem::unique_path("testDir-%%%%").string();
const std::string FILE_DIR_RANDOM_3 =
boost::filesystem::unique_path("testDir-%%%%").string();
+const std::string FILE_DIR_RANDOM_4 =
+ boost::filesystem::unique_path("testDir-%%%%").string();
const std::string FILE_NAME_RANDOM_1 =
boost::filesystem::unique_path("testFile-%%%%").string();
const std::string FILE_NAME_RANDOM_2 =
@@ -146,25 +148,47 @@ BOOST_AUTO_TEST_CASE(MoveFileTest)
BOOST_AUTO_TEST_CASE(CopyDirContentsTest)
{
namespace fs = boost::filesystem;
- std::string src, src_inner, dst, dst_inner;
+ std::string src, src_inner, src_inner2, dst, dst_inner, dst_inner2;
boost::system::error_code ec;
src = TMP_PATH + "/" + FILE_DIR_RANDOM_1;
src_inner = src + "/" + FILE_DIR_RANDOM_3;
+ src_inner2 = src + "/" + FILE_DIR_RANDOM_4;
dst = TMP_PATH + "/" + FILE_DIR_RANDOM_2;
dst_inner = dst + "/" + FILE_DIR_RANDOM_3;
+ dst_inner2 = dst + "/" + FILE_DIR_RANDOM_4;
+
+ // template dir structure:
+ // |-src
+ // |-FILE_NAME_RANDOM_1
+ // |-FILE_NAME_RANDOM_2
+ // |-src_inner (rw directory)
+ // | |-FILE_NAME_RANDOM_1
+ // |
+ // |-src_inner2 (ro directory)
+ // |-FILE_NAME_RANDOM_1
+ // |-FILE_NAME_RANDOM_2
// create entire structure with files
BOOST_REQUIRE(fs::create_directory(src, ec));
BOOST_REQUIRE(ec.value() == 0);
BOOST_REQUIRE(fs::create_directory(src_inner, ec));
BOOST_REQUIRE(ec.value() == 0);
+ BOOST_REQUIRE(fs::create_directory(src_inner2, ec));
+ BOOST_REQUIRE(ec.value() == 0);
BOOST_REQUIRE(saveFileContent(src + "/" + FILE_NAME_RANDOM_1, FILE_CONTENT));
BOOST_REQUIRE(saveFileContent(src + "/" + FILE_NAME_RANDOM_2, FILE_CONTENT_2));
BOOST_REQUIRE(saveFileContent(src_inner + "/" + FILE_NAME_RANDOM_1, FILE_CONTENT_3));
+ BOOST_REQUIRE(saveFileContent(src_inner2 + "/" + FILE_NAME_RANDOM_1, FILE_CONTENT_3));
+ BOOST_REQUIRE(saveFileContent(src_inner2 + "/" + FILE_NAME_RANDOM_2, FILE_CONTENT_2));
+ // change permissions of src_inner2 directory
+ fs::permissions(src_inner2, fs::owner_read, ec);
+ BOOST_REQUIRE(ec.value() == 0);
+
+ // create dst directory
BOOST_REQUIRE(fs::create_directory(dst, ec));
BOOST_REQUIRE(ec.value() == 0);
@@ -176,10 +200,19 @@ BOOST_AUTO_TEST_CASE(CopyDirContentsTest)
BOOST_CHECK(fs::exists(dst + "/" + FILE_NAME_RANDOM_2));
BOOST_CHECK(fs::exists(dst_inner));
BOOST_CHECK(fs::exists(dst_inner + "/" + FILE_NAME_RANDOM_1));
+ BOOST_CHECK(fs::exists(dst_inner2));
+ BOOST_CHECK(fs::exists(dst_inner2 + "/" + FILE_NAME_RANDOM_1));
+ BOOST_CHECK(fs::exists(dst_inner2 + "/" + FILE_NAME_RANDOM_2));
BOOST_CHECK_EQUAL(readFileContent(dst + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT);
BOOST_CHECK_EQUAL(readFileContent(dst + "/" + FILE_NAME_RANDOM_2), FILE_CONTENT_2);
BOOST_CHECK_EQUAL(readFileContent(dst_inner + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT_3);
+ BOOST_CHECK_EQUAL(readFileContent(dst_inner2 + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT_3);
+ BOOST_CHECK_EQUAL(readFileContent(dst_inner2 + "/" + FILE_NAME_RANDOM_2), FILE_CONTENT_2);
+
+ fs::file_status st;
+ BOOST_REQUIRE_NO_THROW(st = fs::status(fs::path(dst_inner2)));
+ BOOST_CHECK(fs::owner_read == st.permissions());
}
BOOST_AUTO_TEST_SUITE_END()
--
2.7.4
From 46bf0c683aad2818f119c275042d39e8d7dcb19b Mon Sep 17 00:00:00 2001
From: Lukasz Kostyra
Date: Thu, 16 Oct 2014 14:44:52 +0200
Subject: [PATCH 03/16] Add launchAsRoot and use it when adding new container
[Feature] Function launchAsRoot.
[Cause] Some functions need to be launched as root.
[Solution] Add launchAsRoot which forks, sets UID to 0 and then calls a function.
[Verification] Build, install, run tests. Add new container - no copying errors should occur.
Change-Id: Iaf917108ea4c7c699d9f2d69c8100430daa4f9c4
---
common/utils/environment.cpp | 39 +++++++++++++++++++++++++++++++++++++++
common/utils/environment.hpp | 8 ++++++++
common/utils/fs.cpp | 6 ------
server/containers-manager.cpp | 13 +++++++++----
server/server.cpp | 4 +++-
5 files changed, 59 insertions(+), 11 deletions(-)
diff --git a/common/utils/environment.cpp b/common/utils/environment.cpp
index 70ef27c..eaaef12 100644
--- a/common/utils/environment.cpp
+++ b/common/utils/environment.cpp
@@ -30,6 +30,8 @@
#include
#include
#include
+#include
+#include
#include
@@ -82,6 +84,43 @@ bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps)
return true;
}
+bool launchAsRoot(const std::function& func)
+{
+ pid_t pid = fork();
+ if (pid < 0) {
+ LOGE("Fork failed: " << strerror(errno));
+ return false;
+ }
+
+ if (pid == 0) {
+ if (::setuid(0) < 0) {
+ LOGW("Failed to become root: " << strerror(errno));
+ ::exit(EXIT_FAILURE);
+ }
+
+ try {
+ func();
+ } catch (std::exception& e) {
+ LOGE("Failed to successfully execute func: " << e.what());
+ ::exit(EXIT_FAILURE);
+ }
+
+ ::exit(EXIT_SUCCESS);
+ }
+
+ int result;
+ if (::waitpid(pid, &result, 0) < 0) {
+ LOGE("waitpid failed: " << strerror(errno));
+ return false;
+ }
+ if (result != 0) {
+ LOGE("Function launched as root failed with result " << result);
+ return false;
+ }
+
+ return true;
+}
+
} // namespace utils
} // namespace security_containers
diff --git a/common/utils/environment.hpp b/common/utils/environment.hpp
index b62189b..120b6ac 100644
--- a/common/utils/environment.hpp
+++ b/common/utils/environment.hpp
@@ -27,6 +27,7 @@
#include
#include
+#include
#include
@@ -44,6 +45,13 @@ bool setSuppGroups(const std::vector& groups);
*/
bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps);
+/**
+ * Launch func as root user.
+ *
+ * This function forks, sets UID 0 to child process and calls func.
+ */
+bool launchAsRoot(const std::function& func);
+
} // namespace utils
} // namespace security_containers
diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp
index 8a6441c..660db9f 100644
--- a/common/utils/fs.cpp
+++ b/common/utils/fs.cpp
@@ -207,12 +207,6 @@ bool copyDirContentsRec(const boost::filesystem::path& src, const boost::filesys
{
namespace fs = boost::filesystem;
- // TODO: Right now this function skips files which produce error when copying. Errors show up
- // when fs::directory_iterator file(src) is created - lack of permissions is the issue.
- //
- // To fix lack of permissions, copying must be done as root. The easiest way would be to launch
- // copyDirContents after fork() and setuid(0).
-
try {
for (fs::directory_iterator file(src);
file != fs::directory_iterator();
diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp
index c9c7ff8..82be28d 100644
--- a/server/containers-manager.cpp
+++ b/server/containers-manager.cpp
@@ -37,6 +37,7 @@
#include "dbus/exception.hpp"
#include "utils/fs.hpp"
#include "utils/img.hpp"
+#include "utils/environment.hpp"
#include
#include
@@ -591,7 +592,11 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
// copy container image if config contains path to image
LOGT("image path: " << mConfig.containerImagePath);
if (!mConfig.containerImagePath.empty()) {
- if (!utils::copyImageContents(mConfig.containerImagePath, containerPathStr)) {
+ auto copyImageContentsWrapper = std::bind(&utils::copyImageContents,
+ mConfig.containerImagePath,
+ containerPathStr);
+
+ if (!utils::launchAsRoot(copyImageContentsWrapper)) {
LOGE("Failed to copy container image.");
result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
"Failed to copy container image.");
@@ -636,7 +641,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
generateNewConfig(id, libvirtNetworkFilterPath, newLibvirtNetworkFilterPath);
} catch (SecurityContainersException& e) {
LOGE(e.what());
- removeAllWrapper(containerPathStr);
+ utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr));
result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what());
return;
}
@@ -646,7 +651,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
addContainer(newConfigPath);
} catch (SecurityContainersException& e) {
LOGE(e.what());
- removeAllWrapper(containerPathStr);
+ utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr));
result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what());
return;
}
@@ -656,7 +661,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
result->setVoid();
} else {
LOGE("Failed to start container.");
- removeAllWrapper(containerPathStr);
+ utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr));
result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
"Failed to start container.");
}
diff --git a/server/server.cpp b/server/server.cpp
index 7b03f4c..f477f0a 100644
--- a/server/server.cpp
+++ b/server/server.cpp
@@ -204,10 +204,12 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot)
// CAP_SYS_TTY_CONFIG is needed to activate virtual terminals through ioctl calls
// CAP_CHOWN is needed when creating new container from image to set owner/group for each file,
// directory or symlink
+ // CAP_SETUID is needed to launch specific funtions as root (see environment.cpp)
return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN,
CAP_MAC_OVERRIDE,
CAP_SYS_TTY_CONFIG,
- CAP_CHOWN}));
+ CAP_CHOWN,
+ CAP_SETUID}));
}
--
2.7.4
From e34356ee58cea135d0396e4b1218f11a44dc0216 Mon Sep 17 00:00:00 2001
From: Lukasz Kostyra
Date: Mon, 20 Oct 2014 14:00:32 +0200
Subject: [PATCH 04/16] Improvements to SCS API
[Bug] * removeAllWrapper caught wrong type of exception
* AddContainer did not focus container after adding
* getActiveContainerId segfaulted when no container was present
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests.
Change-Id: I6bc665952c0f0c515c3aa548bdd6165b2ee7d55b
---
server/containers-manager.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp
index 82be28d..a707fe2 100644
--- a/server/containers-manager.cpp
+++ b/server/containers-manager.cpp
@@ -490,7 +490,7 @@ void ContainersManager::handleGetContainerIdsCall(dbus::MethodResultBuilder::Poi
void ContainersManager::handleGetActiveContainerIdCall(dbus::MethodResultBuilder::Pointer result)
{
LOGI("GetActiveContainerId call");
- if (mContainers[mConfig.foregroundId]->isRunning()){
+ if (!mConfig.foregroundId.empty() && mContainers[mConfig.foregroundId]->isRunning()){
result->set(g_variant_new("(s)", mConfig.foregroundId.c_str()));
} else {
result->set(g_variant_new("(s)", ""));
@@ -622,7 +622,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
try {
LOGD("Removing copied data");
fs::remove_all(fs::path(path));
- } catch(const boost::exception& e) {
+ } catch(const std::exception& e) {
LOGW("Failed to remove data: " << boost::diagnostic_information(e));
}
};
@@ -656,8 +656,9 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
return;
}
- auto resultCallback = [result, containerPathStr, removeAllWrapper](bool succeeded) {
+ auto resultCallback = [this, id, result, containerPathStr, removeAllWrapper](bool succeeded) {
if (succeeded) {
+ focus(id);
result->setVoid();
} else {
LOGE("Failed to start container.");
--
2.7.4
From 068abbdef3718ccd0b142eab2439134975cdd16e Mon Sep 17 00:00:00 2001
From: Lukasz Kostyra
Date: Thu, 23 Oct 2014 13:31:30 +0200
Subject: [PATCH 05/16] Handle empty container name in AddContainer API
[Bug] AddContainer API did not handle the case when container id was empty.
[Cause] N/A
[Solution] N/A
[Verification] Build, install, try adding a container with empty string as name.
Change-Id: I9340e56c58070c5b4c7aa1a0e4d7c2f5ea9c3aa6
---
server/containers-manager.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp
index a707fe2..d0d0a36 100644
--- a/server/containers-manager.cpp
+++ b/server/containers-manager.cpp
@@ -572,6 +572,13 @@ void ContainersManager::generateNewConfig(const std::string& id,
void ContainersManager::handleAddContainerCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result)
{
+ if (id.empty()) {
+ LOGE("Failed to add container - invalid name.");
+ result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
+ "Failed to add container - invalid name.");
+ return;
+ }
+
LOGI("Adding container " << id);
// TODO: This solution is temporary. It utilizes direct access to config files when creating new
--
2.7.4
From 17ebae30eab7530460afee437b56c8ef59e8e0b5 Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Mon, 20 Oct 2014 09:34:33 +0200
Subject: [PATCH 06/16] Added sc_add_container to security-container's client
[Feature] Ability to add container through SCS client
[Cause] Cli need this
[Solution] Add sc_add_container client function
[Verification] Build, install, run Client/AddContainerTest test
Change-Id: Ie0179cb02bdf1946fb9f8d2fd2f3c303cda401fe
---
client/security-containers-client-impl.cpp | 8 ++++++++
client/security-containers-client-impl.hpp | 5 +++++
client/security-containers-client.cpp | 5 +++++
client/security-containers-client.h | 9 +++++++++
tests/unit_tests/client/ut-client.cpp | 12 ++++++++++++
5 files changed, 39 insertions(+)
diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp
index a2c51ba..95418b9 100644
--- a/client/security-containers-client-impl.cpp
+++ b/client/security-containers-client-impl.cpp
@@ -353,6 +353,14 @@ ScStatus Client::sc_set_active_container(const char* id) noexcept
return callMethod(HOST_INTERFACE, api::host::METHOD_SET_ACTIVE_CONTAINER, args_in);
}
+ScStatus Client::sc_add_container(const char* id) noexcept
+{
+ assert(id);
+
+ GVariant* args_in = g_variant_new("(s)", id);
+ return callMethod(HOST_INTERFACE, api::host::METHOD_ADD_CONTAINER, args_in);
+}
+
ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback,
void* data) noexcept
{
diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp
index f1bfacb..3f5a556 100644
--- a/client/security-containers-client-impl.hpp
+++ b/client/security-containers-client-impl.hpp
@@ -127,6 +127,11 @@ public:
ScStatus sc_set_active_container(const char* id) noexcept;
/**
+ * @see ::sc_add_container
+ */
+ ScStatus sc_add_container(const char* id) noexcept;
+
+ /**
* @see ::sc_container_dbus_state
*/
ScStatus sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback,
diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp
index cb22544..95c2758 100644
--- a/client/security-containers-client.cpp
+++ b/client/security-containers-client.cpp
@@ -131,6 +131,11 @@ API ScStatus sc_set_active_container(ScClient client, const char* id)
return getClient(client).sc_set_active_container(id);
}
+API ScStatus sc_add_container(ScClient client, const char* id)
+{
+ return getClient(client).sc_add_container(id);
+}
+
API ScStatus sc_container_dbus_state(ScClient client,
ScContainerDbusStateCallback containerDbusStateCallback,
void* data)
diff --git a/client/security-containers-client.h b/client/security-containers-client.h
index 4d37c3c..1307cb5 100644
--- a/client/security-containers-client.h
+++ b/client/security-containers-client.h
@@ -267,6 +267,15 @@ ScStatus sc_get_container_id_by_pid(ScClient client, int pid, ScString* id);
ScStatus sc_set_active_container(ScClient client, const char* id);
/**
+ * Create and add container
+ *
+ * @param[in] client security-containers-server's client
+ * @param[in] id container id
+ * @return status of this function call
+ */
+ScStatus sc_add_container(ScClient client, const char* id);
+
+/**
* Register dbus state change callback function.
*
* @note The callback function will be invoked on a different thread.
diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp
index 574be39..5db6962 100644
--- a/tests/unit_tests/client/ut-client.cpp
+++ b/tests/unit_tests/client/ut-client.cpp
@@ -188,6 +188,18 @@ BOOST_AUTO_TEST_CASE(SetActiveContainerTest)
sc_client_free(client);
}
+BOOST_AUTO_TEST_CASE(AddContainerTest)
+{
+ const std::string newActiveContainerId = "";
+
+ ScClient client = sc_client_create();
+ ScStatus status = sc_connect(client);
+ BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ status = sc_add_container(client, newActiveContainerId.c_str());
+ BOOST_REQUIRE_EQUAL(SCCLIENT_CUSTOM_ERROR, status);
+ sc_client_free(client);
+}
+
BOOST_AUTO_TEST_CASE(FileMoveRequestTest)
{
const std::string path = "/tmp/fake_path";
--
2.7.4
From 69db805a5ca63b93cb41a4773bdc894444ec52df Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Mon, 20 Oct 2014 10:14:42 +0200
Subject: [PATCH 07/16] Added add_container to cli
[Feature] Ability to add container through cli
[Cause] The need for the ability to add containers
[Solution] Add add_container cli function
[Verification] Build, install, run add container
Change-Id: I020bddaa3707f0e84227a35a85d0905fbb81d6be
---
cli/command-line-interface.cpp | 11 +++++++++++
cli/command-line-interface.hpp | 7 +++++++
cli/main.cpp | 6 ++++++
3 files changed, 24 insertions(+)
diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp
index 02c867f..a7b7aed 100644
--- a/cli/command-line-interface.cpp
+++ b/cli/command-line-interface.cpp
@@ -111,5 +111,16 @@ void set_active_container(int pos, int argc, const char** argv)
one_shot(bind(sc_set_active_container, _1, argv[pos + 1]));
}
+void add_container(int pos, int argc, const char** argv)
+{
+ using namespace std::placeholders;
+
+ if (argc <= pos + 1) {
+ throw runtime_error("Not enough parameters");
+ }
+
+ one_shot(bind(sc_add_container, _1, argv[pos + 1]));
+}
+
} // namespace cli
} // namespace security_containers
diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp
index c193068..d9fc39f 100644
--- a/cli/command-line-interface.hpp
+++ b/cli/command-line-interface.hpp
@@ -103,6 +103,13 @@ private:
*/
void set_active_container(int pos, int argc, const char** argv);
+/**
+ * Parses command line arguments and call sc_add_container
+ *
+ * @see sc_add_container
+ */
+void add_container(int pos, int argc, const char** argv);
+
} // namespace cli
} // namespace security_containers
diff --git a/cli/main.cpp b/cli/main.cpp
index e74f620..d84d5ac 100644
--- a/cli/main.cpp
+++ b/cli/main.cpp
@@ -38,6 +38,12 @@ std::map commands = {
"set_active_container container_id",
"Set active (foreground) container",
{{"container_id", "id container name"}}}
+ },
+ {"add_container", {
+ add_container,
+ "add_container container_id",
+ "Create and add container",
+ {{"container_id", "id container name"}}}
}
};
--
2.7.4
From 0ecba0804c632022b45655a3f168834327685a1d Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Thu, 6 Nov 2014 18:31:58 +0100
Subject: [PATCH 08/16] Rename cli, client library and client test functions
[Feature] Brave New Name
[Cause] New name of SCS
[Solution] Rename:
* sc_ -> vsm_
* Sc -> Vsm,
* SC -> VSM,
* container_dbus_state -> add_state_callback,
* get_container_id_by_pid -> lookup_domain_by_pid,
* get_container_ids -> get_domain_ids
[Verification] Compile
Change-Id: Icaffebaa5e7a0e9d5869a9d2ec701bf385e99529
---
cli/command-line-interface.cpp | 34 ++---
cli/command-line-interface.hpp | 16 +--
cli/main.cpp | 26 ++--
client/security-containers-client-impl.cpp | 161 ++++++++++++------------
client/security-containers-client-impl.hpp | 80 ++++++------
client/security-containers-client.cpp | 84 ++++++-------
client/security-containers-client.h | 120 +++++++++---------
tests/unit_tests/client/ut-client.cpp | 194 +++++++++++++++--------------
8 files changed, 366 insertions(+), 349 deletions(-)
diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp
index a7b7aed..8af17a7 100644
--- a/cli/command-line-interface.cpp
+++ b/cli/command-line-interface.cpp
@@ -39,42 +39,42 @@ namespace cli {
namespace {
/**
- * Invoke specific function on ScClient
+ * Invoke specific function on VsmClient
*
* @param fun Function to be called. It must not throw any exception.
*/
-void one_shot(const function& fun)
+void one_shot(const function& fun)
{
string msg;
- ScStatus status;
- ScClient client;
+ VsmStatus status;
+ VsmClient client;
- status = sc_start_glib_loop();
- if (SCCLIENT_SUCCESS != status) {
+ status = vsm_start_glib_loop();
+ if (VSMCLIENT_SUCCESS != status) {
throw runtime_error("Can't start glib loop");
}
- client = sc_client_create();
+ client = vsm_client_create();
if (NULL == client) {
msg = "Can't create client";
goto finish;
}
- status = sc_connect(client);
- if (SCCLIENT_SUCCESS != status) {
- msg = sc_get_status_message(client);
+ status = vsm_connect(client);
+ if (VSMCLIENT_SUCCESS != status) {
+ msg = vsm_get_status_message(client);
goto finish;
}
status = fun(client);
- if (SCCLIENT_SUCCESS != status) {
- msg = sc_get_status_message(client);
+ if (VSMCLIENT_SUCCESS != status) {
+ msg = vsm_get_status_message(client);
goto finish;
}
finish:
- sc_client_free(client);
- sc_stop_glib_loop();
+ vsm_client_free(client);
+ vsm_stop_glib_loop();
if (! msg.empty()) {
throw runtime_error(msg);
}
@@ -108,10 +108,10 @@ void set_active_container(int pos, int argc, const char** argv)
throw runtime_error("Not enough parameters");
}
- one_shot(bind(sc_set_active_container, _1, argv[pos + 1]));
+ one_shot(bind(vsm_set_active_container, _1, argv[pos + 1]));
}
-void add_container(int pos, int argc, const char** argv)
+void create_domain(int pos, int argc, const char** argv)
{
using namespace std::placeholders;
@@ -119,7 +119,7 @@ void add_container(int pos, int argc, const char** argv)
throw runtime_error("Not enough parameters");
}
- one_shot(bind(sc_add_container, _1, argv[pos + 1]));
+ one_shot(bind(vsm_create_domain, _1, argv[pos + 1]));
}
} // namespace cli
diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp
index d9fc39f..27415c1 100644
--- a/cli/command-line-interface.hpp
+++ b/cli/command-line-interface.hpp
@@ -62,9 +62,9 @@ public:
* @param argsSpec Description of arguments
*/
CommandLineInterface(const ExecutorCallback& executorCallback,
- const std::string& usage,
- const std::string& usageInfo,
- const ArgsSpec& argsSpec)
+ const std::string& usage,
+ const std::string& usageInfo,
+ const ArgsSpec& argsSpec)
: mExecutorCallback(executorCallback),
mUsage(usage),
mUsageInfo(usageInfo),
@@ -97,18 +97,18 @@ private:
};
/**
- * Parses command line arguments and call sc_set_active_container
+ * Parses command line arguments and call vsm_set_active_container
*
- * @see sc_set_active_container
+ * @see vsm_set_active_container
*/
void set_active_container(int pos, int argc, const char** argv);
/**
- * Parses command line arguments and call sc_add_container
+ * Parses command line arguments and call vsm_create_domain
*
- * @see sc_add_container
+ * @see vsm_create_domain
*/
-void add_container(int pos, int argc, const char** argv);
+void create_domain(int pos, int argc, const char** argv);
} // namespace cli
} // namespace security_containers
diff --git a/cli/main.cpp b/cli/main.cpp
index d84d5ac..135385d 100644
--- a/cli/main.cpp
+++ b/cli/main.cpp
@@ -33,17 +33,21 @@
using namespace security_containers::cli;
std::map commands = {
- {"set_active_container", {
- set_active_container,
- "set_active_container container_id",
- "Set active (foreground) container",
- {{"container_id", "id container name"}}}
+ {
+ "set_active_container", {
+ set_active_container,
+ "set_active_container container_id",
+ "Set active (foreground) container",
+ {{"container_id", "id container name"}}
+ }
},
- {"add_container", {
- add_container,
- "add_container container_id",
- "Create and add container",
- {{"container_id", "id container name"}}}
+ {
+ "create_domain", {
+ create_domain,
+ "create_domain container_id",
+ "Create and add container",
+ {{"container_id", "id container name"}}
+ }
}
};
@@ -70,7 +74,7 @@ int main(const int argc, const char** argv)
CommandLineInterface& command = commands[argv[1]];
try {
- command.execute(1, argc, argv);
+ command.execute(1, argc, argv);
} catch (const std::runtime_error& ex) {
std::cerr << ex.what() << std::endl;
return EXIT_FAILURE;
diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp
index 95418b9..39abbfd 100644
--- a/client/security-containers-client-impl.cpp
+++ b/client/security-containers-client-impl.cpp
@@ -52,7 +52,7 @@ const DbusInterfaceInfo CONTAINER_INTERFACE(api::container::BUS_NAME,
unique_ptr gGlibLoop;
-void toDict(GVariant* in, ScArrayString* keys, ScArrayString* values)
+void toDict(GVariant* in, VsmArrayString* keys, VsmArrayString* values)
{
assert(in);
assert(keys);
@@ -108,20 +108,20 @@ void toArray(GVariant* in, T** scArray)
*scArray = ids;
}
-ScStatus toStatus(const std::exception& ex)
+VsmStatus toStatus(const std::exception& ex)
{
if (typeid(DbusCustomException) == typeid(ex)) {
- return SCCLIENT_CUSTOM_ERROR;
+ return VSMCLIENT_CUSTOM_ERROR;
} else if (typeid(DbusIOException) == typeid(ex)) {
- return SCCLIENT_IO_ERROR;
+ return VSMCLIENT_IO_ERROR;
} else if (typeid(DbusOperationException) == typeid(ex)) {
- return SCCLIENT_OPERATION_FAILED;
+ return VSMCLIENT_OPERATION_FAILED;
} else if (typeid(DbusInvalidArgumentException) == typeid(ex)) {
- return SCCLIENT_INVALID_ARGUMENT;
+ return VSMCLIENT_INVALID_ARGUMENT;
} else if (typeid(DbusException) == typeid(ex)) {
- return SCCLIENT_OTHER_ERROR;
+ return VSMCLIENT_OTHER_ERROR;
}
- return SCCLIENT_OTHER_ERROR;
+ return VSMCLIENT_OTHER_ERROR;
}
bool readFirstLineOfFile(const std::string& path, std::string& ret)
@@ -137,36 +137,36 @@ bool readFirstLineOfFile(const std::string& path, std::string& ret)
} //namespace
-ScStatus Client::sc_start_glib_loop() noexcept
+VsmStatus Client::vsm_start_glib_loop() noexcept
{
try {
if (!gGlibLoop) {
gGlibLoop.reset(new ScopedGlibLoop());
}
} catch (const exception&) {
- return SCCLIENT_OTHER_ERROR;
+ return VSMCLIENT_OTHER_ERROR;
}
- return SCCLIENT_SUCCESS;
+ return VSMCLIENT_SUCCESS;
}
-ScStatus Client::sc_stop_glib_loop() noexcept
+VsmStatus Client::vsm_stop_glib_loop() noexcept
{
try {
gGlibLoop.reset();
} catch (const exception&) {
- return SCCLIENT_OTHER_ERROR;
+ return VSMCLIENT_OTHER_ERROR;
}
- return SCCLIENT_SUCCESS;
+ return VSMCLIENT_SUCCESS;
}
Client::Status::Status()
- : mScStatus(SCCLIENT_SUCCESS), mMsg()
+ : mVsmStatus(VSMCLIENT_SUCCESS), mMsg()
{
}
-Client::Status::Status(ScStatus status, const std::string& msg)
- : mScStatus(status), mMsg(msg)
+Client::Status::Status(VsmStatus status, const std::string& msg)
+ : mVsmStatus(status), mMsg(msg)
{
}
@@ -178,33 +178,33 @@ Client::~Client() noexcept
{
}
-ScStatus Client::createSystem() noexcept
+VsmStatus Client::createSystem() noexcept
{
try {
mConnection = DbusConnection::createSystem();
mStatus = Status();
- } catch (const exception& ex) {
+ } catch (const exception& ex) {
mStatus = Status(toStatus(ex), ex.what());
}
- return sc_get_status();
+ return vsm_get_status();
}
-ScStatus Client::create(const string& address) noexcept
+VsmStatus Client::create(const string& address) noexcept
{
try {
mConnection = DbusConnection::create(address);
mStatus = Status();
- } catch (const exception& ex) {
+ } catch (const exception& ex) {
mStatus = Status(toStatus(ex), ex.what());
}
- return sc_get_status();
+ return vsm_get_status();
}
-ScStatus Client::callMethod(const DbusInterfaceInfo& info,
- const string& method,
- GVariant* args_in,
- const string& args_spec_out,
- GVariant** args_out)
+VsmStatus Client::callMethod(const DbusInterfaceInfo& info,
+ const string& method,
+ GVariant* args_in,
+ const string& args_spec_out,
+ GVariant** args_out)
{
try {
GVariantPtr ret = mConnection->callMethod(info.busName,
@@ -220,12 +220,12 @@ ScStatus Client::callMethod(const DbusInterfaceInfo& info,
} catch (const exception& ex) {
mStatus = Status(toStatus(ex), ex.what());
}
- return sc_get_status();
+ return vsm_get_status();
}
-ScStatus Client::signalSubscribe(const DbusInterfaceInfo& info,
- const string& name,
- SignalCallback signalCallback)
+VsmStatus Client::signalSubscribe(const DbusInterfaceInfo& info,
+ const string& name,
+ SignalCallback signalCallback)
{
auto onSignal = [=](const std::string& /*senderBusName*/,
const std::string & objectPath,
@@ -233,8 +233,8 @@ ScStatus Client::signalSubscribe(const DbusInterfaceInfo& info,
const std::string & signalName,
GVariant * parameters) {
if (objectPath == info.objectPath &&
- interface == info.interface &&
- signalName == name) {
+ interface == info.interface &&
+ signalName == name) {
signalCallback(parameters);
}
@@ -245,31 +245,31 @@ ScStatus Client::signalSubscribe(const DbusInterfaceInfo& info,
} catch (const std::exception& ex) {
mStatus = Status(toStatus(ex), ex.what());
}
- return sc_get_status();
+ return vsm_get_status();
}
-const char* Client::sc_get_status_message() noexcept
+const char* Client::vsm_get_status_message() noexcept
{
return mStatus.mMsg.c_str();
}
-ScStatus Client::sc_get_status() noexcept
+VsmStatus Client::vsm_get_status() noexcept
{
- return mStatus.mScStatus;
+ return mStatus.mVsmStatus;
}
-ScStatus Client::sc_get_container_dbuses(ScArrayString* keys, ScArrayString* values) noexcept
+VsmStatus Client::vsm_get_container_dbuses(VsmArrayString* keys, VsmArrayString* values) noexcept
{
assert(keys);
assert(values);
GVariant* out;
- ScStatus ret = callMethod(HOST_INTERFACE,
- api::host::METHOD_GET_CONTAINER_DBUSES,
- NULL,
- "(a{ss})",
- &out);
- if (ret != SCCLIENT_SUCCESS) {
+ VsmStatus ret = callMethod(HOST_INTERFACE,
+ api::host::METHOD_GET_CONTAINER_DBUSES,
+ NULL,
+ "(a{ss})",
+ &out);
+ if (ret != VSMCLIENT_SUCCESS) {
return ret;
}
GVariant* unpacked;
@@ -280,17 +280,17 @@ ScStatus Client::sc_get_container_dbuses(ScArrayString* keys, ScArrayString* val
return ret;
}
-ScStatus Client::sc_get_container_ids(ScArrayString* array) noexcept
+VsmStatus Client::vsm_get_domain_ids(VsmArrayString* array) noexcept
{
assert(array);
GVariant* out;
- ScStatus ret = callMethod(HOST_INTERFACE,
- api::host::METHOD_GET_CONTAINER_ID_LIST,
- NULL,
- "(as)",
- &out);
- if (ret != SCCLIENT_SUCCESS) {
+ VsmStatus ret = callMethod(HOST_INTERFACE,
+ api::host::METHOD_GET_CONTAINER_ID_LIST,
+ NULL,
+ "(as)",
+ &out);
+ if (ret != VSMCLIENT_SUCCESS) {
return ret;
}
GVariant* unpacked;
@@ -301,17 +301,17 @@ ScStatus Client::sc_get_container_ids(ScArrayString* array) noexcept
return ret;
}
-ScStatus Client::sc_get_active_container_id(ScString* id) noexcept
+VsmStatus Client::vsm_get_active_container_id(VsmString* id) noexcept
{
assert(id);
GVariant* out;
- ScStatus ret = callMethod(HOST_INTERFACE,
- api::host::METHOD_GET_ACTIVE_CONTAINER_ID,
- NULL,
- "(s)",
- &out);
- if (ret != SCCLIENT_SUCCESS) {
+ VsmStatus ret = callMethod(HOST_INTERFACE,
+ api::host::METHOD_GET_ACTIVE_CONTAINER_ID,
+ NULL,
+ "(s)",
+ &out);
+ if (ret != VSMCLIENT_SUCCESS) {
return ret;
}
GVariant* unpacked;
@@ -322,7 +322,7 @@ ScStatus Client::sc_get_active_container_id(ScString* id) noexcept
return ret;
}
-ScStatus Client::sc_get_container_id_by_pid(int pid, ScString* id) noexcept
+VsmStatus Client::vsm_lookup_domain_by_pid(int pid, VsmString* id) noexcept
{
assert(id);
@@ -330,22 +330,22 @@ ScStatus Client::sc_get_container_id_by_pid(int pid, ScString* id) noexcept
std::string cpuset;
if (!readFirstLineOfFile(path, cpuset)) {
- mStatus = Status(SCCLIENT_INVALID_ARGUMENT, "Process not found");
- return sc_get_status();
+ mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, "Process not found");
+ return vsm_get_status();
}
std::string containerId;
if (!parseContainerIdFromCpuSet(cpuset, containerId)) {
- mStatus = Status(SCCLIENT_OTHER_ERROR, "unknown format of cpuset");
- return sc_get_status();
+ mStatus = Status(VSMCLIENT_OTHER_ERROR, "unknown format of cpuset");
+ return vsm_get_status();
}
*id = strdup(containerId.c_str());
mStatus = Status();
- return sc_get_status();;
+ return vsm_get_status();;
}
-ScStatus Client::sc_set_active_container(const char* id) noexcept
+VsmStatus Client::vsm_set_active_container(const char* id) noexcept
{
assert(id);
@@ -353,7 +353,7 @@ ScStatus Client::sc_set_active_container(const char* id) noexcept
return callMethod(HOST_INTERFACE, api::host::METHOD_SET_ACTIVE_CONTAINER, args_in);
}
-ScStatus Client::sc_add_container(const char* id) noexcept
+VsmStatus Client::vsm_create_domain(const char* id) noexcept
{
assert(id);
@@ -361,12 +361,13 @@ ScStatus Client::sc_add_container(const char* id) noexcept
return callMethod(HOST_INTERFACE, api::host::METHOD_ADD_CONTAINER, args_in);
}
-ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback,
+VsmStatus Client::vsm_add_state_callback(VsmContainerDbusStateCallback containerDbusStateCallback,
void* data) noexcept
{
assert(containerDbusStateCallback);
- auto onSigal = [=](GVariant * parameters) {
+ auto onSigal = [=](GVariant * parameters)
+ {
const char* container;
const char* dbusAddress;
g_variant_get(parameters, "(&s&s)", &container, &dbusAddress);
@@ -378,7 +379,7 @@ ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerD
onSigal);
}
-ScStatus Client::sc_notify_active_container(const char* application, const char* message) noexcept
+VsmStatus Client::vsm_notify_active_container(const char* application, const char* message) noexcept
{
assert(application);
assert(message);
@@ -389,34 +390,34 @@ ScStatus Client::sc_notify_active_container(const char* application, const char*
args_in);
}
-ScStatus Client::sc_file_move_request(const char* destContainer, const char* path) noexcept
+VsmStatus Client::vsm_file_move_request(const char* destContainer, const char* path) noexcept
{
assert(destContainer);
assert(path);
GVariant* out;
GVariant* args_in = g_variant_new("(ss)", destContainer, path);
- ScStatus ret = callMethod(CONTAINER_INTERFACE,
- api::container::METHOD_FILE_MOVE_REQUEST,
- args_in,
- "(s)",
- &out);
+ VsmStatus ret = callMethod(CONTAINER_INTERFACE,
+ api::container::METHOD_FILE_MOVE_REQUEST,
+ args_in,
+ "(s)",
+ &out);
- if (ret != SCCLIENT_SUCCESS) {
+ if (ret != VSMCLIENT_SUCCESS) {
return ret;
}
const gchar* retcode = NULL;;
g_variant_get(out, "(&s)", &retcode);
if (strcmp(retcode, api::container::FILE_MOVE_SUCCEEDED.c_str()) != 0) {
- mStatus = Status(SCCLIENT_CUSTOM_ERROR, retcode);
+ mStatus = Status(VSMCLIENT_CUSTOM_ERROR, retcode);
g_variant_unref(out);
- return sc_get_status();
+ return vsm_get_status();
}
g_variant_unref(out);
return ret;
}
-ScStatus Client::sc_notification(ScNotificationCallback notificationCallback, void* data) noexcept
+VsmStatus Client::vsm_notification(VsmNotificationCallback notificationCallback, void* data) noexcept
{
assert(notificationCallback);
diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp
index 3f5a556..9a233e5 100644
--- a/client/security-containers-client-impl.hpp
+++ b/client/security-containers-client-impl.hpp
@@ -55,22 +55,22 @@ private:
typedef std::function SignalCallback;
struct Status {
Status();
- Status(ScStatus status, const std::string& msg);
- ScStatus mScStatus;
+ Status(VsmStatus status, const std::string& msg);
+ VsmStatus mVsmStatus;
std::string mMsg;
};
dbus::DbusConnection::Pointer mConnection;
Status mStatus;
- ScStatus callMethod(const DbusInterfaceInfo& info,
- const std::string& method,
- GVariant* args_in,
- const std::string& args_spec_out = std::string(),
- GVariant** args_out = NULL);
- ScStatus signalSubscribe(const DbusInterfaceInfo& info,
- const std::string& name,
- SignalCallback signalCallback);
+ VsmStatus callMethod(const DbusInterfaceInfo& info,
+ const std::string& method,
+ GVariant* args_in,
+ const std::string& args_spec_out = std::string(),
+ GVariant** args_out = NULL);
+ VsmStatus signalSubscribe(const DbusInterfaceInfo& info,
+ const std::string& name,
+ SignalCallback signalCallback);
public:
Client() noexcept;
@@ -81,7 +81,7 @@ public:
*
* @return status of this function call
*/
- ScStatus createSystem() noexcept;
+ VsmStatus createSystem() noexcept;
/**
* Create client.
@@ -89,76 +89,76 @@ public:
* @param address Dbus socket address
* @return status of this function call
*/
- ScStatus create(const std::string& address) noexcept;
+ VsmStatus create(const std::string& address) noexcept;
/**
- * @see ::sc_get_status_message
+ * @see ::vsm_get_status_message
*/
- const char* sc_get_status_message() noexcept;
+ const char* vsm_get_status_message() noexcept;
/**
- * @see ::sc_get_status
+ * @see ::vsm_get_status
*/
- ScStatus sc_get_status() noexcept;
+ VsmStatus vsm_get_status() noexcept;
/**
- * @see ::sc_get_container_dbuses
+ * @see ::vsm_get_container_dbuses
*/
- ScStatus sc_get_container_dbuses(ScArrayString* keys, ScArrayString* values) noexcept;
+ VsmStatus vsm_get_container_dbuses(VsmArrayString* keys, VsmArrayString* values) noexcept;
/**
- * @see ::sc_get_container_ids
+ * @see ::vsm_get_domain_ids
*/
- ScStatus sc_get_container_ids(ScArrayString* array) noexcept;
+ VsmStatus vsm_get_domain_ids(VsmArrayString* array) noexcept;
/**
- * @see ::sc_get_active_container_id
+ * @see ::vsm_get_active_container_id
*/
- ScStatus sc_get_active_container_id(ScString* id) noexcept;
+ VsmStatus vsm_get_active_container_id(VsmString* id) noexcept;
/**
- * @see ::sc_get_container_id_by_pid
+ * @see ::vsm_lookup_domain_by_pid
*/
- ScStatus sc_get_container_id_by_pid(int pid, ScString* id) noexcept;
+ VsmStatus vsm_lookup_domain_by_pid(int pid, VsmString* id) noexcept;
/**
- * @see ::sc_set_active_container
+ * @see ::vsm_set_active_container
*/
- ScStatus sc_set_active_container(const char* id) noexcept;
+ VsmStatus vsm_set_active_container(const char* id) noexcept;
/**
- * @see ::sc_add_container
+ * @see ::vsm_create_domain
*/
- ScStatus sc_add_container(const char* id) noexcept;
+ VsmStatus vsm_create_domain(const char* id) noexcept;
/**
- * @see ::sc_container_dbus_state
+ * @see ::vsm_add_state_callback
*/
- ScStatus sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback,
+ VsmStatus vsm_add_state_callback(VsmContainerDbusStateCallback containerDbusStateCallback,
void* data) noexcept;
/**
- * @see ::sc_notify_active_container
+ * @see ::vsm_notify_active_container
*/
- ScStatus sc_notify_active_container(const char* application, const char* message) noexcept;
+ VsmStatus vsm_notify_active_container(const char* application, const char* message) noexcept;
/**
- * @see ::sc_file_move_request
+ * @see ::vsm_file_move_request
*/
- ScStatus sc_file_move_request(const char* destContainer, const char* path) noexcept;
+ VsmStatus vsm_file_move_request(const char* destContainer, const char* path) noexcept;
/**
- * @see ::sc_notification
+ * @see ::vsm_notification
*/
- ScStatus sc_notification(ScNotificationCallback notificationCallback, void* data) noexcept;
+ VsmStatus vsm_notification(VsmNotificationCallback notificationCallback, void* data) noexcept;
/**
- * @see ::sc_start_glib_loop
+ * @see ::vsm_start_glib_loop
*/
- static ScStatus sc_start_glib_loop() noexcept;
+ static VsmStatus vsm_start_glib_loop() noexcept;
/**
- * @see ::sc_stop_glib_loop
+ * @see ::vsm_stop_glib_loop
*/
- static ScStatus sc_stop_glib_loop() noexcept;
+ static VsmStatus vsm_stop_glib_loop() noexcept;
};
#endif /* SECURITY_CONTAINERS_CLIENT_IMPL_HPP */
diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp
index 95c2758..ad8fb38 100644
--- a/client/security-containers-client.cpp
+++ b/client/security-containers-client.cpp
@@ -37,7 +37,7 @@ using namespace std;
namespace {
-Client& getClient(ScClient client)
+Client& getClient(VsmClient client)
{
assert(client);
return *reinterpret_cast(client);
@@ -46,118 +46,118 @@ Client& getClient(ScClient client)
} // namespace
/* external */
-API ScStatus sc_start_glib_loop()
+API VsmStatus vsm_start_glib_loop()
{
- return Client::sc_start_glib_loop();
+ return Client::vsm_start_glib_loop();
}
-API ScStatus sc_stop_glib_loop()
+API VsmStatus vsm_stop_glib_loop()
{
- return Client::sc_stop_glib_loop();
+ return Client::vsm_stop_glib_loop();
}
-API ScClient sc_client_create()
+API VsmClient vsm_client_create()
{
Client* clientPtr = new(nothrow) Client();
- return reinterpret_cast(clientPtr);
+ return reinterpret_cast(clientPtr);
}
-API ScStatus sc_connect(ScClient client)
+API VsmStatus vsm_connect(VsmClient client)
{
return getClient(client).createSystem();
}
-API ScStatus sc_connect_custom(ScClient client, const char* address)
+API VsmStatus vsm_connect_custom(VsmClient client, const char* address)
{
return getClient(client).create(address);
}
-API void sc_array_string_free(ScArrayString astring)
+API void vsm_array_string_free(VsmArrayString astring)
{
if (!astring) {
return;
}
for (char** ptr = astring; *ptr; ++ptr) {
- sc_string_free(*ptr);
+ vsm_string_free(*ptr);
}
free(astring);
}
-API void sc_string_free(ScString string)
+API void vsm_string_free(VsmString string)
{
free(string);
}
-API void sc_client_free(ScClient client)
+API void vsm_client_free(VsmClient client)
{
if (client != NULL) {
delete &getClient(client);
}
}
-API const char* sc_get_status_message(ScClient client)
+API const char* vsm_get_status_message(VsmClient client)
{
- return getClient(client).sc_get_status_message();
+ return getClient(client).vsm_get_status_message();
}
-API ScStatus sc_get_status(ScClient client)
+API VsmStatus vsm_get_status(VsmClient client)
{
- return getClient(client).sc_get_status();
+ return getClient(client).vsm_get_status();
}
-API ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArrayString* values)
+API VsmStatus vsm_get_container_dbuses(VsmClient client, VsmArrayString* keys, VsmArrayString* values)
{
- return getClient(client).sc_get_container_dbuses(keys, values);
+ return getClient(client).vsm_get_container_dbuses(keys, values);
}
-API ScStatus sc_get_container_ids(ScClient client, ScArrayString* array)
+API VsmStatus vsm_get_domain_ids(VsmClient client, VsmArrayString* array)
{
- return getClient(client).sc_get_container_ids(array);
+ return getClient(client).vsm_get_domain_ids(array);
}
-API ScStatus sc_get_active_container_id(ScClient client, ScString* id)
+API VsmStatus vsm_get_active_container_id(VsmClient client, VsmString* id)
{
- return getClient(client).sc_get_active_container_id(id);
+ return getClient(client).vsm_get_active_container_id(id);
}
-API ScStatus sc_get_container_id_by_pid(ScClient client, int pid, ScString* id)
+API VsmStatus vsm_lookup_domain_by_pid(VsmClient client, int pid, VsmString* id)
{
- return getClient(client).sc_get_container_id_by_pid(pid, id);
+ return getClient(client).vsm_lookup_domain_by_pid(pid, id);
}
-API ScStatus sc_set_active_container(ScClient client, const char* id)
+API VsmStatus vsm_set_active_container(VsmClient client, const char* id)
{
- return getClient(client).sc_set_active_container(id);
+ return getClient(client).vsm_set_active_container(id);
}
-API ScStatus sc_add_container(ScClient client, const char* id)
+API VsmStatus vsm_create_domain(VsmClient client, const char* id)
{
- return getClient(client).sc_add_container(id);
+ return getClient(client).vsm_create_domain(id);
}
-API ScStatus sc_container_dbus_state(ScClient client,
- ScContainerDbusStateCallback containerDbusStateCallback,
+API VsmStatus vsm_add_state_callback(VsmClient client,
+ VsmContainerDbusStateCallback containerDbusStateCallback,
void* data)
{
- return getClient(client).sc_container_dbus_state(containerDbusStateCallback, data);
+ return getClient(client).vsm_add_state_callback(containerDbusStateCallback, data);
}
-API ScStatus sc_notify_active_container(ScClient client,
- const char* application,
- const char* message)
+API VsmStatus vsm_notify_active_container(VsmClient client,
+ const char* application,
+ const char* message)
{
- return getClient(client).sc_notify_active_container(application, message);
+ return getClient(client).vsm_notify_active_container(application, message);
}
-API ScStatus sc_file_move_request(ScClient client, const char* destContainer, const char* path)
+API VsmStatus vsm_file_move_request(VsmClient client, const char* destContainer, const char* path)
{
- return getClient(client).sc_file_move_request(destContainer, path);
+ return getClient(client).vsm_file_move_request(destContainer, path);
}
-API ScStatus sc_notification(ScClient client,
- ScNotificationCallback notificationCallback,
- void* data)
+API VsmStatus vsm_notification(VsmClient client,
+ VsmNotificationCallback notificationCallback,
+ void* data)
{
- return getClient(client).sc_notification(notificationCallback, data);
+ return getClient(client).vsm_notification(notificationCallback, data);
}
diff --git a/client/security-containers-client.h b/client/security-containers-client.h
index 1307cb5..710af99 100644
--- a/client/security-containers-client.h
+++ b/client/security-containers-client.h
@@ -29,47 +29,47 @@
int main(int argc, char** argv)
{
- ScStatus status;
- ScClient client;
- ScArrayString values = NULL;
+ VsmStatus status;
+ VsmClient client;
+ VsmArrayString values = NULL;
int ret = 0;
- status = sc_start_glib_loop(); // start glib loop (if not started any yet)
- if (SCCLIENT_SUCCESS != status) {
+ status = vsm_start_glib_loop(); // start glib loop (if not started any yet)
+ if (VSMCLIENT_SUCCESS != status) {
// error!
return 1;
}
- client = sc_client_create(); // create client handle
+ client = vsm_client_create(); // create client handle
if (NULL == client) {
// error!
ret = 1;
goto finish;
}
- status = sc_connect(client); // connect to dbus
- if (SCCLIENT_SUCCESS != status) {
+ status = vsm_connect(client); // connect to dbus
+ if (VSMCLIENT_SUCCESS != status) {
// error!
ret = 1;
goto finish;
}
- status = sc_get_container_ids(client, &values);
- if (SCCLIENT_SUCCESS != status) {
+ status = vsm_get_domain_ids(client, &values);
+ if (VSMCLIENT_SUCCESS != status) {
// error!
ret = 1;
goto finish;
}
// print array
- for (ScArrayString iValues = values; *iValues; iValues++) {
+ for (VsmArrayString iValues = values; *iValues; iValues++) {
printf("%s\n", *iValues);
}
finish:
- sc_array_string_free(values); // free memory
- sc_client_free(client); // destroy client handle
- sc_stop_glib_loop(); // stop the glib loop (use only with sc_start_glib_loop)
+ vsm_array_string_free(values); // free memory
+ vsm_client_free(client); // destroy client handle
+ vsm_stop_glib_loop(); // stop the glib loop (use only with vsm_start_glib_loop)
return ret;
}
@endcode
@@ -86,33 +86,33 @@ extern "C"
/**
* security-containers-server's client pointer.
*/
-typedef void* ScClient;
+typedef void* VsmClient;
/**
* NULL-terminated string type.
*
- * @sa sc_array_string_free
+ * @sa vsm_array_string_free
*/
-typedef char* ScString;
+typedef char* VsmString;
/**
* NULL-terminated array of strings type.
*
- * @sa sc_string_free
+ * @sa vsm_string_free
*/
-typedef ScString* ScArrayString;
+typedef VsmString* VsmArrayString;
/**
* Completion status of communication function.
*/
typedef enum {
- SCCLIENT_CUSTOM_ERROR, ///< User specified error
- SCCLIENT_IO_ERROR, ///< Input/Output error
- SCCLIENT_OPERATION_FAILED, ///< Operation failed
- SCCLIENT_INVALID_ARGUMENT, ///< Invalid argument
- SCCLIENT_OTHER_ERROR, ///< Other error
- SCCLIENT_SUCCESS ///< Success
-} ScStatus;
+ VSMCLIENT_CUSTOM_ERROR, ///< User specified error
+ VSMCLIENT_IO_ERROR, ///< Input/Output error
+ VSMCLIENT_OPERATION_FAILED, ///< Operation failed
+ VSMCLIENT_INVALID_ARGUMENT, ///< Invalid argument
+ VSMCLIENT_OTHER_ERROR, ///< Other error
+ VSMCLIENT_SUCCESS ///< Success
+} VsmStatus;
/**
* Start glib loop.
@@ -122,30 +122,30 @@ typedef enum {
*
* @return status of this function call
*/
-ScStatus sc_start_glib_loop();
+VsmStatus vsm_start_glib_loop();
/**
* Stop glib loop.
*
- * Call only if sc_start_glib_loop() was called.
+ * Call only if vsm_start_glib_loop() was called.
*
* @return status of this function call
*/
-ScStatus sc_stop_glib_loop();
+VsmStatus vsm_stop_glib_loop();
/**
* Create a new security-containers-server's client.
*
* @return Created client pointer or NULL on failure.
*/
-ScClient sc_client_create();
+VsmClient vsm_client_create();
/**
* Release client resources.
*
* @param[in] client security-containers-server's client
*/
-void sc_client_free(ScClient client);
+void vsm_client_free(VsmClient client);
/**
* Get status code of last security-containers-server communication.
@@ -153,7 +153,7 @@ void sc_client_free(ScClient client);
* @param[in] client security-containers-server's client
* @return status of this function call
*/
-ScStatus sc_get_status(ScClient client);
+VsmStatus vsm_get_status(VsmClient client);
/**
* Get status message of the last security-containers-server communication.
@@ -161,7 +161,7 @@ ScStatus sc_get_status(ScClient client);
* @param[in] client security-containers-server's client
* @return last status message from security-containers-server communication
*/
-const char* sc_get_status_message(ScClient client);
+const char* vsm_get_status_message(VsmClient client);
/**
* Connect client to the security-containers-server.
@@ -169,7 +169,7 @@ const char* sc_get_status_message(ScClient client);
* @param[in] client security-containers-server's client
* @return status of this function call
*/
-ScStatus sc_connect(ScClient client);
+VsmStatus vsm_connect(VsmClient client);
/**
* Connect client to the security-containers-server via custom address.
@@ -178,21 +178,21 @@ ScStatus sc_connect(ScClient client);
* @param[in] address dbus address
* @return status of this function call
*/
-ScStatus sc_connect_custom(ScClient client, const char* address);
+VsmStatus vsm_connect_custom(VsmClient client, const char* address);
/**
- * Release ScArrayString.
+ * Release VsmArrayString.
*
- * @param[in] astring ScArrayString
+ * @param[in] astring VsmArrayString
*/
-void sc_array_string_free(ScArrayString astring);
+void vsm_array_string_free(VsmArrayString astring);
/**
- * Release ScString.
+ * Release VsmString.
*
- * @param string ScString
+ * @param string VsmString
*/
-void sc_string_free(ScString string);
+void vsm_string_free(VsmString string);
/**
@@ -208,9 +208,9 @@ void sc_string_free(ScString string);
*
* @param[in] containerId affected container id
* @param[in] dbusAddress new D-Bus address
- * @param data custom user's data pointer passed to sc_container_dbus_state() function
+ * @param data custom user's data pointer passed to vsm_add_state_callback() function
*/
-typedef void (*ScContainerDbusStateCallback)(const char* containerId,
+typedef void (*VsmContainerDbusStateCallback)(const char* containerId,
const char* dbusAddress,
void* data);
@@ -222,9 +222,9 @@ typedef void (*ScContainerDbusStateCallback)(const char* containerId,
* @param[out] values array of containers dbus address
* @return status of this function call
* @post keys[i] corresponds to values[i]
- * @remark Use sc_array_string_free() to free memory occupied by @p keys and @p values.
+ * @remark Use vsm_array_string_free() to free memory occupied by @p keys and @p values.
*/
-ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArrayString* values);
+VsmStatus vsm_get_container_dbuses(VsmClient client, VsmArrayString* keys, VsmArrayString* values);
/**
* Get containers name.
@@ -232,9 +232,9 @@ ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArraySt
* @param[in] client security-containers-server's client
* @param[out] array array of containers name
* @return status of this function call
- * @remark Use sc_array_string_free() to free memory occupied by @p array.
+ * @remark Use vsm_array_string_free() to free memory occupied by @p array.
*/
-ScStatus sc_get_container_ids(ScClient client, ScArrayString* array);
+VsmStatus vsm_get_domain_ids(VsmClient client, VsmArrayString* array);
/**
* Get active (foreground) container name.
@@ -242,9 +242,9 @@ ScStatus sc_get_container_ids(ScClient client, ScArrayString* array);
* @param[in] client security-containers-server's client
* @param[out] id active container name
* @return status of this function call
- * @remark Use @p sc_string_free() to free memory occupied by @p id.
+ * @remark Use @p vsm_string_free() to free memory occupied by @p id.
*/
-ScStatus sc_get_active_container_id(ScClient client, ScString* id);
+VsmStatus vsm_get_active_container_id(VsmClient client, VsmString* id);
/**
* Get container name of process with given pid.
@@ -253,9 +253,9 @@ ScStatus sc_get_active_container_id(ScClient client, ScString* id);
* @param[in] pid process id
* @param[out] id active container name
* @return status of this function call
- * @remark Use @p sc_string_free() to free memory occupied by @p id.
+ * @remark Use @p vsm_string_free() to free memory occupied by @p id.
*/
-ScStatus sc_get_container_id_by_pid(ScClient client, int pid, ScString* id);
+VsmStatus vsm_lookup_domain_by_pid(VsmClient client, int pid, VsmString* id);
/**
* Set active (foreground) container.
@@ -264,7 +264,7 @@ ScStatus sc_get_container_id_by_pid(ScClient client, int pid, ScString* id);
* @param[in] id container name
* @return status of this function call
*/
-ScStatus sc_set_active_container(ScClient client, const char* id);
+VsmStatus vsm_set_active_container(VsmClient client, const char* id);
/**
* Create and add container
@@ -273,7 +273,7 @@ ScStatus sc_set_active_container(ScClient client, const char* id);
* @param[in] id container id
* @return status of this function call
*/
-ScStatus sc_add_container(ScClient client, const char* id);
+VsmStatus vsm_create_domain(VsmClient client, const char* id);
/**
* Register dbus state change callback function.
@@ -285,8 +285,8 @@ ScStatus sc_add_container(ScClient client, const char* id);
* @param[in] data some extra data that will be passed to callback function
* @return status of this function call
*/
-ScStatus sc_container_dbus_state(ScClient client,
- ScContainerDbusStateCallback containerDbusStateCallback,
+VsmStatus vsm_add_state_callback(VsmClient client,
+ VsmContainerDbusStateCallback containerDbusStateCallback,
void* data);
/** @} */ // Host API
@@ -306,9 +306,9 @@ ScStatus sc_container_dbus_state(ScClient client,
* @param[in] container source container
* @param[in] application sending application name
* @param[in] message notification message
- * @param data custom user's data pointer passed to sc_notification()
+ * @param data custom user's data pointer passed to vsm_notification()
*/
-typedef void (*ScNotificationCallback)(const char* container,
+typedef void (*VsmNotificationCallback)(const char* container,
const char* application,
const char* message,
void* data);
@@ -320,7 +320,7 @@ typedef void (*ScNotificationCallback)(const char* container,
* @param[in] message message
* @return status of this function call
*/
-ScStatus sc_notify_active_container(ScClient client, const char* application, const char* message);
+VsmStatus vsm_notify_active_container(VsmClient client, const char* application, const char* message);
/**
* Move file between containers.
@@ -330,7 +330,7 @@ ScStatus sc_notify_active_container(ScClient client, const char* application, co
* @param[in] path path to moved file
* @return status of this function call
*/
-ScStatus sc_file_move_request(ScClient client, const char* destContainer, const char* path);
+VsmStatus vsm_file_move_request(VsmClient client, const char* destContainer, const char* path);
/**
* Register notification callback function.
@@ -342,7 +342,7 @@ ScStatus sc_file_move_request(ScClient client, const char* destContainer, const
* @param[in] data some extra data that will be passed to callback function
* @return status of this function call
*/
-ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback, void* data);
+VsmStatus vsm_notification(VsmClient client, VsmNotificationCallback notificationCallback, void* data);
/** @} */ // Domain API
diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp
index 5db6962..184659e 100644
--- a/tests/unit_tests/client/ut-client.cpp
+++ b/tests/unit_tests/client/ut-client.cpp
@@ -48,8 +48,14 @@ const std::string TEST_DBUS_CONFIG_PATH =
SC_TEST_CONFIG_INSTALL_DIR "/client/ut-client/test-dbus-daemon.conf";
struct Loop {
- Loop() { sc_start_glib_loop(); }
- ~Loop() { sc_stop_glib_loop(); }
+ Loop()
+ {
+ vsm_start_glib_loop();
+ }
+ ~Loop()
+ {
+ vsm_stop_glib_loop();
+ }
};
struct Fixture {
@@ -64,32 +70,39 @@ struct Fixture {
const int EVENT_TIMEOUT = 5000; ///< ms
const std::map EXPECTED_DBUSES_STARTED = {
- {"ut-containers-manager-console1-dbus",
- "unix:path=/tmp/ut-containers-manager/console1-dbus/dbus/system_bus_socket"},
- {"ut-containers-manager-console2-dbus",
- "unix:path=/tmp/ut-containers-manager/console2-dbus/dbus/system_bus_socket"},
- {"ut-containers-manager-console3-dbus",
- "unix:path=/tmp/ut-containers-manager/console3-dbus/dbus/system_bus_socket"}};
-
-void convertDictToMap(ScArrayString keys,
- ScArrayString values,
+ {
+ "ut-containers-manager-console1-dbus",
+ "unix:path=/tmp/ut-containers-manager/console1-dbus/dbus/system_bus_socket"
+ },
+ {
+ "ut-containers-manager-console2-dbus",
+ "unix:path=/tmp/ut-containers-manager/console2-dbus/dbus/system_bus_socket"
+ },
+ {
+ "ut-containers-manager-console3-dbus",
+ "unix:path=/tmp/ut-containers-manager/console3-dbus/dbus/system_bus_socket"
+ }
+};
+
+void convertDictToMap(VsmArrayString keys,
+ VsmArrayString values,
std::map& ret)
{
- ScArrayString iKeys;
- ScArrayString iValues;
+ VsmArrayString iKeys;
+ VsmArrayString iValues;
for (iKeys = keys, iValues = values; *iKeys && *iValues; iKeys++, iValues++) {
ret.insert(std::make_pair(*iKeys, *iValues));
}
}
-void convertArrayToSet(ScArrayString values, std::set& ret)
+void convertArrayToSet(VsmArrayString values, std::set& ret)
{
- for (ScArrayString iValues = values; *iValues; iValues++) {
+ for (VsmArrayString iValues = values; *iValues; iValues++) {
ret.insert(*iValues);
}
}
-int getArrayStringLength(ScArrayString astring, int max_len = -1)
+int getArrayStringLength(VsmArrayString astring, int max_len = -1)
{
int i = 0;
for (i = 0; astring[i]; i++) {
@@ -108,21 +121,21 @@ BOOST_AUTO_TEST_CASE(NotRunningServerTest)
{
cm.stopAll();
- ScClient client = sc_client_create();
- ScStatus status = sc_connect_custom(client,
- EXPECTED_DBUSES_STARTED.begin()->second.c_str());
- BOOST_CHECK_EQUAL(SCCLIENT_IO_ERROR, status);
- sc_client_free(client);
+ VsmClient client = vsm_client_create();
+ VsmStatus status = vsm_connect_custom(client,
+ EXPECTED_DBUSES_STARTED.begin()->second.c_str());
+ BOOST_CHECK_EQUAL(VSMCLIENT_IO_ERROR, status);
+ vsm_client_free(client);
}
BOOST_AUTO_TEST_CASE(GetContainerDbusesTest)
{
- ScClient client = sc_client_create();
- ScStatus status = sc_connect(client);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
- ScArrayString keys, values;
- status = sc_get_container_dbuses(client, &keys, &values);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ VsmClient client = vsm_client_create();
+ VsmStatus status = vsm_connect(client);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
+ VsmArrayString keys, values;
+ status = vsm_get_container_dbuses(client, &keys, &values);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
BOOST_CHECK_EQUAL(getArrayStringLength(keys, EXPECTED_DBUSES_STARTED.size() + 1),
EXPECTED_DBUSES_STARTED.size());
@@ -132,19 +145,19 @@ BOOST_AUTO_TEST_CASE(GetContainerDbusesTest)
std::map containers;
convertDictToMap(keys, values, containers);
BOOST_CHECK(containers == EXPECTED_DBUSES_STARTED);
- sc_array_string_free(keys);
- sc_array_string_free(values);
- sc_client_free(client);
+ vsm_array_string_free(keys);
+ vsm_array_string_free(values);
+ vsm_client_free(client);
}
BOOST_AUTO_TEST_CASE(GetContainerIdsTest)
{
- ScClient client = sc_client_create();
- ScStatus status = sc_connect(client);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
- ScArrayString values;
- status = sc_get_container_ids(client, &values);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ VsmClient client = vsm_client_create();
+ VsmStatus status = vsm_connect(client);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
+ VsmArrayString values;
+ status = vsm_get_domain_ids(client, &values);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1),
EXPECTED_DBUSES_STARTED.size());
@@ -154,23 +167,23 @@ BOOST_AUTO_TEST_CASE(GetContainerIdsTest)
for (const auto& container : containers) {
BOOST_CHECK(EXPECTED_DBUSES_STARTED.find(container) != EXPECTED_DBUSES_STARTED.cend());
}
- sc_array_string_free(values);
- sc_client_free(client);
+ vsm_array_string_free(values);
+ vsm_client_free(client);
}
BOOST_AUTO_TEST_CASE(GetActiveContainerIdTest)
{
- ScClient client = sc_client_create();
- ScStatus status = sc_connect(client);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
- ScString container;
- status = sc_get_active_container_id(client, &container);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ VsmClient client = vsm_client_create();
+ VsmStatus status = vsm_connect(client);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
+ VsmString container;
+ status = vsm_get_active_container_id(client, &container);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
BOOST_CHECK_EQUAL(container, cm.getRunningForegroundContainerId());
- sc_string_free(container);
- sc_client_free(client);
+ vsm_string_free(container);
+ vsm_client_free(client);
}
BOOST_AUTO_TEST_CASE(SetActiveContainerTest)
@@ -179,25 +192,25 @@ BOOST_AUTO_TEST_CASE(SetActiveContainerTest)
BOOST_REQUIRE_NE(newActiveContainerId, cm.getRunningForegroundContainerId());
- ScClient client = sc_client_create();
- ScStatus status = sc_connect(client);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
- status = sc_set_active_container(client, newActiveContainerId.c_str());
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ VsmClient client = vsm_client_create();
+ VsmStatus status = vsm_connect(client);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
+ status = vsm_set_active_container(client, newActiveContainerId.c_str());
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
BOOST_CHECK_EQUAL(newActiveContainerId, cm.getRunningForegroundContainerId());
- sc_client_free(client);
+ vsm_client_free(client);
}
BOOST_AUTO_TEST_CASE(AddContainerTest)
{
const std::string newActiveContainerId = "";
- ScClient client = sc_client_create();
- ScStatus status = sc_connect(client);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
- status = sc_add_container(client, newActiveContainerId.c_str());
- BOOST_REQUIRE_EQUAL(SCCLIENT_CUSTOM_ERROR, status);
- sc_client_free(client);
+ VsmClient client = vsm_client_create();
+ VsmStatus status = vsm_connect(client);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
+ status = vsm_create_domain(client, newActiveContainerId.c_str());
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_CUSTOM_ERROR, status);
+ vsm_client_free(client);
}
BOOST_AUTO_TEST_CASE(FileMoveRequestTest)
@@ -205,14 +218,14 @@ BOOST_AUTO_TEST_CASE(FileMoveRequestTest)
const std::string path = "/tmp/fake_path";
const std::string secondContainer = "fake_container";
- ScClient client = sc_client_create();
- ScStatus status = sc_connect_custom(client, EXPECTED_DBUSES_STARTED.begin()->second.c_str());
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
- status = sc_file_move_request(client, secondContainer.c_str(), path.c_str());
- BOOST_REQUIRE_EQUAL(SCCLIENT_CUSTOM_ERROR, status);
+ VsmClient client = vsm_client_create();
+ VsmStatus status = vsm_connect_custom(client, EXPECTED_DBUSES_STARTED.begin()->second.c_str());
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
+ status = vsm_file_move_request(client, secondContainer.c_str(), path.c_str());
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_CUSTOM_ERROR, status);
BOOST_REQUIRE_EQUAL(api::container::FILE_MOVE_DESTINATION_NOT_FOUND,
- sc_get_status_message(client));
- sc_client_free(client);
+ vsm_get_status_message(client));
+ vsm_client_free(client);
}
BOOST_AUTO_TEST_CASE(NotificationTest)
@@ -228,30 +241,29 @@ BOOST_AUTO_TEST_CASE(NotificationTest)
auto callback = [](const char* container,
const char* application,
const char* message,
- void* data)
- {
+ void* data) {
CallbackData& callbackData = *reinterpret_cast(data);
callbackData.receivedSignalMsg.push_back(std::make_tuple(container, application, message));
callbackData.signalReceivedLatch.set();
};
CallbackData callbackData;
- std::map clients;
+ std::map clients;
for (const auto& it : EXPECTED_DBUSES_STARTED) {
- ScClient client = sc_client_create();
- ScStatus status = sc_connect_custom(client, it.second.c_str());
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ VsmClient client = vsm_client_create();
+ VsmStatus status = vsm_connect_custom(client, it.second.c_str());
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
clients[it.first] = client;
}
for (auto& client : clients) {
- ScStatus status = sc_notification(client.second, callback, &callbackData);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ VsmStatus status = vsm_notification(client.second, callback, &callbackData);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
}
for (auto& client : clients) {
- ScStatus status = sc_notify_active_container(client.second,
- MSG_APP.c_str(),
- MSG_CONTENT.c_str());
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ VsmStatus status = vsm_notify_active_container(client.second,
+ MSG_APP.c_str(),
+ MSG_CONTENT.c_str());
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
}
BOOST_CHECK(callbackData.signalReceivedLatch.waitForN(clients.size() - 1, EVENT_TIMEOUT));
@@ -264,39 +276,39 @@ BOOST_AUTO_TEST_CASE(NotificationTest)
}
for (auto& client : clients) {
- sc_client_free(client.second);
+ vsm_client_free(client.second);
}
}
BOOST_AUTO_TEST_CASE(GetContainerIdByPidTest1)
{
- ScClient client = sc_client_create();
- ScString container;
- ScStatus status = sc_get_container_id_by_pid(client, 1, &container);
- BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status);
+ VsmClient client = vsm_client_create();
+ VsmString container;
+ VsmStatus status = vsm_lookup_domain_by_pid(client, 1, &container);
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
BOOST_CHECK_EQUAL(container, std::string("host"));
- sc_string_free(container);
- sc_client_free(client);
+ vsm_string_free(container);
+ vsm_client_free(client);
}
BOOST_AUTO_TEST_CASE(GetContainerIdByPidTest2)
{
std::set ids;
- ScClient client = sc_client_create();
+ VsmClient client = vsm_client_create();
for (int n = 0; n < 100000; ++n) {
- ScString container;
- ScStatus status = sc_get_container_id_by_pid(client, n, &container);
- if (status == SCCLIENT_SUCCESS) {
+ VsmString container;
+ VsmStatus status = vsm_lookup_domain_by_pid(client, n, &container);
+ if (status == VSMCLIENT_SUCCESS) {
ids.insert(container);
- sc_string_free(container);
+ vsm_string_free(container);
} else {
- BOOST_WARN_MESSAGE(status == SCCLIENT_INVALID_ARGUMENT, sc_get_status_message(client));
+ BOOST_WARN_MESSAGE(status == VSMCLIENT_INVALID_ARGUMENT, vsm_get_status_message(client));
}
}
- sc_client_free(client);
+ vsm_client_free(client);
BOOST_CHECK(ids.count("host") == 1);
--
2.7.4
From 92f6ab7c3bc9d0fb0e07def9cb552c60309cd008 Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Fri, 7 Nov 2014 09:25:00 +0100
Subject: [PATCH 09/16] Add vsm_del_state_callback and
vsm_del_notification_callback functions
[Feature] Add possibility to unsubscribe from signal
(unregister state callback and notification callback)
[Cause] N/A
[Solution] API Change:
* add vsm_del_state_callback and vsm_del_notification_callback,
* change vsm_add_notification_callback and vsm_add_state_callback signatures
[Verification] Compile
Change-Id: Ia390a41175c6b3bd9334018c28f61533c248fc05
---
client/security-containers-client-impl.cpp | 44 ++++++++++++++++++++++++++----
client/security-containers-client-impl.hpp | 25 ++++++++++++++---
client/security-containers-client.cpp | 25 +++++++++++++----
client/security-containers-client.h | 38 ++++++++++++++++++++++++--
tests/unit_tests/client/ut-client.cpp | 5 +++-
5 files changed, 117 insertions(+), 20 deletions(-)
diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp
index 39abbfd..fd85d2b 100644
--- a/client/security-containers-client-impl.cpp
+++ b/client/security-containers-client-impl.cpp
@@ -225,7 +225,8 @@ VsmStatus Client::callMethod(const DbusInterfaceInfo& info,
VsmStatus Client::signalSubscribe(const DbusInterfaceInfo& info,
const string& name,
- SignalCallback signalCallback)
+ SignalCallback signalCallback,
+ VsmSubscriptionId* subscriptionId)
{
auto onSignal = [=](const std::string& /*senderBusName*/,
const std::string & objectPath,
@@ -240,7 +241,21 @@ VsmStatus Client::signalSubscribe(const DbusInterfaceInfo& info,
}
};
try {
- mConnection->signalSubscribe(onSignal, info.busName);
+ guint id = mConnection->signalSubscribe(onSignal, info.busName);
+ if (subscriptionId) {
+ *subscriptionId = id;
+ }
+ mStatus = Status();
+ } catch (const std::exception& ex) {
+ mStatus = Status(toStatus(ex), ex.what());
+ }
+ return vsm_get_status();
+}
+
+VsmStatus Client::signalUnsubscribe(VsmSubscriptionId id)
+{
+ try {
+ mConnection->signalUnsubscribe(id);
mStatus = Status();
} catch (const std::exception& ex) {
mStatus = Status(toStatus(ex), ex.what());
@@ -362,7 +377,8 @@ VsmStatus Client::vsm_create_domain(const char* id) noexcept
}
VsmStatus Client::vsm_add_state_callback(VsmContainerDbusStateCallback containerDbusStateCallback,
- void* data) noexcept
+ void* data,
+ VsmSubscriptionId* subscriptionId) noexcept
{
assert(containerDbusStateCallback);
@@ -376,7 +392,13 @@ VsmStatus Client::vsm_add_state_callback(VsmContainerDbusStateCallback container
return signalSubscribe(HOST_INTERFACE,
api::host::SIGNAL_CONTAINER_DBUS_STATE,
- onSigal);
+ onSigal,
+ subscriptionId);
+}
+
+VsmStatus Client::vsm_del_state_callback(VsmSubscriptionId subscriptionId) noexcept
+{
+ return signalUnsubscribe(subscriptionId);
}
VsmStatus Client::vsm_notify_active_container(const char* application, const char* message) noexcept
@@ -417,7 +439,9 @@ VsmStatus Client::vsm_file_move_request(const char* destContainer, const char* p
return ret;
}
-VsmStatus Client::vsm_notification(VsmNotificationCallback notificationCallback, void* data) noexcept
+VsmStatus Client::vsm_add_notification_callback(VsmNotificationCallback notificationCallback,
+ void* data,
+ VsmSubscriptionId* subscriptionId) noexcept
{
assert(notificationCallback);
@@ -429,5 +453,13 @@ VsmStatus Client::vsm_notification(VsmNotificationCallback notificationCallback,
notificationCallback(container, application, message, data);
};
- return signalSubscribe(CONTAINER_INTERFACE, api::container::SIGNAL_NOTIFICATION, onSigal);
+ return signalSubscribe(CONTAINER_INTERFACE,
+ api::container::SIGNAL_NOTIFICATION,
+ onSigal,
+ subscriptionId);
+}
+
+VsmStatus Client::vsm_del_notification_callback(VsmSubscriptionId subscriptionId) noexcept
+{
+ return signalUnsubscribe(subscriptionId);
}
diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp
index 9a233e5..e88da49 100644
--- a/client/security-containers-client-impl.hpp
+++ b/client/security-containers-client-impl.hpp
@@ -70,7 +70,9 @@ private:
GVariant** args_out = NULL);
VsmStatus signalSubscribe(const DbusInterfaceInfo& info,
const std::string& name,
- SignalCallback signalCallback);
+ SignalCallback signalCallback,
+ VsmSubscriptionId* subscriptionId);
+ VsmStatus signalUnsubscribe(VsmSubscriptionId id);
public:
Client() noexcept;
@@ -135,7 +137,13 @@ public:
* @see ::vsm_add_state_callback
*/
VsmStatus vsm_add_state_callback(VsmContainerDbusStateCallback containerDbusStateCallback,
- void* data) noexcept;
+ void* data,
+ VsmSubscriptionId* subscriptionId) noexcept;
+
+ /**
+ * @see ::vsm_del_state_callback
+ */
+ VsmStatus vsm_del_state_callback(VsmSubscriptionId subscriptionId) noexcept;
/**
* @see ::vsm_notify_active_container
@@ -146,10 +154,19 @@ public:
* @see ::vsm_file_move_request
*/
VsmStatus vsm_file_move_request(const char* destContainer, const char* path) noexcept;
+
/**
- * @see ::vsm_notification
+ * @see ::vsm_add_notification_callback
*/
- VsmStatus vsm_notification(VsmNotificationCallback notificationCallback, void* data) noexcept;
+ VsmStatus vsm_add_notification_callback(VsmNotificationCallback notificationCallback,
+ void* data,
+ VsmSubscriptionId* subscriptionId) noexcept;
+
+ /**
+ * @see ::vsm_del_notification_callback
+ */
+ VsmStatus vsm_del_notification_callback(VsmSubscriptionId subscriptionId) noexcept;
+
/**
* @see ::vsm_start_glib_loop
*/
diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp
index ad8fb38..2adc702 100644
--- a/client/security-containers-client.cpp
+++ b/client/security-containers-client.cpp
@@ -138,9 +138,15 @@ API VsmStatus vsm_create_domain(VsmClient client, const char* id)
API VsmStatus vsm_add_state_callback(VsmClient client,
VsmContainerDbusStateCallback containerDbusStateCallback,
- void* data)
+ void* data,
+ VsmSubscriptionId* subscriptionId)
{
- return getClient(client).vsm_add_state_callback(containerDbusStateCallback, data);
+ return getClient(client).vsm_add_state_callback(containerDbusStateCallback, data, subscriptionId);
+}
+
+API VsmStatus vsm_del_state_callback(VsmClient client, VsmSubscriptionId subscriptionId)
+{
+ return getClient(client).vsm_del_state_callback(subscriptionId);
}
API VsmStatus vsm_notify_active_container(VsmClient client,
@@ -155,9 +161,16 @@ API VsmStatus vsm_file_move_request(VsmClient client, const char* destContainer,
return getClient(client).vsm_file_move_request(destContainer, path);
}
-API VsmStatus vsm_notification(VsmClient client,
- VsmNotificationCallback notificationCallback,
- void* data)
+API VsmStatus vsm_add_notification_callback(VsmClient client,
+ VsmNotificationCallback notificationCallback,
+ void* data,
+ VsmSubscriptionId* subscriptionId)
+{
+ return getClient(client).vsm_add_notification_callback(notificationCallback, data, subscriptionId);
+}
+
+API VsmStatus vsm_del_notification_callback(VsmClient client,
+ VsmSubscriptionId subscriptionId)
{
- return getClient(client).vsm_notification(notificationCallback, data);
+ return getClient(client).vsm_del_notification_callback(subscriptionId);
}
diff --git a/client/security-containers-client.h b/client/security-containers-client.h
index 710af99..22a2a4e 100644
--- a/client/security-containers-client.h
+++ b/client/security-containers-client.h
@@ -115,6 +115,11 @@ typedef enum {
} VsmStatus;
/**
+ * Subscription id
+ */
+typedef unsigned int VsmSubscriptionId;
+
+/**
* Start glib loop.
*
* Do not call this function if an application creates a glib loop itself.
@@ -283,11 +288,24 @@ VsmStatus vsm_create_domain(VsmClient client, const char* id);
* @param[in] client security-containers-server's client
* @param[in] containerDbusStateCallback callback function
* @param[in] data some extra data that will be passed to callback function
+ * @param[out] subscriptionId subscription identifier that can be used to unsubscribe signal,
+ * pointer can be NULL.
* @return status of this function call
*/
VsmStatus vsm_add_state_callback(VsmClient client,
VsmContainerDbusStateCallback containerDbusStateCallback,
- void* data);
+ void* data,
+ VsmSubscriptionId* subscriptionId);
+
+/**
+ * Unregister dbus state change callback function.
+ *
+ * @param[in] client security-containers-server's client
+ * @param[in] subscriptionId subscription identifier returned by vsm_add_state_callback
+ * @return status of this function call
+ */
+VsmStatus vsm_del_state_callback(VsmClient client, VsmSubscriptionId subscriptionId);
+
/** @} */ // Host API
@@ -306,7 +324,7 @@ VsmStatus vsm_add_state_callback(VsmClient client,
* @param[in] container source container
* @param[in] application sending application name
* @param[in] message notification message
- * @param data custom user's data pointer passed to vsm_notification()
+ * @param data custom user's data pointer passed to vsm_add_notification_callback()
*/
typedef void (*VsmNotificationCallback)(const char* container,
const char* application,
@@ -340,9 +358,23 @@ VsmStatus vsm_file_move_request(VsmClient client, const char* destContainer, con
* @param[in] client security-containers-server's client
* @param[in] notificationCallback callback function
* @param[in] data some extra data that will be passed to callback function
+ * @param[out] subscriptionId subscription identifier that can be used to unsubscribe signal,
+ * pointer can be NULL.
+ * @return status of this function call
+ */
+VsmStatus vsm_add_notification_callback(VsmClient client,
+ VsmNotificationCallback notificationCallback,
+ void* data,
+ VsmSubscriptionId* subscriptionId);
+
+/**
+ * Unregister notification callback function.
+ *
+ * @param[in] client security-containers-server's client
+ * @param[in] subscriptionId subscription identifier returned by vsm_add_notification_callback
* @return status of this function call
*/
-VsmStatus vsm_notification(VsmClient client, VsmNotificationCallback notificationCallback, void* data);
+VsmStatus vsm_del_notification_callback(VsmClient client, VsmSubscriptionId subscriptionId);
/** @} */ // Domain API
diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp
index 184659e..f26dbf3 100644
--- a/tests/unit_tests/client/ut-client.cpp
+++ b/tests/unit_tests/client/ut-client.cpp
@@ -256,7 +256,10 @@ BOOST_AUTO_TEST_CASE(NotificationTest)
clients[it.first] = client;
}
for (auto& client : clients) {
- VsmStatus status = vsm_notification(client.second, callback, &callbackData);
+ VsmStatus status = vsm_add_notification_callback(client.second,
+ callback,
+ &callbackData,
+ NULL);
BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
}
for (auto& client : clients) {
--
2.7.4
From b25dcc4c14d972123e109517585ff36989d05d1a Mon Sep 17 00:00:00 2001
From: Jan Olszak
Date: Mon, 3 Nov 2014 08:52:00 +0200
Subject: [PATCH 10/16] IPC via UX sockets
[Bug/Feature] IPC for communication between the library and daemon
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I9880c7b4f3104b93f38d0e6ad86762fb17013d28
---
common/ipc/client.cpp | 80 +++++++
common/ipc/client.hpp | 156 +++++++++++++
common/ipc/exception.hpp | 45 ++++
common/ipc/internals/acceptor.cpp | 131 +++++++++++
common/ipc/internals/acceptor.hpp | 87 +++++++
common/ipc/internals/event-queue.hpp | 112 +++++++++
common/ipc/internals/eventfd.cpp | 77 +++++++
common/ipc/internals/eventfd.hpp | 62 +++++
common/ipc/internals/processor.cpp | 434 +++++++++++++++++++++++++++++++++++
common/ipc/internals/processor.hpp | 418 +++++++++++++++++++++++++++++++++
common/ipc/internals/socket.cpp | 200 ++++++++++++++++
common/ipc/internals/socket.hpp | 116 ++++++++++
common/ipc/internals/utils.cpp | 134 +++++++++++
common/ipc/internals/utils.hpp | 77 +++++++
common/ipc/service.cpp | 86 +++++++
common/ipc/service.hpp | 168 ++++++++++++++
common/ipc/types.hpp | 48 ++++
packaging/security-containers.spec | 1 +
server/CMakeLists.txt | 2 +-
tests/unit_tests/CMakeLists.txt | 3 +-
tests/unit_tests/ipc/ut-ipc.cpp | 391 +++++++++++++++++++++++++++++++
21 files changed, 2826 insertions(+), 2 deletions(-)
create mode 100644 common/ipc/client.cpp
create mode 100644 common/ipc/client.hpp
create mode 100644 common/ipc/exception.hpp
create mode 100644 common/ipc/internals/acceptor.cpp
create mode 100644 common/ipc/internals/acceptor.hpp
create mode 100644 common/ipc/internals/event-queue.hpp
create mode 100644 common/ipc/internals/eventfd.cpp
create mode 100644 common/ipc/internals/eventfd.hpp
create mode 100644 common/ipc/internals/processor.cpp
create mode 100644 common/ipc/internals/processor.hpp
create mode 100644 common/ipc/internals/socket.cpp
create mode 100644 common/ipc/internals/socket.hpp
create mode 100644 common/ipc/internals/utils.cpp
create mode 100644 common/ipc/internals/utils.hpp
create mode 100644 common/ipc/service.cpp
create mode 100644 common/ipc/service.hpp
create mode 100644 common/ipc/types.hpp
create mode 100644 tests/unit_tests/ipc/ut-ipc.cpp
diff --git a/common/ipc/client.cpp b/common/ipc/client.cpp
new file mode 100644
index 0000000..c1651f3
--- /dev/null
+++ b/common/ipc/client.cpp
@@ -0,0 +1,80 @@
+/*
+* 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 Handling client connections
+ */
+
+#include "config.hpp"
+
+#include "ipc/client.hpp"
+#include "ipc/internals/socket.hpp"
+#include "ipc/exception.hpp"
+
+namespace security_containers {
+namespace ipc {
+
+Client::Client(const std::string& socketPath)
+ : mSocketPath(socketPath)
+{
+ LOGD("Creating client");
+}
+
+Client::~Client()
+{
+ LOGD("Destroying client...");
+ try {
+ stop();
+ } catch (IPCException& e) {
+ LOGE("Error in Client's destructor: " << e.what());
+ }
+ LOGD("Destroyed client");
+}
+
+void Client::start()
+{
+ LOGD("Starting client...");
+
+ // Initialize the connection with the server
+ LOGD("Connecting to " + mSocketPath);
+ auto socketPtr = std::make_shared(Socket::connectSocket(mSocketPath));
+ mServiceID = mProcessor.addPeer(socketPtr);
+
+ // Start listening
+ mProcessor.start();
+
+ LOGD("Started client");
+}
+
+void Client::stop()
+{
+ LOGD("Stopping client...");
+ mProcessor.stop();
+ LOGD("Stopped");
+}
+
+void Client::removeMethod(const MethodID methodID)
+{
+ LOGD("Removing method id: " << methodID);
+ mProcessor.removeMethod(methodID);
+}
+
+} // namespace ipc
+} // namespace security_containers
diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp
new file mode 100644
index 0000000..7429b24
--- /dev/null
+++ b/common/ipc/client.hpp
@@ -0,0 +1,156 @@
+/*
+* 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 Handling client connections
+ */
+
+#ifndef COMMON_IPC_CLIENT_HPP
+#define COMMON_IPC_CLIENT_HPP
+
+#include "ipc/internals/processor.hpp"
+#include "ipc/types.hpp"
+#include "logger/logger.hpp"
+
+#include
+
+namespace security_containers {
+namespace ipc {
+
+/**
+ * This class wraps communication via UX sockets for client applications.
+ * It uses serialization mechanism from libConfig.
+ *
+ * There is one additional thread:
+ * - PROCESSOR is responsible for the communication and calling the callbacks
+ *
+ * For message format @see ipc::Processor
+ */
+class Client {
+public:
+ typedef Processor::MethodID MethodID;
+
+ /**
+ * @param serverPath path to the server's socket
+ */
+ Client(const std::string& serverPath);
+ ~Client();
+
+ Client(const Client&) = delete;
+ Client& operator=(const Client&) = delete;
+
+ /**
+ * Starts the worker thread
+ */
+ void start();
+
+ /**
+ * Stops all worker thread
+ */
+ void stop();
+
+ /**
+ * Saves the callback connected to the method id.
+ * When a message with the given method id is received
+ * the data will be parsed and passed to this callback.
+ *
+ * @param methodID API dependent id of the method
+ * @param methodCallback method handling implementation
+ */
+ template
+ void addMethodHandler(const MethodID methodID,
+ const typename MethodHandler::type& method);
+
+ /**
+ * Removes the callback
+ *
+ * @param methodID API dependent id of the method
+ */
+ void removeMethod(const MethodID methodID);
+
+ /**
+ * Synchronous method call.
+ *
+ * @param methodID API dependent id of the method
+ * @param data data to send
+ * @param timeoutMS how long to wait for the return value before throw
+ * @return result data
+ */
+ template
+ std::shared_ptr callSync(const MethodID methodID,
+ const std::shared_ptr& data,
+ unsigned int timeoutMS = 500);
+
+ /**
+ * Asynchronous method call. The return callback will be called on
+ * return data arrival. It will be run in the PROCESSOR thread.
+ *
+ *
+ * @param methodID API dependent id of the method
+ * @param sendCallback callback for data serialization
+ * @param resultCallback callback for result serialization and handling
+ */
+ template
+ void callAsync(const MethodID methodID,
+ const std::shared_ptr& data,
+ const typename ResultHandler::type& resultCallback);
+
+private:
+ Processor::PeerID mServiceID;
+ Processor mProcessor;
+ std::string mSocketPath;
+};
+
+template
+void Client::addMethodHandler(const MethodID methodID,
+ const typename MethodHandler::type& method)
+{
+ LOGD("Adding method with id " << methodID);
+ mProcessor.addMethodHandler(methodID, method);
+ LOGD("Added method with id " << methodID);
+}
+
+template
+std::shared_ptr Client::callSync(const MethodID methodID,
+ const std::shared_ptr& data,
+ unsigned int timeoutMS)
+{
+ LOGD("Sync calling method: " << methodID);
+ return mProcessor.callSync(methodID, mServiceID, data, timeoutMS);
+}
+
+template
+void Client::callAsync(const MethodID methodID,
+ const std::shared_ptr& data,
+ const typename ResultHandler::type& resultCallback)
+{
+ LOGD("Async calling method: " << methodID);
+ mProcessor.callAsync(methodID,
+ mServiceID,
+ data,
+ resultCallback);
+ LOGD("Async called method: " << methodID);
+}
+
+} // namespace ipc
+} // namespace security_containers
+
+#endif // COMMON_IPC_CLIENT_HPP
diff --git a/common/ipc/exception.hpp b/common/ipc/exception.hpp
new file mode 100644
index 0000000..67d9c86
--- /dev/null
+++ b/common/ipc/exception.hpp
@@ -0,0 +1,45 @@
+/*
+ * 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 Exceptions for the IPC
+ */
+
+
+#ifndef COMMON_IPC_EXCEPTION_HPP
+#define COMMON_IPC_EXCEPTION_HPP
+
+#include "base-exception.hpp"
+
+namespace security_containers {
+
+
+/**
+ * Base class for exceptions in IPC
+ */
+struct IPCException: public SecurityContainersException {
+ IPCException(const std::string& error) : SecurityContainersException(error) {}
+};
+
+
+}
+
+
+#endif // COMMON_IPC_EXCEPTION_HPP
diff --git a/common/ipc/internals/acceptor.cpp b/common/ipc/internals/acceptor.cpp
new file mode 100644
index 0000000..9738546
--- /dev/null
+++ b/common/ipc/internals/acceptor.cpp
@@ -0,0 +1,131 @@
+/*
+* 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 accepting new connections
+ */
+
+#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 security_containers {
+namespace ipc {
+
+Acceptor::Acceptor(const std::string& socketPath, const NewConnectionCallback& newConnectionCallback)
+ : mNewConnectionCallback(newConnectionCallback),
+ mSocket(Socket::createSocket(socketPath))
+{
+ LOGT("Creating Acceptor for socket " << socketPath);
+}
+
+Acceptor::~Acceptor()
+{
+ LOGT("Destroying Acceptor");
+ try {
+ stop();
+ } catch (IPCException& e) {
+ LOGE("Error in destructor: " << e.what());
+ }
+ LOGT("Destroyed Acceptor");
+}
+
+void Acceptor::start()
+{
+ LOGT("Starting Acceptor");
+ if (!mThread.joinable()) {
+ mThread = std::thread(&Acceptor::run, this);
+ }
+ LOGT("Started Acceptor");
+}
+
+void Acceptor::stop()
+{
+ LOGT("Stopping Acceptor");
+ if (mThread.joinable()) {
+ LOGT("Event::FINISH -> Acceptor");
+ mEventQueue.send(Event::FINISH);
+ LOGT("Waiting for Acceptor to finish");
+ mThread.join();
+ }
+ LOGT("Stopped Acceptor");
+}
+
+void Acceptor::run()
+{
+ // Setup polling structure
+ std::vector fds(2);
+
+ fds[0].fd = mEventQueue.getFD();
+ fds[0].events = POLLIN;
+
+ fds[1].fd = mSocket.getFD();
+ fds[1].events = POLLIN;
+
+ // Main loop
+ bool isRunning = true;
+ while (isRunning) {
+ LOGT("Waiting for new connections...");
+
+ int ret = ::poll(fds.data(), fds.size(), -1 /*blocking call*/);
+
+ LOGT("...Incoming connection!");
+
+ if (ret == -1 || ret == 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ LOGE("Error in poll: " << std::string(strerror(errno)));
+ throw IPCException("Error in poll: " + std::string(strerror(errno)));
+ break;
+ }
+
+ // Check for incoming connections
+ if (fds[1].revents & POLLIN) {
+ fds[1].revents = 0;
+ std::shared_ptr tmpSocket = mSocket.accept();
+ mNewConnectionCallback(tmpSocket);
+ }
+
+ // Check for incoming events
+ if (fds[0].revents & POLLIN) {
+ fds[0].revents = 0;
+
+ if (mEventQueue.receive() == Event::FINISH) {
+ LOGD("Event FINISH");
+ isRunning = false;
+ break;
+ }
+ }
+ }
+ LOGT("Exiting run");
+}
+
+} // namespace ipc
+} // namespace security_containers
diff --git a/common/ipc/internals/acceptor.hpp b/common/ipc/internals/acceptor.hpp
new file mode 100644
index 0000000..b863400
--- /dev/null
+++ b/common/ipc/internals/acceptor.hpp
@@ -0,0 +1,87 @@
+/*
+* 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 accepting new connections
+ */
+
+#ifndef COMMON_IPC_INTERNALS_ACCEPTOR_HPP
+#define COMMON_IPC_INTERNALS_ACCEPTOR_HPP
+
+#include "config.hpp"
+
+#include "ipc/internals/socket.hpp"
+#include "ipc/internals/event-queue.hpp"
+
+#include
+#include
+
+namespace security_containers {
+namespace ipc {
+
+/**
+ * Accepts new connections and passes the new socket to a callback.
+ */
+class Acceptor {
+public:
+
+ typedef std::function& socketPtr)> NewConnectionCallback;
+
+ /**
+ * Class for accepting new connections.
+ *
+ * @param socketPath path to the socket
+ * @param newConnectionCallback called on new connections
+ */
+ Acceptor(const std::string& socketPath,
+ const NewConnectionCallback& newConnectionCallback);
+ ~Acceptor();
+
+ Acceptor(const Acceptor& acceptor) = delete;
+ Acceptor& operator=(const Acceptor&) = delete;
+
+ /**
+ * Starts the thread accepting the new connections.
+ */
+ void start();
+
+ /**
+ * Stops the accepting thread.
+ */
+ void stop();
+
+private:
+ enum class Event : int {
+ FINISH // Shutdown request
+ };
+
+ NewConnectionCallback mNewConnectionCallback;
+ Socket mSocket;
+
+ EventQueue mEventQueue;
+ std::thread mThread;
+
+ void run();
+};
+
+} // namespace ipc
+} // namespace security_containers
+
+#endif // COMMON_IPC_INTERNALS_ACCEPTOR_HPP
diff --git a/common/ipc/internals/event-queue.hpp b/common/ipc/internals/event-queue.hpp
new file mode 100644
index 0000000..82cb2ff
--- /dev/null
+++ b/common/ipc/internals/event-queue.hpp
@@ -0,0 +1,112 @@
+/*
+* 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 passing events using eventfd mechanism
+ */
+
+#ifndef COMMON_IPC_INTERNALS_EVENT_QUEUE_HPP
+#define COMMON_IPC_INTERNALS_EVENT_QUEUE_HPP
+
+#include "ipc/exception.hpp"
+#include "ipc/internals/eventfd.hpp"
+#include "logger/logger.hpp"
+
+#include
+#include
+#include
+
+namespace security_containers {
+namespace ipc {
+
+
+/**
+ * This class implements a simple FIFO queue of events.
+ * One can listen for the event with select/poll/epoll.
+ *
+ * @tparam MessageType type to pass as event's value
+ */
+template
+class EventQueue {
+public:
+ EventQueue() = default;
+ ~EventQueue() = default;
+ EventQueue(const EventQueue& eventQueue) = delete;
+ EventQueue& operator=(const EventQueue&) = delete;
+
+ /**
+ * @return reference to the event's file descriptor
+ */
+ int getFD() const;
+
+ /**
+ * Send an event of a given value
+ *
+ * @param value size of the buffer
+ */
+ void send(const MessageType& mess);
+
+ /**
+ * Receives the signal.
+ * Blocks if there is no event.
+ *
+ * @return event's value
+ */
+ MessageType receive();
+
+private:
+ typedef std::lock_guard Lock;
+
+ std::mutex mCommunicationMutex;
+ std::queue mMessages;
+
+ EventFD mEventFD;
+};
+
+template
+int EventQueue::getFD() const
+{
+ return mEventFD.getFD();
+}
+
+template
+void EventQueue::send(const MessageType& mess)
+{
+ Lock lock(mCommunicationMutex);
+ LOGT("Sending event");
+ mMessages.push(mess);
+ mEventFD.send();
+}
+
+template
+MessageType EventQueue::receive()
+{
+ Lock lock(mCommunicationMutex);
+ mEventFD.receive();
+ LOGT("Received event");
+ MessageType mess = mMessages.front();
+ mMessages.pop();
+ return mess;
+}
+
+} // namespace ipc
+} // namespace security_containers
+
+#endif // COMMON_IPC_INTERNALS_EVENT_QUEUE_HPP
diff --git a/common/ipc/internals/eventfd.cpp b/common/ipc/internals/eventfd.cpp
new file mode 100644
index 0000000..c8a17b6
--- /dev/null
+++ b/common/ipc/internals/eventfd.cpp
@@ -0,0 +1,77 @@
+/*
+* 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 Linux socket wrapper
+ */
+
+#include "config.hpp"
+
+#include "ipc/internals/eventfd.hpp"
+#include "ipc/internals/utils.hpp"
+#include "ipc/exception.hpp"
+#include "logger/logger.hpp"
+
+#include
+#include
+#include
+#include
+
+namespace security_containers {
+namespace ipc {
+
+EventFD::EventFD()
+{
+ mFD = ::eventfd(0, EFD_SEMAPHORE);
+ if (mFD == -1) {
+ LOGE("Error in eventfd: " << std::string(strerror(errno)));
+ throw IPCException("Error in eventfd: " + std::string(strerror(errno)));
+ }
+}
+
+EventFD::~EventFD()
+{
+ try {
+ ipc::close(mFD);
+ } catch (IPCException& e) {
+ LOGE("Error in Event's destructor: " << e.what());
+ }
+}
+
+int EventFD::getFD() const
+{
+ return mFD;
+}
+
+void EventFD::send()
+{
+ const std::uint64_t toSend = 1;
+ ipc::write(mFD, &toSend, sizeof(toSend));
+}
+
+void EventFD::receive()
+{
+ std::uint64_t readBuffer;
+ ipc::read(mFD, &readBuffer, sizeof(readBuffer));
+}
+
+
+} // namespace ipc
+} // namespace security_containers
diff --git a/common/ipc/internals/eventfd.hpp b/common/ipc/internals/eventfd.hpp
new file mode 100644
index 0000000..9de6f17
--- /dev/null
+++ b/common/ipc/internals/eventfd.hpp
@@ -0,0 +1,62 @@
+/*
+* 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 Eventfd wrapper
+ */
+
+#ifndef COMMON_IPC_INTERNALS_EVENTFD_HPP
+#define COMMON_IPC_INTERNALS_EVENTFD_HPP
+
+namespace security_containers {
+namespace ipc {
+
+class EventFD {
+public:
+
+ EventFD();
+ ~EventFD();
+ EventFD(const EventFD& eventfd) = delete;
+ EventFD& operator=(const EventFD&) = delete;
+
+ /**
+ * @return event's file descriptor.
+ */
+ int getFD() const;
+
+ /**
+ * Send an event of a given value
+ */
+ void send();
+
+ /**
+ * Receives the signal.
+ * Blocks if there is no event.
+ */
+ void receive();
+
+private:
+ int mFD;
+};
+
+} // namespace ipc
+} // namespace security_containers
+
+#endif // COMMON_IPC_INTERNALS_EVENTFD_HPP
diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp
new file mode 100644
index 0000000..0465574
--- /dev/null
+++ b/common/ipc/internals/processor.cpp
@@ -0,0 +1,434 @@
+/*
+* 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 Data and event processing thread
+ */
+
+#include "config.hpp"
+
+#include "ipc/exception.hpp"
+#include "ipc/internals/processor.hpp"
+#include "ipc/internals/utils.hpp"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+
+namespace security_containers {
+namespace ipc {
+
+const Processor::MethodID Processor::RETURN_METHOD_ID = std::numeric_limits::max();
+
+Processor::Processor(const PeerCallback& newPeerCallback,
+ const PeerCallback& removedPeerCallback,
+ const unsigned int maxNumberOfPeers)
+ : mNewPeerCallback(newPeerCallback),
+ mRemovedPeerCallback(removedPeerCallback),
+ mMaxNumberOfPeers(maxNumberOfPeers),
+ mMessageIDCounter(0),
+ mPeerIDCounter(0)
+{
+ LOGT("Creating Processor");
+}
+
+Processor::~Processor()
+{
+ LOGT("Destroying Processor");
+ try {
+ stop();
+ } catch (IPCException& e) {
+ LOGE("Error in Processor's destructor: " << e.what());
+ }
+ LOGT("Destroyed Processor");
+}
+
+void Processor::start()
+{
+ LOGT("Starting Processor");
+ if (!mThread.joinable()) {
+ mThread = std::thread(&Processor::run, this);
+ }
+ LOGT("Started Processor");
+}
+
+void Processor::stop()
+{
+ LOGT("Stopping Processor");
+ if (mThread.joinable()) {
+ mEventQueue.send(Event::FINISH);
+ mThread.join();
+ }
+ LOGT("Stopped Processor");
+}
+
+void Processor::removeMethod(const MethodID methodID)
+{
+ LOGT("Removing method " << methodID);
+ Lock lock(mCallsMutex);
+ mMethodsCallbacks.erase(methodID);
+}
+
+Processor::PeerID Processor::addPeer(const std::shared_ptr& socketPtr)
+{
+ LOGT("Adding socket");
+ PeerID peerID;
+ {
+ Lock lock(mSocketsMutex);
+ peerID = getNextPeerID();
+ SocketInfo socketInfo;
+ socketInfo.peerID = peerID;
+ socketInfo.socketPtr = std::move(socketPtr);
+ mNewSockets.push(std::move(socketInfo));
+ }
+ LOGI("New peer added. Id: " << peerID);
+ mEventQueue.send(Event::NEW_PEER);
+
+ return peerID;
+}
+
+void Processor::removePeer(PeerID peerID)
+{
+ LOGW("Removing naughty peer. ID: " << peerID);
+ {
+ Lock lock(mSocketsMutex);
+ mSockets.erase(peerID);
+ }
+ resetPolling();
+}
+
+void Processor::resetPolling()
+{
+ LOGI("Resetting polling");
+ // Setup polling on eventfd and sockets
+ Lock lock(mSocketsMutex);
+ mFDs.resize(mSockets.size() + 1);
+
+ mFDs[0].fd = mEventQueue.getFD();
+ mFDs[0].events = POLLIN;
+
+ auto socketIt = mSockets.begin();
+ for (unsigned int i = 1; i < mFDs.size(); ++i) {
+ mFDs[i].fd = socketIt->second->getFD();
+ mFDs[i].events = POLLIN | POLLHUP; // Listen for input events
+ ++socketIt;
+ // TODO: It's possible to block on writing to fd. Maybe listen for POLLOUT too?
+ }
+}
+
+void Processor::run()
+{
+ resetPolling();
+
+ mIsRunning = true;
+ while (mIsRunning) {
+ LOGT("Waiting for communication...");
+ int ret = poll(mFDs.data(), mFDs.size(), -1 /*blocking call*/);
+ LOGT("... incoming communication!");
+ if (ret == -1 || ret == 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ LOGE("Error in poll: " << std::string(strerror(errno)));
+ throw IPCException("Error in poll: " + std::string(strerror(errno)));
+ }
+
+ // Check for lost connections:
+ if (handleLostConnections()) {
+ // mFDs changed
+ continue;
+ }
+
+ // Check for incoming data.
+ if (handleInputs()) {
+ // mFDs changed
+ continue;
+ }
+
+ // Check for incoming events
+ if (handleEvent()) {
+ // mFDs changed
+ continue;
+ }
+ }
+}
+
+bool Processor::handleLostConnections()
+{
+ std::list peersToRemove;
+
+ {
+ Lock lock(mSocketsMutex);
+ auto socketIt = mSockets.begin();
+ for (unsigned int i = 1; i < mFDs.size(); ++i, ++socketIt) {
+ if (mFDs[i].revents & POLLHUP) {
+ LOGI("Lost connection to peer: " << socketIt->first);
+ mFDs[i].revents &= ~(POLLHUP);
+ peersToRemove.push_back(socketIt->first);
+ }
+ }
+
+ for (const auto peerID : peersToRemove) {
+ LOGT("Removing peer. ID: " << peerID);
+ mSockets.erase(peerID);
+ }
+ }
+
+ if (!peersToRemove.empty()) {
+ resetPolling();
+ }
+
+ return !peersToRemove.empty();
+}
+
+bool Processor::handleInputs()
+{
+ std::list> > peersWithInput;
+ {
+ Lock lock(mSocketsMutex);
+ auto socketIt = mSockets.begin();
+ for (unsigned int i = 1; i < mFDs.size(); ++i, ++socketIt) {
+ if (mFDs[i].revents & POLLIN) {
+ mFDs[i].revents &= ~(POLLIN);
+ peersWithInput.push_back(*socketIt);
+ }
+ }
+ }
+
+ bool pollChanged = false;
+ // Handle input outside the critical section
+ for (const auto& peer : peersWithInput) {
+ pollChanged = pollChanged || handleInput(peer.first, *peer.second);
+ }
+ return pollChanged;
+}
+
+bool Processor::handleInput(const PeerID peerID, const Socket& socket)
+{
+ LOGT("Handle incoming data");
+ MethodID methodID;
+ MessageID messageID;
+ {
+ LOGI("Locking");
+ Socket::Guard guard = socket.getGuard();
+ socket.read(&methodID, sizeof(methodID));
+ socket.read(&messageID, sizeof(messageID));
+ LOGI("Locked");
+
+ if (methodID == RETURN_METHOD_ID) {
+ LOGI("Return value for messageID: " << messageID);
+ ReturnCallbacks returnCallbacks;
+ try {
+ Lock lock(mReturnCallbacksMutex);
+ LOGT("Getting the return callback");
+ returnCallbacks = std::move(mReturnCallbacks.at(messageID));
+ mReturnCallbacks.erase(messageID);
+ } catch (const std::out_of_range&) {
+ LOGW("No return callback for messageID: " << messageID);
+ return false;
+ }
+
+ std::shared_ptr data;
+ try {
+ LOGT("Parsing incoming return data");
+ data = returnCallbacks.parse(socket.getFD());
+ } catch (const IPCException&) {
+ removePeer(peerID);
+ return true;
+ }
+
+ guard.unlock();
+
+ LOGT("Process callback for methodID: " << methodID << "; messageID: " << messageID);
+ returnCallbacks.process(data);
+
+ } else {
+ LOGI("Remote call; methodID: " << methodID << " messageID: " << messageID);
+ std::shared_ptr methodCallbacks;
+ try {
+ Lock lock(mCallsMutex);
+ methodCallbacks = mMethodsCallbacks.at(methodID);
+ } catch (const std::out_of_range&) {
+ LOGW("No method callback for methodID: " << methodID);
+ removePeer(peerID);
+ return true;
+ }
+
+ std::shared_ptr data;
+ try {
+ LOGT("Parsing incoming data");
+ data = methodCallbacks->parse(socket.getFD());
+ } catch (const IPCException&) {
+ removePeer(peerID);
+ return true;
+ }
+
+ guard.unlock();
+
+ LOGT("Process callback for methodID: " << methodID << "; messageID: " << messageID);
+ std::shared_ptr returnData = methodCallbacks->method(data);
+
+ LOGT("Sending return data; methodID: " << methodID << "; messageID: " << messageID);
+ try {
+ // Send the call with the socket
+ Socket::Guard guard = socket.getGuard();
+ socket.write(&RETURN_METHOD_ID, sizeof(RETURN_METHOD_ID));
+ socket.write(&messageID, sizeof(messageID));
+ methodCallbacks->serialize(socket.getFD(), returnData);
+ } catch (const IPCException&) {
+ removePeer(peerID);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+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");
+ mIsRunning = false;
+ return false;
+ }
+
+ case Event::CALL: {
+ LOGD("Event CALL");
+ handleCall();
+ return false;
+ }
+
+ case Event::NEW_PEER: {
+ LOGD("Event NEW_PEER");
+ SocketInfo socketInfo;
+ {
+ Lock lock(mSocketsMutex);
+
+ socketInfo = std::move(mNewSockets.front());
+ mNewSockets.pop();
+
+ if (mSockets.size() > mMaxNumberOfPeers) {
+ LOGE("There are too many peers. I don't accept the connection with " << socketInfo.peerID);
+
+ }
+ if (mSockets.count(socketInfo.peerID) != 0) {
+ LOGE("There already was a socket for peerID: " << socketInfo.peerID);
+ }
+ mSockets[socketInfo.peerID] = socketInfo.socketPtr;
+ }
+ resetPolling();
+
+ if (mNewPeerCallback) {
+ // Notify about the new user.
+ mNewPeerCallback(socketInfo.peerID);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Processor::MessageID Processor::getNextMessageID()
+{
+ // TODO: This method of generating UIDs is buggy. To be changed.
+ return ++mMessageIDCounter;
+}
+
+Processor::PeerID Processor::getNextPeerID()
+{
+ // TODO: This method of generating UIDs is buggy. To be changed.
+ return ++mPeerIDCounter;
+}
+
+Processor::Call Processor::getCall()
+{
+ Lock lock(mCallsMutex);
+ if (mCalls.empty()) {
+ LOGE("Calls queue empty");
+ throw IPCException("Calls queue empty");
+ }
+ Call call = std::move(mCalls.front());
+ mCalls.pop();
+ return call;
+}
+
+void Processor::handleCall()
+{
+ LOGT("Handle call from another thread");
+ Call call = getCall();
+
+ ReturnCallbacks returnCallbacks;
+ returnCallbacks.parse = call.parse;
+ returnCallbacks.process = call.process;
+
+ std::shared_ptr socketPtr;
+ try {
+ // Get the addressee's socket
+ Lock lock(mSocketsMutex);
+ socketPtr = mSockets.at(call.peerID);
+ } catch (const std::out_of_range&) {
+ LOGE("Peer disconnected. No socket with a peerID: " << call.peerID);
+ return;
+ }
+
+ MessageID messageID = getNextMessageID();
+
+ {
+ // Set what to do with the return message
+ Lock lock(mReturnCallbacksMutex);
+ if (mReturnCallbacks.count(messageID) != 0) {
+ LOGE("There already was a return callback for messageID: " << messageID);
+ }
+ mReturnCallbacks[messageID] = std::move(returnCallbacks);
+ }
+
+ try {
+ // Send the call with the socket
+ Socket::Guard guard = socketPtr->getGuard();
+ socketPtr->write(&call.methodID, sizeof(call.methodID));
+ socketPtr->write(&messageID, sizeof(messageID));
+ call.serialize(socketPtr->getFD(), call.data);
+ } catch (const std::exception& e) {
+ LOGE("Error during sending a message: " << e.what());
+ {
+ Lock lock(mReturnCallbacksMutex);
+ mReturnCallbacks.erase(messageID);
+ }
+ // TODO: User should get the error code.
+ }
+}
+
+} // namespace ipc
+} // namespace security_containers
diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp
new file mode 100644
index 0000000..cb14a67
--- /dev/null
+++ b/common/ipc/internals/processor.hpp
@@ -0,0 +1,418 @@
+/*
+* 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 Data and event processing thread
+ */
+
+#ifndef COMMON_IPC_INTERNALS_PROCESSOR_HPP
+#define COMMON_IPC_INTERNALS_PROCESSOR_HPP
+
+#include "ipc/internals/socket.hpp"
+#include "ipc/internals/event-queue.hpp"
+#include "ipc/exception.hpp"
+#include "ipc/types.hpp"
+#include "config/manager.hpp"
+#include "config/is-visitable.hpp"
+#include "logger/logger.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace security_containers {
+namespace ipc {
+namespace {
+const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
+}
+/**
+* This class wraps communication via UX sockets
+*
+* It's intended to be used both in Client and Service classes.
+* It uses a serialization mechanism from libConfig.
+* Library user will only have to pass the types that each call will send and receive
+*
+* Message format:
+* - MethodID - probably casted enum.
+* MethodID == std::numeric_limits::max() is reserved for return messages
+* - MessageID - unique id of a message exchange sent by this object instance. Used to identify reply messages.
+* - Rest: The data written in a callback. One type per method.ReturnCallbacks
+*
+* TODO:
+* - error codes passed to async callbacks
+* - remove ReturnCallbacks on peer disconnect
+* - on sync timeout erase the return callback
+* - don't throw timeout if the message is already processed
+* - naming convention or methods that just commissions the PROCESS thread to do something
+* - removePeer API function
+*/
+class Processor {
+public:
+ typedef std::function PeerCallback;
+ typedef unsigned int PeerID;
+ typedef unsigned int MethodID;
+
+ /**
+ * Method ID. Used to indicate a message with the return value.
+ */
+ static const MethodID RETURN_METHOD_ID;
+ /**
+ * Constructs the Processor, but doesn't start it.
+ * The object is ready to add methods.
+ *
+ * @param newPeerCallback called when a new peer arrives
+ * @param removedPeerCallback called when the Processor stops listening for this peer
+ */
+ Processor(const PeerCallback& newPeerCallback = nullptr,
+ const PeerCallback& removedPeerCallback = nullptr,
+ const unsigned int maxNumberOfPeers = DEFAULT_MAX_NUMBER_OF_PEERS);
+ ~Processor();
+
+ Processor(const Processor&) = delete;
+ Processor(Processor&&) = delete;
+ Processor& operator=(const Processor&) = delete;
+
+ /**
+ * Start the processing thread.
+ * Quits immediately after starting the thread.
+ */
+ void start();
+
+ /**
+ * Stops the processing thread.
+ * No incoming data will be handled after.
+ */
+ void stop();
+
+ /**
+ * From now on socket is owned by the Processor object.
+ * Calls the newPeerCallback.
+ *
+ * @param socketPtr pointer to the new socket
+ * @return peerID of the new socket
+ */
+ PeerID addPeer(const std::shared_ptr& socketPtr);
+
+ /**
+ * Saves the callbacks connected to the method id.
+ * When a message with the given method id is received,
+ * the data will be passed to the serialization callback through file descriptor.
+ *
+ * Then the process callback will be called with the parsed data.
+ *
+ * @param methodID API dependent id of the method
+ * @param process data processing callback
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
+ */
+ template
+ void addMethodHandler(const MethodID methodID,
+ const typename MethodHandler::type& process);
+
+ /**
+ * Removes the callback
+ *
+ * @param methodID API dependent id of the method
+ */
+ void removeMethod(const MethodID methodID);
+
+ /**
+ * Synchronous method call.
+ *
+ * @param methodID API dependent id of the method
+ * @param peerID id of the peer
+ * @param data data to sent
+ * @param timeoutMS how long to wait for the return value before throw
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
+ */
+ template
+ std::shared_ptr callSync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ unsigned int timeoutMS = 500);
+
+ /**
+ * Asynchronous method call
+ *
+ * @param methodID API dependent id of the method
+ * @param peerID id of the peer
+ * @param data data to sent
+ * @param process callback processing the return data
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
+ */
+ template
+ void callAsync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ const typename ResultHandler::type& process);
+
+
+private:
+ typedef std::function& data)> SerializeCallback;
+ typedef std::function(int fd)> ParseCallback;
+ typedef std::lock_guard Lock;
+ typedef unsigned int MessageID;
+
+ struct Call {
+ Call(const Call& other) = delete;
+ Call& operator=(const Call&) = delete;
+ Call() = default;
+ Call(Call&&) = default;
+
+ PeerID peerID;
+ MethodID methodID;
+ std::shared_ptr data;
+ SerializeCallback serialize;
+ ParseCallback parse;
+ ResultHandler::type process;
+ };
+
+ struct MethodHandlers {
+ MethodHandlers(const MethodHandlers& other) = delete;
+ MethodHandlers& operator=(const MethodHandlers&) = delete;
+ MethodHandlers() = default;
+ MethodHandlers(MethodHandlers&&) = default;
+ MethodHandlers& operator=(MethodHandlers &&) = default;
+
+ SerializeCallback serialize;
+ ParseCallback parse;
+ MethodHandler::type method;
+ };
+
+ struct ReturnCallbacks {
+ ReturnCallbacks(const ReturnCallbacks& other) = delete;
+ ReturnCallbacks& operator=(const ReturnCallbacks&) = delete;
+ ReturnCallbacks() = default;
+ ReturnCallbacks(ReturnCallbacks&&) = default;
+ ReturnCallbacks& operator=(ReturnCallbacks &&) = default;
+
+ ParseCallback parse;
+ ResultHandler::type process;
+ };
+
+ struct SocketInfo {
+ SocketInfo(const SocketInfo& other) = delete;
+ SocketInfo& operator=(const SocketInfo&) = delete;
+ SocketInfo() = default;
+ SocketInfo(SocketInfo&&) = default;
+ SocketInfo& operator=(SocketInfo &&) = default;
+
+ std::shared_ptr socketPtr;
+ PeerID peerID;
+ };
+
+ enum class Event : int {
+ FINISH, // Shutdown request
+ CALL, // New method call in the queue
+ NEW_PEER // New peer in the queue
+ };
+ EventQueue mEventQueue;
+
+
+ bool mIsRunning;
+
+ // Mutex for the Calls queue and the map of methods.
+ std::mutex mCallsMutex;
+ std::queue mCalls;
+ std::unordered_map> mMethodsCallbacks;
+
+ // Mutex for changing mSockets map.
+ // Shouldn't be locked on any read/write, that could block. Just copy the ptr.
+ std::mutex mSocketsMutex;
+ std::unordered_map > mSockets;
+ std::queue mNewSockets;
+
+ // Mutex for modifying the map with return callbacks
+ std::mutex mReturnCallbacksMutex;
+ std::unordered_map mReturnCallbacks;
+
+
+ PeerCallback mNewPeerCallback;
+ PeerCallback mRemovedPeerCallback;
+
+ unsigned int mMaxNumberOfPeers;
+
+ std::thread mThread;
+ std::vector mFDs;
+
+ std::atomic mMessageIDCounter;
+ std::atomic mPeerIDCounter;
+
+ void run();
+ bool handleEvent();
+ void handleCall();
+ bool handleLostConnections();
+ bool handleInputs();
+ bool handleInput(const PeerID peerID, const Socket& socket);
+ void resetPolling();
+ MessageID getNextMessageID();
+ PeerID getNextPeerID();
+ Call getCall();
+ void removePeer(PeerID peerID);
+
+};
+
+template
+void Processor::addMethodHandler(const MethodID methodID,
+ const typename MethodHandler::type& method)
+{
+ static_assert(config::isVisitable::value,
+ "Use the libConfig library");
+ static_assert(config::isVisitable::value,
+ "Use the libConfig library");
+
+ if (methodID == RETURN_METHOD_ID) {
+ LOGE("Forbidden methodID: " << methodID);
+ throw IPCException("Forbidden methodID: " + std::to_string(methodID));
+ }
+
+ using namespace std::placeholders;
+
+ MethodHandlers methodCall;
+
+ methodCall.parse = [](const int fd)->std::shared_ptr {
+ std::shared_ptr data(new ReceivedDataType());
+ config::loadFromFD(fd, *data);
+ return data;
+ };
+
+ methodCall.serialize = [](const int fd, std::shared_ptr& data)->void {
+ config::saveToFD(fd, *std::static_pointer_cast(data));
+ };
+
+ methodCall.method = [method](std::shared_ptr& data)->std::shared_ptr {
+ std::shared_ptr tmpData = std::static_pointer_cast(data);
+ return method(tmpData);
+ };
+
+ {
+ Lock lock(mCallsMutex);
+ mMethodsCallbacks[methodID] = std::make_shared(std::move(methodCall));
+ }
+}
+
+template
+void Processor::callAsync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ const typename ResultHandler::type& process)
+{
+ static_assert(config::isVisitable::value,
+ "Use the libConfig library");
+ static_assert(config::isVisitable::value,
+ "Use the libConfig library");
+
+ if (!mThread.joinable()) {
+ 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.");
+ }
+
+ using namespace std::placeholders;
+
+ Call call;
+ call.peerID = peerID;
+ call.methodID = methodID;
+ call.data = data;
+
+ call.parse = [](const int fd)->std::shared_ptr {
+ std::shared_ptr data(new ReceivedDataType());
+ config::loadFromFD(fd, *data);
+ return data;
+ };
+
+ call.serialize = [](const int fd, std::shared_ptr& data)->void {
+ config::saveToFD(fd, *std::static_pointer_cast(data));
+ };
+
+ call.process = [process](std::shared_ptr& data)->void {
+ std::shared_ptr tmpData = std::static_pointer_cast(data);
+ return process(tmpData);
+ };
+
+ {
+ Lock lock(mCallsMutex);
+ mCalls.push(std::move(call));
+ }
+
+ mEventQueue.send(Event::CALL);
+}
+
+
+template
+std::shared_ptr Processor::callSync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ unsigned int timeoutMS)
+{
+ static_assert(config::isVisitable::value,
+ "Use the libConfig library");
+ static_assert(config::isVisitable::value,
+ "Use the libConfig library");
+
+ if (!mThread.joinable()) {
+ 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::shared_ptr result;
+
+ std::mutex mtx;
+ std::unique_lock lck(mtx);
+ std::condition_variable cv;
+
+ auto process = [&result, &cv](std::shared_ptr returnedData) {
+ result = returnedData;
+ cv.notify_one();
+ };
+
+ callAsync(methodID,
+ peerID,
+ data,
+ process);
+
+ auto isResultInitialized = [&result]() {
+ return static_cast(result);
+ };
+
+ if (!cv.wait_for(lck, std::chrono::milliseconds(timeoutMS), isResultInitialized)) {
+ LOGE("Function call timeout; methodID: " << methodID);
+ throw IPCException("Function call timeout; methodID: " + std::to_string(methodID));
+ }
+
+ return result;
+}
+
+
+} // namespace ipc
+} // namespace security_containers
+
+#endif // COMMON_IPC_INTERNALS_PROCESSOR_HPP
diff --git a/common/ipc/internals/socket.cpp b/common/ipc/internals/socket.cpp
new file mode 100644
index 0000000..002b9cf
--- /dev/null
+++ b/common/ipc/internals/socket.cpp
@@ -0,0 +1,200 @@
+/*
+* 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 Linux socket wrapper
+ */
+
+#include "config.hpp"
+
+#include "ipc/exception.hpp"
+#include "ipc/internals/socket.hpp"
+#include "ipc/internals/utils.hpp"
+#include "logger/logger.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+namespace security_containers {
+namespace ipc {
+
+namespace {
+const int MAX_QUEUE_LENGTH = 1000;
+}
+
+Socket::Socket(int socketFD)
+ : mFD(socketFD)
+{
+}
+
+Socket::Socket(Socket&& socket)
+ : mFD(socket.mFD)
+{
+ socket.mFD = -1;
+}
+
+Socket::~Socket()
+{
+ try {
+ ipc::close(mFD);
+ } catch (IPCException& e) {
+ LOGE("Error in Socket's destructor: " << e.what());
+ }
+}
+
+Socket::Guard Socket::getGuard() const
+{
+ return Guard(mCommunicationMutex);
+}
+
+int Socket::getFD() const
+{
+ return mFD;
+}
+
+std::shared_ptr Socket::accept()
+{
+ int sockfd = ::accept(mFD, nullptr, nullptr);
+ if (sockfd == -1) {
+ LOGE("Error in accept: " << std::string(strerror(errno)));
+ IPCException("Error in accept: " + std::string(strerror(errno)));
+ }
+ return std::make_shared(sockfd);
+}
+
+void Socket::write(const void* bufferPtr, const size_t size) const
+{
+ Guard guard(mCommunicationMutex);
+ ipc::write(mFD, bufferPtr, size);
+}
+
+void Socket::read(void* bufferPtr, const size_t size) const
+{
+ Guard guard(mCommunicationMutex);
+ ipc::read(mFD, bufferPtr, size);
+}
+
+int Socket::getSystemdSocket(const std::string& path)
+{
+ int n = ::sd_listen_fds(-1 /*Block further calls to sd_listen_fds*/);
+ if (n < 0) {
+ LOGE("sd_listen_fds fails with errno: " + n);
+ throw IPCException("sd_listen_fds fails with errno: " + n);
+ }
+
+ for (int fd = SD_LISTEN_FDS_START;
+ fd < SD_LISTEN_FDS_START + n;
+ ++fd) {
+ if (0 < ::sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, 1, path.c_str(), 0)) {
+ return fd;
+ }
+ }
+ LOGW("No usable sockets were passed by systemd.");
+ return -1;
+}
+
+int Socket::createDomainSocket(const std::string& path)
+{
+ // Isn't the path too long?
+ if (path.size() >= sizeof(sockaddr_un::sun_path)) {
+ LOGE("Socket's path too long");
+ throw IPCException("Socket's path too long");
+ }
+
+ int sockfd = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ LOGE("Error in socket: " + std::string(strerror(errno)));
+ throw IPCException("Error in socket: " + std::string(strerror(errno)));
+ }
+
+ ::sockaddr_un serverAddress;
+ serverAddress.sun_family = AF_UNIX;
+ ::strncpy(serverAddress.sun_path, path.c_str(), sizeof(sockaddr_un::sun_path));
+ unlink(serverAddress.sun_path);
+
+ // Everybody can access the socket
+ // TODO: Use SMACK to guard the socket
+ if (-1 == ::bind(sockfd,
+ reinterpret_cast(&serverAddress),
+ sizeof(struct sockaddr_un))) {
+ std::string message = strerror(errno);
+ ::close(sockfd);
+ LOGE("Error in bind: " << message);
+ IPCException("Error in bind: " + message);
+ }
+
+ if (-1 == ::listen(sockfd,
+ MAX_QUEUE_LENGTH)) {
+ std::string message = strerror(errno);
+ ::close(sockfd);
+ LOGE("Error in listen: " << message);
+ IPCException("Error in listen: " + message);
+ }
+
+ return sockfd;
+}
+
+Socket Socket::createSocket(const std::string& path)
+{
+ // Initialize a socket
+ int fd = getSystemdSocket(path);
+ fd = fd != -1 ? fd : createDomainSocket(path);
+
+ return Socket(fd);
+}
+
+Socket Socket::connectSocket(const std::string& path)
+{
+ // Isn't the path too long?
+ if (path.size() >= sizeof(sockaddr_un::sun_path)) {
+ LOGE("Socket's path too long");
+ throw IPCException("Socket's path too long");
+ }
+
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ LOGE("Error in socket: " + std::string(strerror(errno)));
+ throw IPCException("Error in socket: " + std::string(strerror(errno)));
+ }
+
+ sockaddr_un serverAddress;
+ serverAddress.sun_family = AF_UNIX;
+ strncpy(serverAddress.sun_path, path.c_str(), sizeof(sockaddr_un::sun_path));
+
+ if (-1 == connect(fd,
+ reinterpret_cast(&serverAddress),
+ sizeof(struct sockaddr_un))) {
+ ::close(fd);
+ LOGE("Error in connect: " + std::string(strerror(errno)));
+ throw IPCException("Error in connect: " + std::string(strerror(errno)));
+ }
+
+ return Socket(fd);
+}
+
+} // namespace ipc
+} // namespace security_containers
diff --git a/common/ipc/internals/socket.hpp b/common/ipc/internals/socket.hpp
new file mode 100644
index 0000000..b7a6d40
--- /dev/null
+++ b/common/ipc/internals/socket.hpp
@@ -0,0 +1,116 @@
+/*
+* 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 Linux socket wrapper
+ */
+
+#ifndef COMMON_IPC_INTERNALS_SOCKET_HPP
+#define COMMON_IPC_INTERNALS_SOCKET_HPP
+
+#include
+#include
+#include
+
+namespace security_containers {
+namespace ipc {
+
+/**
+ * This class wraps all operations possible to do with a socket.
+ *
+ * It has operations both for client and server application.
+ */
+class Socket {
+public:
+
+ typedef std::unique_lock Guard;
+
+ /**
+ * Default constructor.
+ * If socketFD is passed then it's passed by the Socket
+ *
+ * @param socketFD socket obtained outside the class.
+ */
+ Socket(int socketFD = -1);
+ Socket(Socket&& socket);
+ ~Socket();
+ Socket& operator=(const Socket&) = delete;
+
+ /**
+ * @return reference to the socket's file descriptor
+ */
+ int getFD() const;
+
+ /**
+ * Write data using the file descriptor
+ *
+ * @param bufferPtr buffer with the data
+ * @param size size of the buffer
+ */
+ void write(const void* bufferPtr, const size_t size) const;
+
+ /**
+ * Reads a value of the given type.
+ *
+ * @param bufferPtr buffer with the data
+ * @param size size of the buffer
+ */
+ void read(void* bufferPtr, const size_t size) const;
+
+ /**
+ * Accepts connection. Used by a server application.
+ * Blocking, called by a server.
+ */
+ std::shared_ptr accept() ;
+
+ /**
+ */
+ Socket::Guard getGuard() const;
+
+
+ /**
+ * Prepares socket for accepting connections.
+ * Called by a server.
+ *
+ * @param path path to the socket
+ * @return created socket
+ */
+ static Socket createSocket(const std::string& path);
+
+ /**
+ * Connects to a socket. Called as a client.
+ *
+ * @param path path to the socket
+ * @return connected socket
+ */
+ static Socket connectSocket(const std::string& path);
+
+private:
+ int mFD;
+ mutable std::recursive_mutex mCommunicationMutex;
+
+ static int createDomainSocket(const std::string& path);
+ static int getSystemdSocket(const std::string& path);
+};
+
+} // namespace ipc
+} // namespace security_containers
+
+#endif // COMMON_IPC_INTERNALS_SOCKET_HPP
diff --git a/common/ipc/internals/utils.cpp b/common/ipc/internals/utils.cpp
new file mode 100644
index 0000000..e98b60d
--- /dev/null
+++ b/common/ipc/internals/utils.cpp
@@ -0,0 +1,134 @@
+/*
+* 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 Utility functions
+ */
+
+#include "config.hpp"
+
+#include "ipc/exception.hpp"
+#include "ipc/internals/utils.hpp"
+#include "logger/logger.hpp"
+
+#include
+#include
+#include
+
+#include
+#include
+
+namespace fs = boost::filesystem;
+
+namespace security_containers {
+namespace ipc {
+
+void close(int fd)
+{
+ if (fd < 0) {
+ return;
+ }
+
+ for (;;) {
+ if (-1 == ::close(fd)) {
+ if (errno == EINTR) {
+ LOGD("Close interrupted by a signal, retrying");
+ continue;
+ }
+ LOGE("Error in close: " << std::string(strerror(errno)));
+ throw IPCException("Error in close: " + std::string(strerror(errno)));
+ }
+ break;
+ }
+}
+
+void write(int fd, const void* bufferPtr, const size_t size)
+{
+ size_t nTotal = 0;
+ int n;
+
+ do {
+ n = ::write(fd,
+ reinterpret_cast(bufferPtr) + nTotal,
+ size - nTotal);
+ if (n < 0) {
+ if (errno == EINTR) {
+ LOGD("Write interrupted by a signal, retrying");
+ continue;
+ }
+ LOGE("Error during writing: " + std::string(strerror(errno)));
+ throw IPCException("Error during witting: " + std::string(strerror(errno)));
+ }
+ nTotal += n;
+ } while (nTotal < size);
+}
+
+void read(int fd, void* bufferPtr, const size_t size)
+{
+ size_t nTotal = 0;
+ int n;
+
+ do {
+ n = ::read(fd,
+ reinterpret_cast(bufferPtr) + nTotal,
+ size - nTotal);
+ if (n < 0) {
+ if (errno == EINTR) {
+ LOGD("Read interrupted by a signal, retrying");
+ continue;
+ }
+ LOGE("Error during reading: " + std::string(strerror(errno)));
+ throw IPCException("Error during reading: " + std::string(strerror(errno)));
+ }
+ nTotal += n;
+ } while (nTotal < size);
+}
+
+unsigned int getMaxFDNumber()
+{
+ struct rlimit rlim;
+ if (-1 == getrlimit(RLIMIT_NOFILE, &rlim)) {
+ LOGE("Error during getrlimit: " + std::string(strerror(errno)));
+ throw IPCException("Error during getrlimit: " + std::string(strerror(errno)));
+ }
+ return rlim.rlim_cur;
+}
+
+void setMaxFDNumber(unsigned int limit)
+{
+ struct rlimit rlim;
+ rlim.rlim_cur = limit;
+ rlim.rlim_max = limit;
+ if (-1 == setrlimit(RLIMIT_NOFILE, &rlim)) {
+ LOGE("Error during setrlimit: " + std::string(strerror(errno)));
+ throw IPCException("Error during setrlimit: " + std::string(strerror(errno)));
+ }
+}
+
+unsigned int getFDNumber()
+{
+ const std::string path = "/proc/self/fd/";
+ return std::distance(fs::directory_iterator(path),
+ fs::directory_iterator());
+}
+
+} // namespace ipc
+} // namespace security_containers
+
diff --git a/common/ipc/internals/utils.hpp b/common/ipc/internals/utils.hpp
new file mode 100644
index 0000000..0b1815d
--- /dev/null
+++ b/common/ipc/internals/utils.hpp
@@ -0,0 +1,77 @@
+/*
+* 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 Utility functions
+ */
+
+#ifndef COMMON_IPC_INTERNALS_UTILS_HPP
+#define COMMON_IPC_INTERNALS_UTILS_HPP
+
+#include
+
+namespace security_containers {
+namespace ipc {
+
+/**
+ * Close the file descriptor.
+ * Repeat until
+ */
+void close(int fd);
+
+/**
+ * Write to a file descriptor, throw on error.
+ *
+ * @param fd file descriptor
+ * @param bufferPtr pointer to the data buffer
+ * @param size size of data to write
+ */
+void write(int fd, const void* bufferPtr, const size_t size);
+
+/**
+ * Read from a file descriptor, throw on error.
+ *
+ * @param fd file descriptor
+ * @param bufferPtr pointer to the data buffer
+ * @param size size of the data to read
+ */
+void read(int fd, void* bufferPtr, const size_t size);
+
+/**
+ * @return the max number of file descriptors for this process.
+ */
+unsigned int getMaxFDNumber();
+
+/**
+ * Set the software and hardware limit of file descriptors for this process.
+ *
+ * @param limit limit of file descriptors
+ */
+void setMaxFDNumber(unsigned int limit);
+
+/**
+ * @return number of opened file descriptors by this process
+ */
+unsigned int getFDNumber();
+
+} // namespace ipc
+} // namespace security_containers
+
+#endif // COMMON_IPC_INTERNALS_UTILS_HPP
diff --git a/common/ipc/service.cpp b/common/ipc/service.cpp
new file mode 100644
index 0000000..d2590d6
--- /dev/null
+++ b/common/ipc/service.cpp
@@ -0,0 +1,86 @@
+// /*
+// * 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 Implementation of the IPC handling class
+// */
+
+#include "config.hpp"
+
+#include "ipc/service.hpp"
+#include "ipc/exception.hpp"
+#include "logger/logger.hpp"
+
+using namespace std::placeholders;
+
+namespace security_containers {
+namespace ipc {
+
+Service::Service(const std::string& socketPath,
+ const PeerCallback& addPeerCallback,
+ const PeerCallback& removePeerCallback)
+ : mProcessor(addPeerCallback, removePeerCallback),
+ mAcceptor(socketPath, std::bind(&Processor::addPeer, &mProcessor, _1))
+
+{
+ LOGD("Creating server");
+}
+
+Service::~Service()
+{
+ LOGD("Destroying server...");
+ try {
+ stop();
+ } catch (IPCException& e) {
+ LOGE("Error in Service's destructor: " << e.what());
+ }
+ LOGD("Destroyed");
+}
+
+void Service::start()
+{
+ LOGD("Starting server");
+ mProcessor.start();
+
+ // There can be an incoming connection from mAcceptor before mProcessor is listening,
+ // but it's OK. It will handle the connection when ready. So no need to wait for mProcessor.
+ mAcceptor.start();
+
+ LOGD("Started server");
+}
+
+void Service::stop()
+{
+ LOGD("Stopping server..");
+ mAcceptor.stop();
+ mProcessor.stop();
+ LOGD("Stopped");
+}
+
+void Service::removeMethod(const MethodID methodID)
+{
+ LOGD("Removing method " << methodID);
+ mProcessor.removeMethod(methodID);
+ LOGD("Removed " << methodID);
+}
+
+
+} // namespace ipc
+} // namespace security_containers
diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp
new file mode 100644
index 0000000..08f7ec9
--- /dev/null
+++ b/common/ipc/service.hpp
@@ -0,0 +1,168 @@
+/*
+* 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 Declaration of the IPC handling class
+ */
+
+#ifndef COMMON_IPC_SERVICE_HPP
+#define COMMON_IPC_SERVICE_HPP
+
+#include "ipc/internals/processor.hpp"
+#include "ipc/internals/acceptor.hpp"
+#include "ipc/types.hpp"
+#include "logger/logger.hpp"
+
+#include
+
+namespace security_containers {
+namespace ipc {
+
+
+/**
+ * This class wraps communication via UX sockets.
+ * It uses serialization mechanism from libConfig.
+ *
+ * There are two working threads:
+ * - ACCEPTOR accepts incoming connections and passes them to PROCESSOR
+ * - PROCESSOR is responsible for the communication and calling the callbacks
+ *
+ * For message format @see ipc::Processor
+ */
+class Service {
+public:
+ typedef Processor::PeerCallback PeerCallback;
+ typedef Processor::PeerID PeerID;
+ typedef Processor::MethodID MethodID;
+
+ /**
+ * @param path path to the socket
+ */
+ Service(const std::string& path,
+ const PeerCallback& addPeerCallback = nullptr,
+ const PeerCallback& removePeerCallback = nullptr);
+ ~Service();
+
+ Service(const Service&) = delete;
+ Service& operator=(const Service&) = delete;
+
+ /**
+ * Starts the worker and acceptor threads
+ */
+ void start();
+
+ /**
+ * Stops all working threads
+ */
+ void stop();
+
+ /**
+ * Saves the callback connected to the method id.
+ * When a message with the given method id is received
+ * the data will be parsed and passed to this callback.
+ *
+ * @param methodID API dependent id of the method
+ * @param methodCallback method handling implementation
+ */
+ template
+ void addMethodHandler(const MethodID methodID,
+ const typename MethodHandler::type& method);
+
+ /**
+ * Removes the callback
+ *
+ * @param methodID API dependent id of the method
+ */
+ void removeMethod(const MethodID methodID);
+
+ /**
+ * Synchronous method call.
+ *
+ * @param methodID API dependent id of the method
+ * @param data data to send
+ * @return result data
+ */
+ template
+ std::shared_ptr callSync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ unsigned int timeoutMS);
+
+ /**
+ * Asynchronous method call. The return callback will be called on
+ * return data arrival. It will be run in the PROCESSOR thread.
+ *
+ *
+ * @param methodID API dependent id of the method
+ * @param sendCallback callback for data serialization
+ * @param resultCallback callback for result serialization and handling
+ */
+ template
+ void callAsync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ const typename ResultHandler::type& resultCallback);
+
+private:
+ typedef std::lock_guard Lock;
+ Processor mProcessor;
+ Acceptor mAcceptor;
+};
+
+
+template
+void Service::addMethodHandler(const MethodID methodID,
+ const typename MethodHandler::type& method)
+{
+ LOGD("Adding method with id " << methodID);
+ mProcessor.addMethodHandler(methodID, method);
+ LOGD("Added method with id " << methodID);
+}
+
+template
+std::shared_ptr Service::callSync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ unsigned int timeoutMS = 500)
+{
+ LOGD("Sync calling method: " << methodID << " for user: " << peerID);
+ return mProcessor.callSync(methodID, peerID, data, timeoutMS);
+}
+
+template
+void Service::callAsync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ const typename ResultHandler::type& resultCallback)
+{
+ LOGD("Async calling method: " << methodID << " for user: " << peerID);
+ mProcessor.callAsync(methodID,
+ peerID,
+ data,
+ resultCallback);
+ LOGD("Async called method: " << methodID << "for user: " << peerID);
+}
+
+
+} // namespace ipc
+} // namespace security_containers
+
+#endif // COMMON_IPC_SERVICE_HPP
diff --git a/common/ipc/types.hpp b/common/ipc/types.hpp
new file mode 100644
index 0000000..4269664
--- /dev/null
+++ b/common/ipc/types.hpp
@@ -0,0 +1,48 @@
+/*
+* 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 Handler types definitions
+ */
+
+#ifndef COMMON_IPC_HANDLERS_HPP
+#define COMMON_IPC_HANDLERS_HPP
+
+#include
+#include
+
+namespace security_containers {
+namespace ipc {
+
+template
+struct MethodHandler {
+ typedef std::function