[Feature] Add more functions to the client library.
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run test suite Client
Change-Id: Ided49f0363c5bb94669c272fda745510cd21d985
#include <dbus/exception.hpp>
#include <utils/glib-loop.hpp>
#include <host-dbus-definitions.hpp>
+#include <container-dbus-definitions.hpp>
#include <memory>
#include <cstring>
const DbusInterfaceInfo hostDbusInterfaceInfo(api::host::BUS_NAME,
api::host::OBJECT_PATH,
api::host::INTERFACE);
+const DbusInterfaceInfo domainDbusInterfaceInfo(api::container::BUS_NAME,
+ api::container::OBJECT_PATH,
+ api::container::INTERFACE);
+
+template<typename T> struct fake_dependency: public std::false_type {};
unique_ptr<ScopedGlibLoop> loop;
*values = outv;
}
+template<typename T>
+void toBasic(GVariant* in, T str)
+{
+ static_assert(fake_dependency<T>::value, "Must use specialization");
+ assert(!"Must use specialization");
+}
+
+template<>
+void toBasic(GVariant* in, char** str)
+{
+ assert(in);
+ assert(str);
+
+ gsize length;
+ const gchar* src = g_variant_get_string(in, &length);
+ char* buf = strndup(src, length);
+ *str = buf;
+}
+
+template<typename T>
+void toArray(GVariant* in, T** scArray)
+{
+ assert(in);
+ assert(scArray);
+
+ gsize size = g_variant_n_children(in);
+ T* ids = (T*)calloc(size + 1, sizeof(T));
+
+ GVariantIter iter;
+ GVariant* child;
+
+ g_variant_iter_init(&iter, in);
+ for (int i = 0; (child = g_variant_iter_next_value(&iter)); i++) {
+ toBasic(child, &ids[i]);
+ g_variant_unref(child);
+ }
+ *scArray = ids;
+}
+
ScStatus toStatus(const std::exception& ex)
{
if (typeid(DbusCustomException) == typeid(ex)) {
return sc_get_status();
}
+ScStatus Client::signalSubscribe(const DbusInterfaceInfo& info,
+ const string& name,
+ SignalCallback signalCallback)
+{
+ auto onSignal = [=](const std::string& /*senderBusName*/,
+ const std::string & objectPath,
+ const std::string & interface,
+ const std::string & signalName,
+ GVariant * parameters) {
+ if (objectPath == info.objectPath &&
+ interface == info.interface &&
+ signalName == name) {
+
+ signalCallback(parameters);
+ }
+ };
+ try {
+ mConnection->signalSubscribe(onSignal, info.busName);
+ mStatus = Status(SCCLIENT_SUCCESS);
+ } catch (const std::exception& ex) {
+ mStatus = Status(toStatus(ex), ex.what());
+ } catch (...) {
+ mStatus = Status(SCCLIENT_EXCEPTION);
+ }
+ return sc_get_status();
+}
+
const char* Client::sc_get_status_message() noexcept
{
return mStatus.mMsg.c_str();
g_variant_unref(out);
return ret;
}
+
+ScStatus Client::sc_get_container_ids(ScArrayString* array) noexcept
+{
+ assert(array);
+
+ GVariant* out;
+ ScStatus ret = callMethod(hostDbusInterfaceInfo,
+ api::host::METHOD_GET_CONTAINER_ID_LIST,
+ NULL,
+ "(as)",
+ &out);
+ if (ret != SCCLIENT_SUCCESS) {
+ return ret;
+ }
+ GVariant* unpacked;
+ g_variant_get(out, "(*)", &unpacked);
+ toArray(unpacked, array);
+ g_variant_unref(unpacked);
+ g_variant_unref(out);
+ return ret;
+}
+
+ScStatus Client::sc_get_active_container_id(ScString* id) noexcept
+{
+ assert(id);
+
+ GVariant* out;
+ ScStatus ret = callMethod(hostDbusInterfaceInfo,
+ api::host::METHOD_GET_ACTIVE_CONTAINER_ID,
+ NULL,
+ "(s)",
+ &out);
+ if (ret != SCCLIENT_SUCCESS) {
+ return ret;
+ }
+ GVariant* unpacked;
+ g_variant_get(out, "(*)", &unpacked);
+ toBasic(unpacked, id);
+ g_variant_unref(unpacked);
+ g_variant_unref(out);
+ return ret;
+}
+
+ScStatus Client::sc_set_active_container(const char* id) noexcept
+{
+ assert(id);
+
+ GVariant* args_in = g_variant_new("(s)", id);
+ return callMethod(hostDbusInterfaceInfo, api::host::METHOD_SET_ACTIVE_CONTAINER, args_in);
+}
+
+ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback)
+ noexcept
+{
+ assert(containerDbusStateCallback);
+
+ auto onSigal = [ = ](GVariant * parameters) {
+ const char* container;
+ const char* dbusAddress;
+ g_variant_get(parameters, "(&s&s)", &container, &dbusAddress);
+ containerDbusStateCallback(container, dbusAddress);
+ };
+
+ return signalSubscribe(hostDbusInterfaceInfo,
+ api::host::SIGNAL_CONTAINER_DBUS_STATE,
+ onSigal);
+}
+
+ScStatus Client::sc_notify_active_container(const char* application, const char* message) noexcept
+{
+ assert(application);
+ assert(message);
+
+ GVariant* args_in = g_variant_new("(ss)", application, message);
+ return callMethod(domainDbusInterfaceInfo,
+ api::container::METHOD_NOTIFY_ACTIVE_CONTAINER,
+ args_in);
+}
+
+ScStatus Client::sc_notification(ScNotificationCallback notificationCallback) noexcept
+{
+ assert(notificationCallback);
+
+ auto onSigal = [ = ](GVariant * parameters) {
+ const char* container;
+ const char* application;
+ const char* message;
+ g_variant_get(parameters, "(&s&s&s)", &container, &application, &message);
+ notificationCallback(container, application, message);
+ };
+
+ return signalSubscribe(domainDbusInterfaceInfo, api::container::SIGNAL_NOTIFICATION, onSigal);
+}
*/
class Client {
private:
+ typedef std::function<void(GVariant* parameters)> SignalCallback;
struct Status {
Status(ScStatus status);
Status(ScStatus status, const std::string& msg);
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);
public:
Client() noexcept;
ScStatus sc_get_container_dbuses(ScArrayString* keys, ScArrayString* values) noexcept;
/**
+ * @see ::sc_get_container_ids
+ */
+ ScStatus sc_get_container_ids(ScArrayString* array) noexcept;
+
+ /**
+ * @see ::sc_get_active_container_id
+ */
+ ScStatus sc_get_active_container_id(ScString* id) noexcept;
+
+ /**
+ * @see ::sc_set_active_container
+ */
+ ScStatus sc_set_active_container(const char* id) noexcept;
+
+ /**
+ * @see ::sc_container_dbus_state
+ */
+ ScStatus sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback) noexcept;
+
+ /**
+ * @see ::sc_notify_active_container
+ */
+ ScStatus sc_notify_active_container(const char* application, const char* message) noexcept;
+
+ /**
+ * @see ::sc_notification
+ */
+ ScStatus sc_notification(ScNotificationCallback notificationCallback) noexcept;
+ /**
* @see ::sc_start
*/
static ScStatus sc_start() noexcept;
{
return getClient(client)->sc_get_container_dbuses(keys, values);
}
+
+API ScStatus sc_get_container_ids(ScClient client, ScArrayString* array)
+{
+ return getClient(client)->sc_get_container_ids(array);
+}
+
+API ScStatus sc_get_active_container_id(ScClient client, ScString* id)
+{
+ return getClient(client)->sc_get_active_container_id(id);
+}
+
+API ScStatus sc_set_active_container(ScClient client, const char* id)
+{
+ return getClient(client)->sc_set_active_container(id);
+}
+
+API ScStatus sc_container_dbus_state(ScClient client,
+ ScContainerDbusStateCallback containerDbusStateCallback)
+{
+ return getClient(client)->sc_container_dbus_state(containerDbusStateCallback);
+}
+
+API ScStatus sc_notify_active_container(ScClient client,
+ const char* application,
+ const char* message)
+{
+ return getClient(client)->sc_notify_active_container(application, message);
+}
+
+API ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback)
+{
+ return getClient(client)->sc_notification(notificationCallback);
+}
************************************************************************************************/
/**
+ * Dbus state change callback function signature.
+ */
+typedef void (*ScContainerDbusStateCallback)(const char* containerId, const char* dbusAddress);
+
+/**
* Get dbus address of each container.
*
* @param[in] client security-containers-server's client.
*/
ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArrayString* values);
+/**
+ * Get containers name.
+ *
+ * @param[in] client security-containers-server's client.
+ * @param[out] array Array of containers name.
+ * @return Status of this function call.
+ */
+ScStatus sc_get_container_ids(ScClient client, ScArrayString* array);
+
+/**
+ * Get active container name.
+ *
+ * @param[in] client security-containers-server's client.
+ * @param[out] id Active container name.
+ * @return Status of this function call.
+ */
+ScStatus sc_get_active_container_id(ScClient client, ScString* id);
+
+/**
+ * Set active container.
+ *
+ * @param client security-containers-server's client.
+ * @param id Container name.
+ * @return Status of this function call.
+ */
+ScStatus sc_set_active_container(ScClient client, const char* id);
+
+/**
+ * Register dbus state change callback function.
+ *
+ * The callback function will be invoked on a different thread
+ *
+ * @param client security-containers-server's client.
+ * @param containerDbusStateCallback Callback function.
+ * @return Status of this function call.
+ */
+ScStatus sc_container_dbus_state(ScClient client,
+ ScContainerDbusStateCallback containerDbusStateCallback);
+
+
+/*************************************************************************************************
+ *
+ * org.tizen.containers.domain.manager interface
+ *
+ ************************************************************************************************/
+
+/**
+ * Notification callback function signature.
+ */
+typedef void (*ScNotificationCallback)(const char* container,
+ const char* application,
+ const char* message);
+/**
+ * Send message to active container.
+ *
+ * @param client security-containers-server's client.
+ * @param application Application name.
+ * @param message Message.
+ * @return Status of this function call.
+ */
+ScStatus sc_notify_active_container(ScClient client, const char* application, const char* message);
+
+/**
+ * Register notification callback function.
+ *
+ * The callback function will be invoked on a different thread.
+ *
+ * @param client security-containers-server's client.
+ * @param notificationCallback Callback function.
+ * @return Status of this function call.
+ */
+ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback);
#ifdef __cplusplus
}
#endif
"switchToDefaultAfterTimeout" : true,
"config" : "../libvirt-config/console1-dbus.xml",
"networkConfig" : "../libvirt-config/network1.xml",
+ "networkFilterConfig" : "../libvirt-config/network1-filter.xml",
"cpuQuotaForeground" : -1,
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-containers-manager/console1-dbus",
"switchToDefaultAfterTimeout" : false,
"config" : "../libvirt-config/console2-dbus.xml",
"networkConfig" : "../libvirt-config/network2.xml",
+ "networkFilterConfig" : "../libvirt-config/network2-filter.xml",
"cpuQuotaForeground" : -1,
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-containers-manager/console2-dbus",
"switchToDefaultAfterTimeout" : true,
"config" : "../libvirt-config/console3-dbus.xml",
"networkConfig" : "../libvirt-config/network3.xml",
+ "networkFilterConfig" : "../libvirt-config/network3-filter.xml",
"cpuQuotaForeground" : -1,
"cpuQuotaBackground" : 1000,
"runMountPoint" : "/tmp/ut-containers-manager/console3-dbus",
--- /dev/null
+<filter name='test-network-1-filter' chain='root'>
+ <uuid>abc79a77-0209-41a2-ab82-f767dfa5897e</uuid>
+</filter>
--- /dev/null
+<filter name='test-network-2-filter' chain='root'>
+ <uuid>703f53eb-c602-4383-9de9-62bbe843ba31</uuid>
+</filter>
--- /dev/null
+<filter name='test-network-3-filter' chain='root'>
+ <uuid>40943fcc-faec-4bfe-9e89-104945164d35</uuid>
+</filter>
#include "ut.hpp"
#include <security-containers-client.h>
+#include "utils/latch.hpp"
#include "containers-manager.hpp"
#include <map>
#include <string>
#include <utility>
#include <memory>
+#include <set>
+#include <tuple>
+#include <utility>
using namespace security_containers;
+using namespace security_containers::utils;
namespace {
~Fixture() { sc_stop(); };
};
+const int EVENT_TIMEOUT = 5000; ///< ms
const std::map<std::string, std::string> EXPECTED_DBUSES_STARTED = {
{"ut-containers-manager-console1-dbus",
"unix:path=/tmp/ut-containers-manager/console1-dbus/dbus/system_bus_socket"},
}
}
+void convertArrayToSet(ScArrayString values, std::set<std::string>& ret)
+{
+ for (char** iValues = values; *iValues; iValues++) {
+ ret.insert(*iValues);
+ }
+}
+
int getArrayStringLength(ScArrayString astring, int max_len = -1)
{
int i = 0;
return i;
}
+Latch signalReceivedLatch;
+std::vector< std::tuple<std::string, std::string, std::string> > receivedSignalMsg;
+
+void NotificationTestCallback(const char* container, const char* application, const char* message)
+{
+ receivedSignalMsg.push_back(std::make_tuple(container, application, message));
+ signalReceivedLatch.set();
+}
+
} // namespace
BOOST_FIXTURE_TEST_SUITE(Client, Fixture)
BOOST_WARN_NO_THROW(cm.reset());
}
+BOOST_AUTO_TEST_CASE(GetContainerIdsTest)
+{
+ std::unique_ptr<ContainersManager> cm;
+ BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH)));
+ cm->startAll();
+ ScClient client;
+ ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE);
+ BOOST_REQUIRE(!sc_is_failed(status));
+ ScArrayString values;
+ status = sc_get_container_ids(client, &values);
+ BOOST_REQUIRE(!sc_is_failed(status));
+ BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1),
+ EXPECTED_DBUSES_STARTED.size());
+
+ std::set<std::string> containers;
+ convertArrayToSet(values, containers);
+
+ 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);
+
+ BOOST_WARN_NO_THROW(cm.reset());
+}
+
+BOOST_AUTO_TEST_CASE(GetActiveContainerIdTest)
+{
+ std::unique_ptr<ContainersManager> cm;
+ BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH)));
+ cm->startAll();
+
+ ScClient client;
+ ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE);
+ BOOST_REQUIRE(!sc_is_failed(status));
+ ScString container;
+ status = sc_get_active_container_id(client, &container);
+ BOOST_REQUIRE(!sc_is_failed(status));
+
+ BOOST_CHECK_EQUAL(container, cm->getRunningForegroundContainerId());
+
+ sc_string_free(container);
+ sc_client_free(client);
+
+ BOOST_WARN_NO_THROW(cm.reset());
+}
+
+BOOST_AUTO_TEST_CASE(SetActiveContainerTest)
+{
+ std::string newActiveContainerId = "ut-containers-manager-console2-dbus";
+
+ std::unique_ptr<ContainersManager> cm;
+ BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH)));
+ cm->startAll();
+ BOOST_REQUIRE_NE(newActiveContainerId, cm->getRunningForegroundContainerId());
+
+ ScClient client;
+ ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE);
+ BOOST_REQUIRE(!sc_is_failed(status));
+ status = sc_set_active_container(client, newActiveContainerId.c_str());
+ BOOST_REQUIRE(!sc_is_failed(status));
+ BOOST_CHECK_EQUAL(newActiveContainerId, cm->getRunningForegroundContainerId());
+ sc_client_free(client);
+ BOOST_WARN_NO_THROW(cm.reset());
+}
+
+BOOST_AUTO_TEST_CASE(NotificationTest)
+{
+ std::string activeContainerId = "ut-containers-manager-console1-dbus";
+ std::unique_ptr<ContainersManager> cm;
+ BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH)));
+ cm->startAll();
+
+ std::map<std::string, ScClient> clients;
+ for (const auto& it : EXPECTED_DBUSES_STARTED) {
+ ScClient client;
+ ScStatus status = sc_get_client(&client, SCCLIENT_CUSTOM_TYPE, it.second.c_str());
+ BOOST_REQUIRE(!sc_is_failed(status));
+ clients[it.first] = client;
+ }
+ for (auto& client : clients) {
+ ScStatus status = sc_notification(client.second, NotificationTestCallback);
+ BOOST_REQUIRE(!sc_is_failed(status));
+ }
+ for (auto& client : clients) {
+ ScStatus status = sc_notify_active_container(client.second, "app", "msg");
+ BOOST_REQUIRE(!sc_is_failed(status));
+ }
+
+ BOOST_CHECK(signalReceivedLatch.waitForN(clients.size() - 1, EVENT_TIMEOUT));
+ BOOST_CHECK(signalReceivedLatch.empty());
+
+ for (auto& client : clients) {
+ sc_client_free(client.second);
+ }
+ BOOST_WARN_NO_THROW(cm.reset());
+}
+
BOOST_AUTO_TEST_SUITE_END()